All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- The plugin now actually works on its advertised
pytest >= 7.4floor. The rootdir-conftest preload (the mechanism that letsregister()calls run before pytest-django's hook) called the private_loadconftestmodules, which does not exist in pytest 7 — there the method is_getconftestmodules, with a different signature and noconsider_namespace_packagesconcept. On pytest 7 the call raisedAttributeError, was swallowed by the preload's broadexcept, and the rootdir conftest was silently never preloaded, soregister()-based config and early env injection didn't take effect (6 tests failed). The preload now dispatches on method presence:_loadconftestmodules(withconsider_namespace_packages) on pytest >= 8, falling back to_getconftestmodules(path, importmode, rootpath)on pytest 7.
- Test matrix across pytest 7.x, 8.x and 9.x (Python 3.10–3.13), runnable
locally via
tox(newtox.ini,tox/tox-uvadded to thedevextra) and mirrored in CI. Thepy3.13 × pytest7cell is excluded (pytest gained Python 3.13 support in 8.3). CI also splits linting into its own job.
- Relaxed the pytest dependency cap from
<9to<10, so the package installs alongside pytest 9 (validated by the new matrix). Bumped thepytest-testcontainersfloor to>= 0.2.0, the release whose own pytest cap was raised to<10(0.1.0 pinnedpytest < 9and would otherwise block pytest 9 transitively).
- The rootdir-conftest preload no longer dumps a spurious traceback
(
preloading rootdir conftest.py raised; continuing) when the conftest transitively touches the Django app registry beforedjango.setup()has run — e.g.model_bakery>= 1.20 callingapps.is_installed()at import. 0.2.1 added a quiet-deferral shortcut, but it only recognisedImproperlyConfigured(raised whenDJANGO_SETTINGS_MODULEis unset). When the settings module is configured early but the app registry has not been populated yet, Django raises the sibling exceptionAppRegistryNotReady("Apps aren't loaded yet.") instead — which is not a subclass ofImproperlyConfigured, so the shortcut missed it and the benign deferral was logged as an error. The predicate (renamed_is_django_not_configured→_is_django_not_ready) now matches both exceptions by class name.
- Serial (no-
-n) pytest runs no longer connect to the developer's local Postgres port instead of the testcontainer port. Root cause: the rootdir-conftest preload (the mechanism that letsregister()calls run before pytest-django's hook) can transitively touchdjango.conf.settingsat module top level — e.g. a BPP-stylefrom django.utils.translation import activateinconftest.py. That triggers Django's lazySettingsto bind before we inject the container's host/port intoos.environ, freezingDATABASES["default"]["PORT"]to whatever the developer's.envor shell had set (commonly5432). Pytest-django's laterdjango.setup()reused that stale cache, so tests opened psycopg connections to the wrong port. pytest-xdist runs accidentally hid the bug because workers are fresh subprocesses that re-import everything against the injected env. Fix: afterinject()succeeds, evict the cachedLazySettings._wrappedand drop the user's settings sub-package fromsys.modules, so the next access (pytest-django'sdjango.setup()) re-imports module-level code with the now-corrected environment.
- The rootdir-conftest preload (the mechanism that lets
register()calls run before pytest-django's hook) now logs at DEBUG level — instead of emitting a full WARNING-level traceback — when the import fails because Django settings aren't configured yet. This is the common case when a conftest transitively importsmodel_bakery >= 1.20, which callsapps.is_installed(...)at module import time. The conftest is still re-imported by pytest's normal trylast loader after our env injection and pytest-django run, so tests work as before — only the noisy traceback at the end of the run is gone. Unrelated conftest errors (anything not chaining toImproperlyConfigured) keep the original WARNING + traceback behaviour.
- New
[redis]install extra soredis_enabled = trueworks without a separatepip install redis(testcontainers.redisimports the Python redis client at module load). ReuseStaleContainerErrorand matchingpytest.UsageErrorfor the reuse-mode edge case where a pre-existing container is indead/removingstate — surfaced with the exactdocker rm -f <name>command instead of letting Docker fail the start with a 409 name conflict.
__version__now reads fromimportlib.metadataso it stays in sync withpyproject.toml.- README Django support matrix marks 4.2 LTS as past EOL (Apr 2026).
- The plugin's own test suite now disables eager-start via a root
conftest.pyrather thantests/conftest.py. The root file is preloaded by the plugin'stryfirsthook;tests/conftest.pyis not — meaning the previous setup silently ran every "unit" test against a real Docker daemon when one was available locally (CI was unaffected because it sets the env var explicitly).
Initial release.
pytest_load_initial_conftests(tryfirst=True)hook that starts Postgres (and optionally Redis) containers and injects connection details intoos.environbefore pytest-django imports settings.- Configuration via
[tool.pytest-testcontainers-django]inpyproject.tomlor programmatically viaregister(DjangoContainerConfig(...))fromconftest.py. - Postgres init-script mounting (
/docker-entrypoint-initdb.d/NN-name.sql) with automaticpostgres_template = postgres_databasedefaulting when init scripts are present (SPEC §10.6). - Reuse mode via
PYTEST_TESTCONTAINERS_REUSE=1, with a stderr warning when init scripts wouldn't be replayed against a pre-existing container (SPEC §10.7). - pytest-xdist worker handling: workers inherit env from the controller and
only set the
*_SKIP_DOTENVflag (SPEC §7). - Optional integration with
django-pg-baselinevia theuse_django_pg_baseline = trueflag. - atexit safety net for abrupt-exit paths that skip
pytest_unconfigure. - Custom
*_SKIP_DOTENVenv-var injection so projects using django-environ don't have their just-injected ports clobbered by.envreload (SPEC §9).