Skip to main content

pytest-django-autocheck

OpenSSF Scorecard

Zero-config pytest plugin that runs generic safety checks on any Django project. .

Pulls in pytest-django automatically and discovers Django settings from your manage.py. Install and run:

pip install pytest-django-autocheck
pytest --autocheck

Why

Legacy or untested Django projects rarely have any safety net. This plugin catches the basics in CI before they reach production:

  • modules that fail to import
  • migrations that don't reverse, or are missing entirely
  • models that can't be saved or stringified
  • admin pages that return 500/404
  • broken URLconfs
  • public pages that return 500
  • template syntax errors
  • management commands that fail to load
  • forms and serializers that can't be instantiated
  • Django system check failures

Requirements

  • Python 3.10+
  • Django 5.0+

Installation

pip install pytest-django-autocheck

Usage

From your project root (where manage.py lives):

pytest --autocheck

The plugin discovers DJANGO_SETTINGS_MODULE from manage.py. If you already declare it explicitly (in pytest.ini/pyproject.toml, via --ds, or as an environment variable), that value wins and auto-discovery is skipped.

Run only specific checks by repeating --autocheck-only:

# a single check
pytest --autocheck --autocheck-only=admin

# multiple checks
pytest --autocheck --autocheck-only=admin --autocheck-only=models

Or skip specific checks with --autocheck-skip:

pytest --autocheck --autocheck-skip=templates --autocheck-skip=serializers

Both flags can be combined; --autocheck-skip is applied after --autocheck-only, so a check named in both ends up skipped.

Valid check names for both flags: admin, forms, imports, management_commands, migrations, models, serializers, system_checks, templates, urls, views.

Checks

