Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ Compatibility

* Official Django 6.1 support.

Bugfixes
^^^^^^^^

* Fixed the :fixture:`settings` fixture restoring the settings of an
``override_settings`` that was entered after the fixture was set up but
exited before it was torn down, which leaked those settings into later
tests and could eventually cause a ``RecursionError``
(`#809 <https://github.com/pytest-dev/pytest-django/issues/809>`__).

v4.14.0 (2026-08-10)
--------------------

Expand Down
9 changes: 8 additions & 1 deletion pytest_django/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,15 @@ def __init__(
assert _is_pytest_django, (
"Settings should only be instantiated from the `settings` fixture"
)
from django.test import override_settings

# Disabled last, so the settings active when the fixture was set up
# are restored even if an override_settings entered later exits
# before the fixture is finalized.
base = override_settings()
base.enable()
self._to_restore: list[django.test.override_settings]
object.__setattr__(self, "_to_restore", [])
object.__setattr__(self, "_to_restore", [base])

def __delattr__(self, attr: str) -> None:
from django.test import override_settings
Expand Down
32 changes: 32 additions & 0 deletions tests/test_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,38 @@ def test_set_non_existent(settings):
]
)

def test_override_settings_exited_before_teardown(
self, django_pytester: DjangoPytester
) -> None:
django_pytester.create_test_module(
"""
import pytest

from django.conf import settings as django_settings
from django.test import override_settings


@pytest.fixture
def overrides():
with override_settings(OVERRIDDEN=1):
yield


def test_override_inside_settings_fixture(settings, overrides):
settings.ADDED = 1
assert django_settings.OVERRIDDEN == 1
assert django_settings.ADDED == 1


def test_settings_restored():
assert not hasattr(django_settings, "OVERRIDDEN")
assert not hasattr(django_settings, "ADDED")
"""
)

result = django_pytester.runpytest_subprocess("-v")
result.assert_outcomes(passed=2)


class TestLiveServer:
@pytest.mark.skipif("PYTEST_XDIST_WORKER" in os.environ, reason="xdist in use")
Expand Down