[tox] envlist = lint format audit # Python/Django combinations that are officially supported (minus end-of-life Pythons) py{39,310,311,312}-django{42} py{310,311,312,313}-django{51} py{310,311,312,313}-django{52} package docs clean [gh-actions] python = 3.9: py39 3.10: py310 3.11: py311 3.12: py312 3.13: py313 [gh-actions:env] DJANGO = 4.2: django42 5.1: django51 5.2: django52 [testenv] description = Unit tests deps = coverage[toml] pytest-django django42: Django>=4.2,<5.0 django51: Django>=5.1,<5.2 django52: Django>=5.2,<6.0 commands = coverage run -m pytest {posargs} coverage report coverage xml [testenv:audit] description = Scan for vulnerable dependencies skip_install = true deps = pip-audit uv commands = uv export --no-emit-project --no-hashes -o requirements.txt -q pip-audit {posargs:-r requirements.txt --progress-spinner off} [testenv:bandit] description = PyCQA security linter skip_install = true deps = bandit commands = bandit {posargs:-r analytical} -v [testenv:clean] description = Clean up bytecode and build artifacts skip_install = true deps = pyclean commands = pyclean {posargs:. --debris cache coverage package pytest mypy --erase requirements.txt uv.lock docs/_build/**/* docs/_build/ tests/unittests-report.xml --yes} [testenv:docs] description = Build the HTML documentation deps = sphinx commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html [testenv:format] description = Ensure consistent code style (Ruff) skip_install = true deps = ruff commands = ruff format {posargs:--check --diff .} [testenv:lint] description = Lightening-fast linting (Ruff) skip_install = true deps = ruff commands = ruff check {posargs:--output-format=full .} [testenv:mypy] description = Perform static type checking deps = mypy commands = mypy {posargs:.} [testenv:package] description = Build package and check metadata (or upload package) skip_install = true deps = build twine commands = python -m build twine {posargs:check --strict} dist/* passenv = TWINE_USERNAME TWINE_PASSWORD TWINE_REPOSITORY_URL