Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Make django_settings_is_configured return the first value always #708

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion pytest_django/lazy_django.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def django_settings_is_configured():
ret = bool(os.environ.get("DJANGO_SETTINGS_MODULE"))

if not ret and "django.conf" in sys.modules:
return sys.modules["django.conf"].settings.configured
ret = sys.modules["django.conf"].settings.configured

return ret

Expand Down
71 changes: 38 additions & 33 deletions pytest_django/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,13 @@ def get_order_number(test):
items[:] = sorted(items, key=get_order_number)


@pytest.fixture(scope="session")
def _django_settings_is_configured():
return django_settings_is_configured()


@pytest.fixture(autouse=True, scope="session")
def django_test_environment(request):
def django_test_environment(_django_settings_is_configured):
"""
Ensure that Django is loaded and has its testing environment setup.

Expand All @@ -463,18 +468,22 @@ def django_test_environment(request):
without duplicating a lot more of Django's test support code
we need to follow this model.
"""
if django_settings_is_configured():
if _django_settings_is_configured:
_setup_django()
from django.conf import settings as dj_settings
from django.test.utils import setup_test_environment, teardown_test_environment

dj_settings.DEBUG = False
setup_test_environment()
request.addfinalizer(teardown_test_environment)

yield

if _django_settings_is_configured:
teardown_test_environment()


@pytest.fixture(scope="session")
def django_db_blocker():
def django_db_blocker(_django_settings_is_configured):
"""Wrapper around Django's database access.

This object can be used to re-enable database access. This fixture is used
Expand All @@ -487,10 +496,8 @@ def django_db_blocker():
This is an advanced feature that is meant to be used to implement database
fixtures.
"""
if not django_settings_is_configured():
return None

return _blocking_manager
if _django_settings_is_configured:
return _blocking_manager


@pytest.fixture(autouse=True)
Expand All @@ -512,9 +519,9 @@ def _django_db_marker(request):


@pytest.fixture(autouse=True, scope="class")
def _django_setup_unittest(request, django_db_blocker):
def _django_setup_unittest(request, django_db_blocker, _django_settings_is_configured):
"""Setup a django unittest, internal to pytest-django."""
if not django_settings_is_configured() or not is_django_unittest(request):
if not _django_settings_is_configured or not is_django_unittest(request):
yield
return

Expand Down Expand Up @@ -553,34 +560,33 @@ def _cleaning_debug(self):


@pytest.fixture(scope="function", autouse=True)
def _dj_autoclear_mailbox():
if not django_settings_is_configured():
return

from django.core import mail
def _dj_autoclear_mailbox(_django_settings_is_configured):
if _django_settings_is_configured:
from django.core import mail

del mail.outbox[:]
del mail.outbox[:]


@pytest.fixture(scope="function")
def mailoutbox(monkeypatch, django_mail_patch_dns, _dj_autoclear_mailbox):
if not django_settings_is_configured():
return

from django.core import mail
def mailoutbox(django_mail_patch_dns, _dj_autoclear_mailbox,
_django_settings_is_configured):
if _django_settings_is_configured:
from django.core import mail

return mail.outbox
return mail.outbox


@pytest.fixture(scope="function")
def django_mail_patch_dns(monkeypatch, django_mail_dnsname):
from django.core import mail
def django_mail_patch_dns(monkeypatch, django_mail_dnsname,
_django_settings_is_configured):
if _django_settings_is_configured:
from django.core import mail

monkeypatch.setattr(mail.message, "DNS_NAME", django_mail_dnsname)
monkeypatch.setattr(mail.message, "DNS_NAME", django_mail_dnsname)


@pytest.fixture(scope="function")
def django_mail_dnsname(monkeypatch):
def django_mail_dnsname():
return "fake-tests.example.com"


Expand Down Expand Up @@ -615,7 +621,7 @@ def restore():


@pytest.fixture(autouse=True, scope="session")
def _fail_for_invalid_template_variable(request):
def _fail_for_invalid_template_variable(_django_settings_is_configured):
"""Fixture that fails for invalid variables in templates.

This fixture will fail each test that uses django template rendering
Expand Down Expand Up @@ -687,7 +693,7 @@ def __mod__(self, var):

if (
os.environ.get(INVALID_TEMPLATE_VARS_ENV, "false") == "true"
and django_settings_is_configured()
and _django_settings_is_configured
):
from django.conf import settings as dj_settings

Expand All @@ -700,12 +706,12 @@ def __mod__(self, var):


@pytest.fixture(autouse=True)
def _template_string_if_invalid_marker(request):
def _template_string_if_invalid_marker(request, _django_settings_is_configured):
"""Apply the @pytest.mark.ignore_template_errors marker,
internal to pytest-django."""
marker = request.keywords.get("ignore_template_errors", None)
if os.environ.get(INVALID_TEMPLATE_VARS_ENV, "false") == "true":
if marker and django_settings_is_configured():
if marker and _django_settings_is_configured:
from django.conf import settings as dj_settings

if dj_settings.TEMPLATES:
Expand All @@ -715,12 +721,11 @@ def _template_string_if_invalid_marker(request):


@pytest.fixture(autouse=True, scope="function")
def _django_clear_site_cache():
def _django_clear_site_cache(_django_settings_is_configured):
"""Clears ``django.contrib.sites.models.SITE_CACHE`` to avoid
unexpected behavior with cached site objects.
"""

if django_settings_is_configured():
if _django_settings_is_configured:
from django.conf import settings as dj_settings

if "django.contrib.sites" in dj_settings.INSTALLED_APPS:
Expand Down
32 changes: 32 additions & 0 deletions tests/test_django_settings_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,35 @@ def test_no_django_settings_but_django_imported(testdir, monkeypatch):
testdir.makeconftest("import django")
r = testdir.runpytest_subprocess("--help")
assert r.ret == 0


def test_django_settings_is_configured_first(testdir, monkeypatch):
"""
The value from ``django_settings_is_configured`` should be used internally
always.

This avoids having the _dj_autoclear_mailbox autouse fixture trigger
"AttributeError: module 'django.core.mail' has no attribute 'outbox'",
because Django / the test environment was not setup initially.
"""
monkeypatch.delenv("DJANGO_SETTINGS_MODULE")

p = testdir.makepyfile(
"""
from pytest_django.lazy_django import django_settings_is_configured

def test_1(_django_settings_is_configured):
import os

assert not _django_settings_is_configured
assert not django_settings_is_configured()

os.environ["DJANGO_SETTINGS_MODULE"] = "ignored_dsm"

def test_2(_django_settings_is_configured):
assert not _django_settings_is_configured
assert django_settings_is_configured()
""")
result = testdir.runpytest_subprocess(p, "-s")
result.stdout.fnmatch_lines(["*2 passed in*"])
assert result.ret == 0