-
Notifications
You must be signed in to change notification settings - Fork 352
Description
Django provides django.test.utils.isolate_apps() to isolate the app registry for a test. It's the recommended mechanism when defining
temporary models or avoiding side effects on the global app registry. However, Django's decorator form only works on unittest.TestCase subclasses. Applying it to a plain pytest test class:
from django.test.utils import isolate_apps
@isolate_apps("myapp")
class TestModel:
...raises a TypeError.
pytest-django wraps several Django testing features with pytest-native markers (django_db, urls, etc.), but currently there is no pytest-native way to use isolate_apps on classes or functions that don't inherit from Django's test classes.
Relation to existing features
I'm aware of pytest.mark.django_db(available_apps=...), which limits the set of available apps for database setup/teardown. That's useful but not equivalent:
available_appsis tied to database access;isolate_appsisolates the app registry itself and is designed for scenarios such as temporary model definitions (e.g. testing custom base model features), even when the database isn't used.
I believe these serve different purposes, and a pytest-native isolate_apps would complement rather than overlap with available_apps.
Feature request
Add a marker that mirrors Django's isolate_apps and works on pytest test functions, methods, and classes:
@pytest.mark.isolate_apps("myapp")
class TestModel:
...
@pytest.mark.isolate_apps("app1", "app2")
def test_something():
...The marker should accept one or more app labels.
Would you be open to adding such a marker to pytest-django?
Possible implementation sketch
(Just to illustrate the idea; exact details can differ.)
def pytest_configure(config):
config.addinivalue_line(
"markers",
"isolate_apps(*app_labels): isolate one or more apps for this test using django.test.utils.isolate_apps",
)
def pytest_runtest_setup(item):
marker = item.get_closest_marker("isolate_apps")
if not marker:
return
app_labels = marker.args
if not app_labels:
pytest.fail("@pytest.mark.isolate_apps requires at least one app label")
item._isolate_apps_labels = app_labels
item.fixturenames.append("_isolate_apps")
@pytest.fixture
def _isolate_apps(request):
from django.test.utils import isolate_apps
labels = request.node._isolate_apps_labels
with isolate_apps(*labels):
yieldThis wraps the test execution inside Django's isolate_apps context manager and follows the same marker-based pattern used elsewhere in pytest-django.