Skip to content

Commit 69392f4

Browse files
committed
remove cache, use session-scoped fixture
1 parent 9103942 commit 69392f4

File tree

3 files changed

+66
-41
lines changed

3 files changed

+66
-41
lines changed

pytest_django/lazy_django.py

+4-12
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
import pytest
99

1010

11-
_django_settings_is_configured = None
12-
13-
1411
def skip_if_no_django():
1512
"""Raises a skip exception when no Django settings are available"""
1613
if not django_settings_is_configured():
@@ -24,17 +21,12 @@ def django_settings_is_configured():
2421
configured flag in the Django settings object if django.conf has already
2522
been imported.
2623
"""
27-
global _django_settings_is_configured
28-
29-
if _django_settings_is_configured is None:
30-
ret = bool(os.environ.get("DJANGO_SETTINGS_MODULE"))
31-
32-
if not ret and "django.conf" in sys.modules:
33-
ret = sys.modules["django.conf"].settings.configured
24+
ret = bool(os.environ.get("DJANGO_SETTINGS_MODULE"))
3425

35-
_django_settings_is_configured = ret
26+
if not ret and "django.conf" in sys.modules:
27+
ret = sys.modules["django.conf"].settings.configured
3628

37-
return _django_settings_is_configured
29+
return ret
3830

3931

4032
def get_django_version():

pytest_django/plugin.py

+32-29
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,13 @@ def pytest_runtest_setup(item):
425425
_disable_class_methods(item.cls)
426426

427427

428+
@pytest.fixture(scope="session")
429+
def _django_settings_is_configured():
430+
return django_settings_is_configured()
431+
432+
428433
@pytest.fixture(autouse=True, scope="session")
429-
def django_test_environment(request):
434+
def django_test_environment(_django_settings_is_configured):
430435
"""
431436
Ensure that Django is loaded and has its testing environment setup.
432437
@@ -437,18 +442,22 @@ def django_test_environment(request):
437442
without duplicating a lot more of Django's test support code
438443
we need to follow this model.
439444
"""
440-
if django_settings_is_configured():
445+
if _django_settings_is_configured:
441446
_setup_django()
442447
from django.conf import settings as dj_settings
443448
from django.test.utils import setup_test_environment, teardown_test_environment
444449

445450
dj_settings.DEBUG = False
446451
setup_test_environment()
447-
request.addfinalizer(teardown_test_environment)
452+
453+
yield
454+
455+
if _django_settings_is_configured:
456+
teardown_test_environment()
448457

449458

450459
@pytest.fixture(scope="session")
451-
def django_db_blocker():
460+
def django_db_blocker(_django_settings_is_configured):
452461
"""Wrapper around Django's database access.
453462
454463
This object can be used to re-enable database access. This fixture is used
@@ -461,10 +470,8 @@ def django_db_blocker():
461470
This is an advanced feature that is meant to be used to implement database
462471
fixtures.
463472
"""
464-
if not django_settings_is_configured():
465-
return None
466-
467-
return _blocking_manager
473+
if _django_settings_is_configured:
474+
return _blocking_manager
468475

469476

470477
@pytest.fixture(autouse=True)
@@ -486,9 +493,9 @@ def _django_db_marker(request):
486493

487494

488495
@pytest.fixture(autouse=True, scope="class")
489-
def _django_setup_unittest(request, django_db_blocker):
496+
def _django_setup_unittest(request, django_db_blocker, _django_settings_is_configured):
490497
"""Setup a django unittest, internal to pytest-django."""
491-
if django_settings_is_configured() and is_django_unittest(request):
498+
if _django_settings_is_configured and is_django_unittest(request):
492499
request.getfixturevalue("django_test_environment")
493500
request.getfixturevalue("django_db_setup")
494501

@@ -528,23 +535,20 @@ def teardown():
528535

529536

530537
@pytest.fixture(scope="function", autouse=True)
531-
def _dj_autoclear_mailbox():
532-
if not django_settings_is_configured():
533-
return
534-
535-
from django.core import mail
538+
def _dj_autoclear_mailbox(_django_settings_is_configured):
539+
if _django_settings_is_configured:
540+
from django.core import mail
536541

537-
del mail.outbox[:]
542+
del mail.outbox[:]
538543

539544

540545
@pytest.fixture(scope="function")
541-
def mailoutbox(monkeypatch, django_mail_patch_dns, _dj_autoclear_mailbox):
542-
if not django_settings_is_configured():
543-
return
546+
def mailoutbox(monkeypatch, django_mail_patch_dns, _dj_autoclear_mailbox,
547+
_django_settings_is_configured):
548+
if _django_settings_is_configured:
549+
from django.core import mail
544550

545-
from django.core import mail
546-
547-
return mail.outbox
551+
return mail.outbox
548552

549553

550554
@pytest.fixture(scope="function")
@@ -590,7 +594,7 @@ def restore():
590594

591595

592596
@pytest.fixture(autouse=True, scope="session")
593-
def _fail_for_invalid_template_variable(request):
597+
def _fail_for_invalid_template_variable(_django_settings_is_configured):
594598
"""Fixture that fails for invalid variables in templates.
595599
596600
This fixture will fail each test that uses django template rendering
@@ -662,7 +666,7 @@ def __mod__(self, var):
662666

