Skip to content

Commit 1ef698f

Browse files
committed
Reintroduce tox and thoroughly test the project
This commit introduces the following major changes: * Use tox. * Test the project against both `unidecode` and `text_unidecode`. Previously, `unidecode` was untested. * Drop support for Python 3.7, 3.8, and 3.9. CI was unable to run because Python 3.7 is no longer available. In addition, Python 3.9 and lower are all end-of-life. * Test against PyPy 3.11 and Python 3.14. * Test type annotations using mypy. Previously, type annotations were untested. * Install and test all supported Python interpreters in CI at once. * Use tox, and the tox-uv plugin, exclusively in CI. This eliminates differences between local and CI testing. * Run CI against pull requests. * Collect, combine, and report coverage for all Python versions and dependencies, locally and in CI. In addition, this commit introduces the following minor changes: * Fix typing issues identified by mypy. Note that `text_unidecode` is untyped and must be type-ignored. * Remove almost all coverage `pragma: nocover` lines. * Fix incorrect copy/pasted comments in `ci.yml` and `main.yml`. * Upgrade `actions/checkout` to v5 and `actions/setup-python` to v6.
1 parent 45f9d33 commit 1ef698f

File tree

8 files changed

+134
-35
lines changed

8 files changed

+134
-35
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: CI
22

3-
# Run on push only for dev/sandbox
3+
# Run on push only for ci/staging
44
# Otherwise it may trigger concurrently `push & pull_request` on PRs.
55
on:
66
push:

.github/workflows/main.yml

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,33 @@
11
name: Main
22

3-
# Run on push only for dev/sandbox
4-
# Otherwise it may trigger concurrently `push & pull_request` on PRs.
53
on:
4+
pull_request: null
65
push:
76
branches:
87
- master
98

109
jobs:
1110
build:
12-
name: Python ${{ matrix.python }}
11+
name: Linux
1312
runs-on: ubuntu-latest
14-
strategy:
15-
matrix:
16-
python:
17-
- "3.10"
18-
- "3.11"
19-
- "3.12"
20-
- "3.13"
21-
- "3.14"
22-
- "pypy3.11"
23-
2413
steps:
25-
- uses: actions/checkout@v4
14+
- uses: actions/checkout@v5
2615
- name: setup python
27-
uses: actions/setup-python@v5
16+
uses: actions/setup-python@v6
2817
with:
29-
python-version: ${{ matrix.python }}
18+
python-version: |
19+
pypy3.11
20+
3.10
21+
3.11
22+
3.12
23+
3.13
24+
3.14
3025
- name: Install dependencies
3126
run: |
32-
python -m pip install --upgrade pip
33-
pip install -e .
34-
pip install coveralls --upgrade
35-
- name: Run flake8
36-
run: |
37-
pip install flake8 --upgrade
38-
flake8 --exclude=build --ignore=E501,F403,F401,E241,E225,E128 .
39-
- name: Run pycodestyle
40-
run: |
41-
pip install pycodestyle --upgrade
42-
pycodestyle --ignore=E128,E261,E225,E501,W605 slugify test.py setup.py
27+
python -m pip install coveralls tox tox-uv
4328
- name: Run test
4429
run: |
45-
coverage run --source=slugify test.py
30+
tox
4631
- name: Coveralls
4732
run: coveralls --service=github
4833
env:

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
- Support Python 3.14.
44
- Drop support for Python 3.9 and lower.
5+
- Use tox for local test runs and in CI.
6+
- Test the project against both `unidecode` and `text_unidecode`.
7+
- Fix type annotation issues identified by mypy.
8+
- Run CI against pull requests.
59

610
## 8.0.4
711

pyproject.toml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# coverage
2+
# --------
3+
4+
[tool.coverage.run]
5+
relative_files = true
6+
parallel = true
7+
branch = true
8+
source = [
9+
"slugify",
10+
"test",
11+
]
12+
13+
[tool.coverage.paths]
14+
source = [
15+
"src",
16+
"*/site-packages",
17+
]
18+
19+
[tool.coverage.report]
20+
skip_covered = true
21+
fail_under = 97
22+
23+
24+
# mypy
25+
# ----
26+
27+
[tool.mypy]
28+
packages = "slugify"
29+
strict = true
30+
sqlite_cache = true
31+
32+
33+
# pytest
34+
# ------
35+
36+
[tool.pytest.ini_options]
37+
testpaths = ["test.py"]
38+
addopts = "--color=yes"
39+
filterwarnings = [
40+
"error",
41+
]

