Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: CI

# Run on push only for dev/sandbox
# Run on push only for ci/staging
# Otherwise it may trigger concurrently `push & pull_request` on PRs.
on:
push:
Expand Down
35 changes: 13 additions & 22 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,42 +1,33 @@
name: Main

# Run on push only for dev/sandbox
# Otherwise it may trigger concurrently `push & pull_request` on PRs.
on:
pull_request: null
push:
branches:
- master

jobs:
build:
name: Python ${{ matrix.python }}
name: Linux
runs-on: ubuntu-latest
strategy:
matrix:
python: [3.7, 3.8, 3.9, "3.10", 3.11, 3.12, 3.13, pypy3.10]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: setup python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
python-version: |
pypy3.11
3.10
3.11
3.12
3.13
3.14
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .
pip install coveralls --upgrade
- name: Run flake8
run: |
pip install flake8 --upgrade
flake8 --exclude=build --ignore=E501,F403,F401,E241,E225,E128 .
- name: Run pycodestyle
run: |
pip install pycodestyle --upgrade
pycodestyle --ignore=E128,E261,E225,E501,W605 slugify test.py setup.py
python -m pip install coveralls tox tox-uv
- name: Run test
run: |
coverage run --source=slugify test.py
tox
- name: Coveralls
run: coveralls --service=github
env:
Expand Down
41 changes: 41 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# coverage
# --------

[tool.coverage.run]
relative_files = true
parallel = true
branch = true
source = [
"slugify",
"test",
]

[tool.coverage.paths]
source = [
"src",
"*/site-packages",
]

[tool.coverage.report]
skip_covered = true
fail_under = 97


# mypy
# ----

[tool.mypy]
packages = "slugify"
strict = true
sqlite_cache = true


# pytest
# ------

[tool.pytest.ini_options]
testpaths = ["test.py"]
addopts = "--color=yes"
filterwarnings = [
"error",
]
6 changes: 2 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


package = 'slugify'
python_requires = ">=3.7"
python_requires = ">=3.10"
here = os.path.abspath(os.path.dirname(__file__))

install_requires = ['text-unidecode>=1.3']
Expand Down Expand Up @@ -78,13 +78,11 @@ def status(s):
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
'Programming Language :: Python :: 3.14',
],
entry_points={'console_scripts': ['slugify=slugify.__main__:main']},
)
6 changes: 3 additions & 3 deletions slugify/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
parser.error("Input strings and --stdin cannot work together")

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


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


if __name__ == '__main__': # pragma: no cover
if __name__ == '__main__':
main()
4 changes: 2 additions & 2 deletions slugify/slugify.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
try:
import unidecode
except ImportError:
import text_unidecode as unidecode
import text_unidecode as unidecode # type: ignore[import-untyped, no-redef]

__all__ = ['slugify', 'smart_truncate']

Expand Down Expand Up @@ -67,7 +67,7 @@ def smart_truncate(
else:
if save_order:
break
if not truncated: # pragma: no cover
if not truncated:
truncated = string[:max_length]
return truncated.strip(separator)

Expand Down
2 changes: 1 addition & 1 deletion test.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,5 +653,5 @@ def test_multivalued_options_with_text(self):
self.assertEqual(params['stopwords'], ['the', 'in', 'a', 'hurry'])


if __name__ == '__main__':
if __name__ == '__main__': # pragma: nocover
unittest.main()
69 changes: 69 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
[tox]
env_list =
coverage-erase
py{3.10, 3.11, 3.12, 3.13, 3.14}-{unidecode, text_unidecode}
pypy{3.11}-{unidecode, text_unidecode}
coverage-report
coverage-html
mypy
pycodestyle

[testenv]
depends =
py{3.10, 3.11, 3.12, 3.13, 3.14}-{unidecode, text_unidecode}: coverage-erase
pypy{3.11}-{unidecode, text_unidecode}: coverage-erase
deps =
coverage[toml]
pytest
unidecode: pip
unidecode: unidecode
commands_pre:
# If testing unidecode, ensure text_unidecode is unavailable.
unidecode: pip uninstall --yes text_unidecode
commands =
coverage run -m pytest test.py

[testenv:coverage_base]
deps =
coverage[toml]

[testenv:coverage-erase]
base = coverage_base
commands =
coverage erase

[testenv:coverage-report]
base = coverage_base
depends =
py{3.10, 3.11, 3.12, 3.13, 3.14}-{unidecode, text_unidecode}
pypy{3.11}-{unidecode, text_unidecode}
commands_pre =
- coverage combine
commands =
coverage report

[testenv:coverage-html]
base = coverage_base
depends =
coverage-report
commands =
coverage html --fail-under=0

[testenv:mypy]
deps =
mypy
unidecode
commands =
mypy

[testenv:pycodestyle]
deps =
pycodestyle
commands =
pycodestyle --ignore=E128,E261,E225,E501,W605 slugify test.py setup.py

[testenv:flake8]
deps =
flake8
commands =
flake8 --ignore=E501,F403,F401,E241,E225,E128 slugify/ setup.py test.py