Check Description
admin Every admin registered for a project model validates its configuration and renders its changelist and changeform without 500/404. Any redirect is reported as WARNING: the client is logged in as a superuser, so a redirect (SSL/www rewrite or a bounce to the login page) means the view was never exercised. Admins for third-party models and for models defined inside a tests package are skipped.
forms Every ModelForm defined in a project app's forms module instantiates without raising.
imports Every module of every project app imports without ImportError or circular import (third-party pip apps are skipped).
management_commands Every management command defined by a project app loads its class and builds its argument parser without raising.
migrations Detects model changes not captured by a migration, statically inspects every project migration for irreversible operations and silent noop-reverse migrations, then dynamically verifies the whole graph by applying it forward, reversing to zero, and re-applying forward on a throwaway database. Third-party and django.contrib migrations are skipped: a dependency's irreversible data migration won't fail your build.
models Every project model is instantiable, savable, and stringifiable via both str() and repr(). Third-party and django.contrib models are skipped, as are test-support models defined inside a tests package (a top-level tests/ or an app-level {app}/tests/).
serializers Every Django REST Framework serializer defined in a project app (<app>.serializers or <app>.api.serializers) binds its fields without raising. Skipped entirely when djangorestframework isn't installed.
system_checks Runs Django's own system check framework (django.core.checks) and reports every error, warning and info message it raises.
templates Every template under the project's own template directories compiles without a TemplateSyntaxError. Only the Django template backend is inspected: Jinja2 templates are not compiled.
urls Every URL pattern loads its included URLconf, resolves its callback, and reverses without raising (other than NoReverseMatch).
views Every named URL that reverses without arguments and whose view is owned by a project app is requested with GET by an unauthenticated client; a raised exception or an HTTP 5xx response is reported. Anything below 500 (redirects, 403, 404) is a legitimate answer for an anonymous client and is ignored. Views shipped by third-party packages are skipped (ownership is resolved from the view callback's module, for both function-based and class-based views), and the admin namespace is skipped because the admin check already exercises it with a superuser. Known caveat: a TemplateView.as_view(template_name=...) declared directly in urls.py is skipped, because its view_class is Django's own.

Project-vs-third-party detection is filesystem based: an app is considered third-party when it lives under site-packages, the standard library or the environment prefix. A dependency installed in editable mode (pip install -e) lives outside those locations and is therefore inspected as project code; use the SKIP/CHECKS settings (or MODELS_EXCLUDE) if its findings are noise.

Settings

Every option is read from Django settings under the PYTEST_DJANGO_AUTOCHECK_ prefix, with a safe default: override only what you need.

Setting Default Effect
PYTEST_DJANGO_AUTOCHECK_CHECKS None List of check names to run, e.g. ["imports", "migrations"]. When unset, every registered check runs. --autocheck-only, when given, takes precedence.
PYTEST_DJANGO_AUTOCHECK_SKIP None List of check names to exclude, e.g. ["templates", "serializers"]. Applied after CHECKS/--autocheck-only. --autocheck-skip, when given, takes precedence.
PYTEST_DJANGO_AUTOCHECK_MIGRATIONS_PROBE_TIMEOUT 300 Max seconds the dynamic migration probe subprocess may run before it's aborted; on timeout the dynamic step is skipped with a WARNING and the run doesn't fail. The probe self-aborts at this deadline and destroys its throwaway database.
PYTEST_DJANGO_AUTOCHECK_MODELS_EXCLUDE [] List of "app_label.ModelName" labels (case-insensitive) excluded from instance building: the models check skips them entirely and the admin check skips their change view (attribute validation, changelist and add views still run). Escape hatch for models whose domain constraints can never be satisfied by generated data (e.g. a clean() that requires specific related rows, or a CHECK constraint between correlated fields). Every exclusion is reported as INFO, so it never disappears silently.
PYTEST_DJANGO_AUTOCHECK_MODELS_FACTORIES {} Dict mapping "app_label.ModelName" labels (case-insensitive) to the dotted path of a zero-argument callable returning a saved instance, e.g. {"billing.Plan": "billing.testing.make_plan"}. The callable replaces the generic generator for that model in the models and admin checks. A model listed here wins over MODELS_EXCLUDE: providing a factory means the model can be checked after all, so prefer this over excluding it.
PYTEST_DJANGO_AUTOCHECK_DEPLOY False When True, system_checks also runs Django's deployment checks (DEBUG, SECRET_KEY, SSL/HSTS, secure cookies). Off by default since those fail on dev/test settings; enable for a pre-production audit.

The dynamic migration verification runs in a short-lived subprocess, isolated from the suite's own test database. If that subprocess can't set up its environment, the dynamic step is skipped with a warning rather than failing the run.

Instance generation

The models and admin checks need a valid instance of every model. The generator prefers the project's own factory_boy factories when present (looked up in <app>.factories or <app>.tests.factories): they already encode domain rules, which avoids false positives. Falls back to model_bakery when no factory is found. factory_boy is optional; discovery is a no-op if it's not installed.

When neither a factory nor generated data can satisfy a model's domain constraints, point PYTEST_DJANGO_AUTOCHECK_MODELS_FACTORIES at your own callable to keep the model checked, or, as a last resort, list it in PYTEST_DJANGO_AUTOCHECK_MODELS_EXCLUDE (see Settings) to exclude it from instance building.

The serializers check requires Django REST Framework and is skipped if it's not installed.

Custom checks

Third-party packages can ship their own checks through the pytest_django_autocheck.checks entry-point group. Each entry point must resolve to a check class (instantiated with no arguments) or a check instance exposing name, severity and run(app_configs) -> list[Finding]:

[project.entry-points."pytest_django_autocheck.checks"]
mycheck = "mypackage.checks:MyCheck"

Registered checks run like the built-in ones: they get their own pytest item, their name works with --autocheck-only/--autocheck-skip and the CHECKS/ SKIP settings, and their ERROR findings fail the run.

A check that never touches the database can declare requires_db = False: its pytest item then skips the database fixture, and running only such checks (like the built-in imports, migrations, templates and urls) never creates the test database.

Testing

# clone repository
git clone https://github.com/fabiocaccamo/pytest-django-autocheck.git && cd pytest-django-autocheck

# create virtualenv and activate it
python -m venv .venv && . .venv/bin/activate

# upgrade pip
python -m pip install --upgrade pip

# install package and test requirements
python -m pip install -e ".[test]"

# install pre-commit to run formatters and linters
pre-commit install --install-hooks

# run tests using tox
tox

# or run tests using pytest
coverage run -m pytest && coverage report -m

License

Released under MIT License.


Supporting

  • :star: Star this project on GitHub
  • :octocat: Follow me on GitHub
  • :blue_heart: Follow me on Bluesky
  • :moneybag: Sponsor me on Github

See also

  • django-admin-interface - the default admin interface made customizable by the admin itself. popup windows replaced by modals. 🧙 ⚡

  • django-cache-cleaner - clear the entire cache or individual caches easily using the admin panel or management command. 🧹✨

  • django-colorfield - simple color field for models with a nice color-picker in the admin. 🎨

  • django-email-validators - no more invalid or disposable emails in your database. ✉️ ✅

  • django-extra-settings - config and manage typed extra settings using just the django admin. ⚙️

  • django-maintenance-mode - shows a 503 error page when maintenance-mode is on. 🚧 🛠️

  • django-redirects - redirects with full control. ↪️

  • django-treenode - probably the best abstract model / admin for your tree based stuff. 🌳

  • python-benedict - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. 📘

  • python-codicefiscale - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. 🇮🇹 💳

  • python-fontbro - friendly font operations. 🧢

  • python-fsutil - file-system utilities for lazy devs. 🧟‍♂️

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_django_autocheck-0.3.0.tar.gz (58.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_django_autocheck-0.3.0-py3-none-any.whl (48.3 kB view details)

Uploaded Python 3

File details

Details for the file pytest_django_autocheck-0.3.0.tar.gz.

File metadata

  • Download URL: pytest_django_autocheck-0.3.0.tar.gz
  • Upload date:
  • Size: 58.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pytest_django_autocheck-0.3.0.tar.gz
Algorithm Hash digest
SHA256 293f7f0ff70cb49958faeae66f08567f5167d228456f7e650b17f33808f18f9e
MD5 bd1483527fb35a082cb573440731c2fb
BLAKE2b-256 ac9a26aaf5405ead97a4016d639b11c798ab7a69857b09115c5dea32295f6463

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_django_autocheck-0.3.0.tar.gz:

Publisher: create-release.yml on fabiocaccamo/pytest-django-autocheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pytest_django_autocheck-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_django_autocheck-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fd5d389d03f2f3a496183c239839de54423d5065d78139e0490ba2810cc12afc
MD5 ff32857f554912c067641cc3bc6743e8
BLAKE2b-256 d9d29701f4cbe6c68737910cb326313671447ff497f0c6b4ec61ed5b145ec605

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_django_autocheck-0.3.0-py3-none-any.whl:

Publisher: create-release.yml on fabiocaccamo/pytest-django-autocheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page