663667
if (
664668
os.environ.get(INVALID_TEMPLATE_VARS_ENV, "false") == "true"
665-
and django_settings_is_configured()
669+
and _django_settings_is_configured
666670
):
667671
from django.conf import settings as dj_settings
668672

@@ -675,12 +679,12 @@ def __mod__(self, var):
675679

676680

677681
@pytest.fixture(autouse=True)
678-
def _template_string_if_invalid_marker(request):
682+
def _template_string_if_invalid_marker(request, _django_settings_is_configured):
679683
"""Apply the @pytest.mark.ignore_template_errors marker,
680684
internal to pytest-django."""
681685
marker = request.keywords.get("ignore_template_errors", None)
682686
if os.environ.get(INVALID_TEMPLATE_VARS_ENV, "false") == "true":
683-
if marker and django_settings_is_configured():
687+
if marker and _django_settings_is_configured:
684688
from django.conf import settings as dj_settings
685689

686690
if dj_settings.TEMPLATES:
@@ -690,12 +694,11 @@ def _template_string_if_invalid_marker(request):
690694

691695

692696
@pytest.fixture(autouse=True, scope="function")
693-
def _django_clear_site_cache():
697+
def _django_clear_site_cache(_django_settings_is_configured):
694698
"""Clears ``django.contrib.sites.models.SITE_CACHE`` to avoid
695699
unexpected behavior with cached site objects.
696700
"""
697-
698-
if django_settings_is_configured():
701+
if _django_settings_is_configured:
699702
from django.conf import settings as dj_settings
700703

701704
if "django.contrib.sites" in dj_settings.INSTALLED_APPS:

tests/test_django_settings_module.py

+30
Original file line numberDiff line numberDiff line change
@@ -450,3 +450,33 @@ def test_no_django_settings_but_django_imported(testdir, monkeypatch):
450450
testdir.makeconftest("import django")
451451
r = testdir.runpytest_subprocess("--help")
452452
assert r.ret == 0
453+
454+
455+
def test_django_settings_is_configured_cached(testdir, monkeypatch):
456+
"""
457+
``django_settings_is_configured`` should return the initial value always.
458+
459+
This avoids having the _dj_autoclear_mailbox autouse fixture trigger
460+
"AttributeError: module 'django.core.mail' has no attribute 'outbox'".
461+
"""
462+
monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
463+
464+
p = testdir.makepyfile(
465+
"""
466+
from pytest_django.lazy_django import django_settings_is_configured
467+
468+
def test_1(_django_settings_is_configured):
469+
import os
470+
471+
assert not _django_settings_is_configured
472+
assert not django_settings_is_configured()
473+
474+
os.environ["DJANGO_SETTINGS_MODULE"] = "ignored_dsm"
475+
476+
def test_2(_django_settings_is_configured):
477+
assert not _django_settings_is_configured
478+
assert django_settings_is_configured()
479+
""")
480+
result = testdir.runpytest_subprocess(p, "-s")
481+
result.stdout.fnmatch_lines(["*2 passed in*"])
482+
assert result.ret == 0

0 commit comments

Comments
 (0)