slugify/__main__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
4747
parser.error("Input strings and --stdin cannot work together")
4848

4949
if args.replacements:
50-
def split_check(repl):
50+
def split_check(repl: str) -> list[str]:
5151
SEP = '->'
5252
if SEP not in repl:
5353
parser.error("Replacements must be of the form: ORIGINAL{SEP}REPLACED".format(SEP=SEP))
@@ -82,7 +82,7 @@ def slugify_params(args: argparse.Namespace) -> dict[str, Any]:
8282
)
8383

8484

85-
def main(argv: list[str] | None = None): # pragma: no cover
85+
def main(argv: list[str] | None = None) -> None:
8686
""" Run this program """
8787
if argv is None:
8888
argv = sys.argv
@@ -94,5 +94,5 @@ def main(argv: list[str] | None = None): # pragma: no cover
9494
sys.exit(-1)
9595

9696

97-
if __name__ == '__main__': # pragma: no cover
97+
if __name__ == '__main__':
9898
main()

slugify/slugify.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
try:
99
import unidecode
1010
except ImportError:
11-
import text_unidecode as unidecode
11+
import text_unidecode as unidecode # type: ignore[import-untyped, no-redef]
1212

1313
__all__ = ['slugify', 'smart_truncate']
1414

@@ -67,7 +67,7 @@ def smart_truncate(
6767
else:
6868
if save_order:
6969
break
70-
if not truncated: # pragma: no cover
70+
if not truncated:
7171
truncated = string[:max_length]
7272
return truncated.strip(separator)
7373

test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,5 +653,5 @@ def test_multivalued_options_with_text(self):
653653
self.assertEqual(params['stopwords'], ['the', 'in', 'a', 'hurry'])
654654

655655

656-
if __name__ == '__main__':
656+
if __name__ == '__main__': # pragma: nocover
657657
unittest.main()

tox.ini

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
[tox]
2+
env_list =
3+
coverage-erase
4+
py{3.10, 3.11, 3.12, 3.13, 3.14}-{unidecode, text_unidecode}
5+
pypy{3.11}-{unidecode, text_unidecode}
6+
coverage-report
7+
coverage-html
8+
mypy
9+
pycodestyle
10+
11+
[testenv]
12+
depends =
13+
py{3.10, 3.11, 3.12, 3.13, 3.14}-{unidecode, text_unidecode}: coverage-erase
14+
pypy{3.11}-{unidecode, text_unidecode}: coverage-erase
15+
deps =
16+
coverage[toml]
17+
pytest
18+
unidecode: pip
19+
unidecode: unidecode
20+
commands_pre:
21+
# If testing unidecode, ensure text_unidecode is unavailable.
22+
unidecode: pip uninstall --yes text_unidecode
23+
commands =
24+
coverage run -m pytest test.py
25+
26+
[testenv:coverage_base]
27+
deps =
28+
coverage[toml]
29+
30+
[testenv:coverage-erase]
31+
base = coverage_base
32+
commands =
33+
coverage erase
34+
35+
[testenv:coverage-report]
36+
base = coverage_base
37+
depends =
38+
py{3.10, 3.11, 3.12, 3.13, 3.14}-{unidecode, text_unidecode}
39+
pypy{3.11}-{unidecode, text_unidecode}
40+
commands_pre =
41+
- coverage combine
42+
commands =
43+
coverage report
44+
45+
[testenv:coverage-html]
46+
base = coverage_base
47+
depends =
48+
coverage-report
49+
commands =
50+
coverage html --fail-under=0
51+
52+
[testenv:mypy]
53+
deps =
54+
mypy
55+
unidecode
56+
commands =
57+
mypy
58+
59+
[testenv:pycodestyle]
60+
deps =
61+
pycodestyle
62+
commands =
63+
pycodestyle --ignore=E128,E261,E225,E501,W605 slugify test.py setup.py
64+
65+
[testenv:flake8]
66+
deps =
67+
flake8
68+
commands =
69+
flake8 --ignore=E501,F403,F401,E241,E225,E128 slugify/ setup.py test.py

0 commit comments

Comments
 (0)