pytest-django icon indicating copy to clipboard operation
pytest-django copied to clipboard

Add a pytest marker for Django's `isolate_apps`

Open paduszyk opened this issue 2 months ago • 1 comments

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_apps is tied to database access;
  • isolate_apps isolates 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):
        yield

This wraps the test execution inside Django's isolate_apps context manager and follows the same marker-based pattern used elsewhere in pytest-django.

paduszyk avatar Nov 14 '25 13:11 paduszyk

Makes sense. PRs welcome!

kingbuzzman avatar Nov 14 '25 16:11 kingbuzzman