Skip to content

Add a pytest marker for Django's isolate_apps #1253

@paduszyk

Description

@paduszyk

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions