From 1fe4ef768dbad77a833a4ecc70a07207d4bda641 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Mon, 31 Mar 2025 15:34:52 -0400 Subject: [PATCH 01/23] Update plugin.py --- pytest_django/plugin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index 08d961a6..fc439819 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -599,7 +599,8 @@ def _dj_autoclear_mailbox() -> None: from django.core import mail - del mail.outbox[:] + if hasattr(main, "outbox": + mail.outbox.clear() @pytest.fixture() From acd9d6182b5db49e0715e76c1abc1982aa981ad0 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Mon, 31 Mar 2025 15:37:33 -0400 Subject: [PATCH 02/23] Update plugin.py --- pytest_django/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index fc439819..2309c9ed 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -599,7 +599,7 @@ def _dj_autoclear_mailbox() -> None: from django.core import mail - if hasattr(main, "outbox": + if hasattr(main, "outbox"): mail.outbox.clear() From 502380faa59d98c6137f74b14abe05170423d832 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Mon, 31 Mar 2025 15:41:33 -0400 Subject: [PATCH 03/23] Update test_environment.py --- tests/test_environment.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_environment.py b/tests/test_environment.py index a3549732..2823d813 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -18,6 +18,23 @@ # to do it. +@pytest.mark.django_project( + project_root="django_project_root", + extra_settings=""" + EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" + """, +) +def test_manage_test_runner(django_pytester: DjangoPytester) -> None: + django_pytester.create_test_module( + """ + def test_bad_mail(): + pass + """ + ) + result = django_pytester.runpytest_subprocess("-s") + assert "1 passed" in "\n".join(result.outlines) + + @pytest.mark.parametrize("subject", ["subject1", "subject2"]) def test_autoclear_mailbox(subject: str) -> None: assert len(mail.outbox) == 0 From c8427b437f48efdf9ff3c3090a10e52dd2f4cc46 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Mon, 31 Mar 2025 15:42:37 -0400 Subject: [PATCH 04/23] i want to see it fail --- pytest_django/plugin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index 2309c9ed..eece6a51 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -599,8 +599,9 @@ def _dj_autoclear_mailbox() -> None: from django.core import mail - if hasattr(main, "outbox"): - mail.outbox.clear() + del mail.outbox[:] + # if hasattr(main, "outbox"): + # mail.outbox.clear() @pytest.fixture() From 9e786dba0541d97cc8a285e90d453f9e496d95af Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Mon, 31 Mar 2025 15:48:41 -0400 Subject: [PATCH 05/23] Update test_environment.py --- tests/test_environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_environment.py b/tests/test_environment.py index 2823d813..26876ab5 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -32,7 +32,7 @@ def test_bad_mail(): """ ) result = django_pytester.runpytest_subprocess("-s") - assert "1 passed" in "\n".join(result.outlines) + assert "1 passed" in "\n".join([*result.outlines, *result.errlines]) @pytest.mark.parametrize("subject", ["subject1", "subject2"]) From b9dee6aec323ffe6d78b5da9ace65a0e1608690e Mon Sep 17 00:00:00 2001 From: kingbuzzman <buzzi.javier@gmail.com> Date: Mon, 31 Mar 2025 17:47:51 -0400 Subject: [PATCH 06/23] This is a much bigger issue. --- pytest_django/plugin.py | 7 ++++--- tests/test_environment.py | 26 +++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index eece6a51..fe315fe5 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -599,9 +599,10 @@ def _dj_autoclear_mailbox() -> None: from django.core import mail - del mail.outbox[:] - # if hasattr(main, "outbox"): - # mail.outbox.clear() + # import ipdb; print('\a'); ipdb.sset_trace() + # del mail.outbox[:] + if hasattr(mail, "outbox"): + mail.outbox.clear() @pytest.fixture() diff --git a/tests/test_environment.py b/tests/test_environment.py index 26876ab5..8e375c65 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -19,19 +19,39 @@ @pytest.mark.django_project( - project_root="django_project_root", extra_settings=""" EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" + import unittest.mock + from types import SimpleNamespace + + def setup_test_environment(*a, **k): + if hasattr(_TestState, "saved_data"): + # Executing this function twice would overwrite the saved values. + raise RuntimeError( + "setup_test_environment() was already called and can't be called " + "again without first calling teardown_test_environment()." + ) + + saved_data = SimpleNamespace() + _TestState.saved_data = saved_data + saved_data.allowed_hosts = [] + saved_data.debug = False + saved_data.email_backend = None + saved_data.template_render = None + + unittest.mock.patch("django.test.utils.setup_test_environment", setup_test_environment).start() + from django.test.utils import _TestState """, ) -def test_manage_test_runner(django_pytester: DjangoPytester) -> None: +def test_mail_auto_fixture(django_pytester: DjangoPytester) -> None: django_pytester.create_test_module( """ def test_bad_mail(): pass """ ) - result = django_pytester.runpytest_subprocess("-s") + result = django_pytester.runpytest_subprocess("-s", "-vv") + print("\n".join([*result.outlines, *result.errlines])) assert "1 passed" in "\n".join([*result.outlines, *result.errlines]) From 2b5b1977927177ec8de7744d4e380c5ed76b4ea3 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Tue, 1 Apr 2025 10:59:21 +0200 Subject: [PATCH 07/23] Update test_environment.py --- tests/test_environment.py | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/tests/test_environment.py b/tests/test_environment.py index 8e375c65..687bbe69 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -21,26 +21,8 @@ @pytest.mark.django_project( extra_settings=""" EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" - import unittest.mock - from types import SimpleNamespace - - def setup_test_environment(*a, **k): - if hasattr(_TestState, "saved_data"): - # Executing this function twice would overwrite the saved values. - raise RuntimeError( - "setup_test_environment() was already called and can't be called " - "again without first calling teardown_test_environment()." - ) - - saved_data = SimpleNamespace() - _TestState.saved_data = saved_data - saved_data.allowed_hosts = [] - saved_data.debug = False - saved_data.email_backend = None - saved_data.template_render = None - unittest.mock.patch("django.test.utils.setup_test_environment", setup_test_environment).start() - from django.test.utils import _TestState + unittest.mock.patch("pytest_django.lazy_django.django_settings_is_configured", lambda: False).start() """, ) def test_mail_auto_fixture(django_pytester: DjangoPytester) -> None: @@ -50,7 +32,7 @@ def test_bad_mail(): pass """ ) - result = django_pytester.runpytest_subprocess("-s", "-vv") + result = django_pytester.runpytest_subprocess("-s") print("\n".join([*result.outlines, *result.errlines])) assert "1 passed" in "\n".join([*result.outlines, *result.errlines]) From 60a07b2a12596bd8777cb915ed2bfc64abe8b48a Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Tue, 1 Apr 2025 11:00:07 +0200 Subject: [PATCH 08/23] Update test_environment.py --- tests/test_environment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_environment.py b/tests/test_environment.py index 687bbe69..98cb79d6 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -22,6 +22,7 @@ extra_settings=""" EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" + import unittest.mock unittest.mock.patch("pytest_django.lazy_django.django_settings_is_configured", lambda: False).start() """, ) From e831c77373cbda0b28e8e548180dbcfc83d0de5c Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Tue, 1 Apr 2025 11:49:43 +0200 Subject: [PATCH 09/23] getting closer.. --- pytest_django/plugin.py | 5 ++--- tests/test_environment.py | 11 +++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index fe315fe5..b479fefb 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -599,8 +599,6 @@ def _dj_autoclear_mailbox() -> None: from django.core import mail - # import ipdb; print('\a'); ipdb.sset_trace() - # del mail.outbox[:] if hasattr(mail, "outbox"): mail.outbox.clear() @@ -616,7 +614,8 @@ def mailoutbox( from django.core import mail - return mail.outbox # type: ignore[no-any-return] + if hasattr(mail, "outbox"): + return mail.outbox # type: ignore[no-any-return] @pytest.fixture() diff --git a/tests/test_environment.py b/tests/test_environment.py index 98cb79d6..a568c60f 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -19,21 +19,24 @@ @pytest.mark.django_project( + create_manage_py=True, extra_settings=""" EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" import unittest.mock - unittest.mock.patch("pytest_django.lazy_django.django_settings_is_configured", lambda: False).start() + unittest.mock.patch("django.test.utils.setup_test_environment", lambda *a, **k: None).start() + unittest.mock.patch("django.test.utils.teardown_test_environment", lambda *a, **k: None).start() """, ) def test_mail_auto_fixture(django_pytester: DjangoPytester) -> None: django_pytester.create_test_module( """ - def test_bad_mail(): - pass + def test_bad_mail(settings, mailoutbox): + assert mailoutbox is None + assert settings.EMAIL_BACKEND == "django.core.mail.backends.dummy.EmailBackend" """ ) - result = django_pytester.runpytest_subprocess("-s") + result = django_pytester.runpytest_subprocess("-s", '-vv') print("\n".join([*result.outlines, *result.errlines])) assert "1 passed" in "\n".join([*result.outlines, *result.errlines]) From e5631311edb1a0b62643df954296de56c30261ca Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Tue, 1 Apr 2025 12:01:50 +0200 Subject: [PATCH 10/23] got to the root issue, its a custom django_test_environment --- tests/test_environment.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/test_environment.py b/tests/test_environment.py index a568c60f..9188acbe 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -22,13 +22,19 @@ create_manage_py=True, extra_settings=""" EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" - - import unittest.mock - unittest.mock.patch("django.test.utils.setup_test_environment", lambda *a, **k: None).start() - unittest.mock.patch("django.test.utils.teardown_test_environment", lambda *a, **k: None).start() """, ) def test_mail_auto_fixture(django_pytester: DjangoPytester) -> None: + django_pytester.create_test_module( + """ + import pytest + + @pytest.fixture(autouse=True, scope="session") + def django_test_environment(request): + yield + """, filename="conftest.py" + ) + django_pytester.create_test_module( """ def test_bad_mail(settings, mailoutbox): From 43da9ac17508208a28620c0b1b6758c029ce2b20 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Tue, 1 Apr 2025 12:17:45 +0200 Subject: [PATCH 11/23] Moved test --- tests/test_environment.py | 29 ----------------------------- tests/test_fixtures.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/tests/test_environment.py b/tests/test_environment.py index 9188acbe..a3549732 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -18,35 +18,6 @@ # to do it. -@pytest.mark.django_project( - create_manage_py=True, - extra_settings=""" - EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" - """, -) -def test_mail_auto_fixture(django_pytester: DjangoPytester) -> None: - django_pytester.create_test_module( - """ - import pytest - - @pytest.fixture(autouse=True, scope="session") - def django_test_environment(request): - yield - """, filename="conftest.py" - ) - - django_pytester.create_test_module( - """ - def test_bad_mail(settings, mailoutbox): - assert mailoutbox is None - assert settings.EMAIL_BACKEND == "django.core.mail.backends.dummy.EmailBackend" - """ - ) - result = django_pytester.runpytest_subprocess("-s", '-vv') - print("\n".join([*result.outlines, *result.errlines])) - assert "1 passed" in "\n".join([*result.outlines, *result.errlines]) - - @pytest.mark.parametrize("subject", ["subject1", "subject2"]) def test_autoclear_mailbox(subject: str) -> None: assert len(mail.outbox) == 0 diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 39c6666f..4c98b899 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -825,3 +825,37 @@ def mocked_make_msgid(*args, **kwargs): result = django_pytester.runpytest_subprocess("--tb=short", "-vv", "-s") result.stdout.fnmatch_lines(["*test_mailbox_inner*", "django_mail_dnsname_mark", "PASSED*"]) assert result.ret == 0 + + +@pytest.mark.django_project( + create_manage_py=True, + extra_settings=""" + EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" + """, +) +def test_mail_auto_fixture_misconfigured(django_pytester: DjangoPytester) -> None: + """ + django_test_environment fixture can be overridden by user, and that would break mailoutbox fixture. + + Normally settings.EMAIL_BACKEND is set to "django.core.mail.backends.locmem.EmailBackend" by django, + along with mail.outbox = []. If this function doesn't run for whatever reason, the mailoutbox fixture will not work properly. + """ + django_pytester.create_test_module( + """ + import pytest + + @pytest.fixture(autouse=True, scope="session") + def django_test_environment(request): + yield + """, filename="conftest.py" + ) + + django_pytester.create_test_module( + """ + def test_bad_mail(settings, mailoutbox): + assert mailoutbox is None + assert settings.EMAIL_BACKEND == "django.core.mail.backends.dummy.EmailBackend" + """ + ) + result = django_pytester.runpytest_subprocess() + assert result.ret == 0 From c8c73550cf8d0786ecb38fa0e2f9914ade00eff4 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Tue, 1 Apr 2025 12:19:29 +0200 Subject: [PATCH 12/23] Fixes linter --- pytest_django/plugin.py | 1 + tests/test_fixtures.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index b479fefb..f99ea246 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -616,6 +616,7 @@ def mailoutbox( if hasattr(mail, "outbox"): return mail.outbox # type: ignore[no-any-return] + return None @pytest.fixture() diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 4c98b899..f8ca69c7 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -837,7 +837,7 @@ def test_mail_auto_fixture_misconfigured(django_pytester: DjangoPytester) -> Non """ django_test_environment fixture can be overridden by user, and that would break mailoutbox fixture. - Normally settings.EMAIL_BACKEND is set to "django.core.mail.backends.locmem.EmailBackend" by django, + Normally settings.EMAIL_BACKEND is set to "django.core.mail.backends.locmem.EmailBackend" by django, along with mail.outbox = []. If this function doesn't run for whatever reason, the mailoutbox fixture will not work properly. """ django_pytester.create_test_module( @@ -847,7 +847,8 @@ def test_mail_auto_fixture_misconfigured(django_pytester: DjangoPytester) -> Non @pytest.fixture(autouse=True, scope="session") def django_test_environment(request): yield - """, filename="conftest.py" + """, + filename="conftest.py", ) django_pytester.create_test_module( From 4e26a87597231a9b4945017bb05e7f739fd01f68 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Tue, 1 Apr 2025 12:29:43 +0200 Subject: [PATCH 13/23] Adds warning --- pytest_django/plugin.py | 6 +++++- tests/test_fixtures.py | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index f99ea246..faaa3535 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -593,7 +593,7 @@ def non_debugging_runtest(self) -> None: @pytest.fixture(autouse=True) -def _dj_autoclear_mailbox() -> None: +def _dj_autoclear_mailbox(request: pytest.FixtureRequest) -> None: if not django_settings_is_configured(): return @@ -601,6 +601,10 @@ def _dj_autoclear_mailbox() -> None: if hasattr(mail, "outbox"): mail.outbox.clear() + else: + request.node.warn( + pytest.PytestWarning("Error when trying to clear mailbox, possible misconfiguration") + ) @pytest.fixture() diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index f8ca69c7..bf4fccf9 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -838,8 +838,12 @@ def test_mail_auto_fixture_misconfigured(django_pytester: DjangoPytester) -> Non django_test_environment fixture can be overridden by user, and that would break mailoutbox fixture. Normally settings.EMAIL_BACKEND is set to "django.core.mail.backends.locmem.EmailBackend" by django, - along with mail.outbox = []. If this function doesn't run for whatever reason, the mailoutbox fixture will not work properly. + along with mail.outbox = []. If this function doesn't run for whatever reason, the + mailoutbox fixture will not work properly. """ + expected_warning_message = ( + "PytestWarning: Error when trying to clear mailbox, possible misconfiguration" + ) django_pytester.create_test_module( """ import pytest @@ -860,3 +864,4 @@ def test_bad_mail(settings, mailoutbox): ) result = django_pytester.runpytest_subprocess() assert result.ret == 0 + assert expected_warning_message in "\n".join(result.outlines) From 5effbf7f348fcd62e4ca5b1fde8cb4e080d5941f Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Tue, 1 Apr 2025 12:39:01 +0200 Subject: [PATCH 14/23] Test the warning --- tests/test_fixtures.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index bf4fccf9..8227ec84 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -857,11 +857,16 @@ def django_test_environment(request): django_pytester.create_test_module( """ - def test_bad_mail(settings, mailoutbox): + def test_with_fixture(settings, mailoutbox): assert mailoutbox is None assert settings.EMAIL_BACKEND == "django.core.mail.backends.dummy.EmailBackend" + + def test_without_fixture(): + from django.core import mail + assert not hasattr(mail, "outbox") """ ) - result = django_pytester.runpytest_subprocess() - assert result.ret == 0 - assert expected_warning_message in "\n".join(result.outlines) + result = django_pytester.runpytest_subprocess("-q") + output = "\n".join(result.outlines) + assert "2 passed, 2 warnings" in output + assert expected_warning_message in output From c4a9a7b252ec5badcc6b888c36619f77290c0794 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Tue, 1 Apr 2025 13:00:21 +0200 Subject: [PATCH 15/23] ehh f-it. this is good enough --- tests/test_fixtures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 8227ec84..db524cc6 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -868,5 +868,5 @@ def test_without_fixture(): ) result = django_pytester.runpytest_subprocess("-q") output = "\n".join(result.outlines) - assert "2 passed, 2 warnings" in output + assert "2 passed" in output assert expected_warning_message in output From 1d7a61570769783c498e2f9bb7e760bd3896abdd Mon Sep 17 00:00:00 2001 From: kingbuzzman <buzzi.javier@gmail.com> Date: Wed, 2 Apr 2025 15:43:19 -0400 Subject: [PATCH 16/23] Adds test for when there is no 'settings' at all --- tests/conftest.py | 7 ++++++- tests/test_fixtures.py | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 16e209f1..1ef17498 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -30,11 +30,13 @@ def _marker_apifun( extra_settings: str = "", create_manage_py: bool = False, project_root: str | None = None, + has_settings: bool = True, ): return { "extra_settings": extra_settings, "create_manage_py": create_manage_py, "project_root": project_root, + "has_settings": has_settings, } @@ -142,7 +144,10 @@ def django_pytester( pythonpath = os.pathsep.join(filter(None, [str(REPOSITORY_ROOT), os.getenv("PYTHONPATH", "")])) monkeypatch.setenv("PYTHONPATH", pythonpath) - monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "tpkg.the_settings") + if options["has_settings"]: + monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "tpkg.the_settings") + else: + monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False) def create_test_module(test_code: str, filename: str = "test_the_test.py") -> Path: r = tpkg_path.joinpath(filename) diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index db524cc6..500c34b0 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -870,3 +870,25 @@ def test_without_fixture(): output = "\n".join(result.outlines) assert "2 passed" in output assert expected_warning_message in output + + +@pytest.mark.django_project(has_settings=False) +def test_no_settings(django_pytester: DjangoPytester) -> None: + django_pytester.create_test_module( + """ + def test_skipped_settings(settings): + pass + + def test_mailoutbox(mailoutbox): + assert mailoutbox is None + + def test_mail(): + from django.core import mail + assert not hasattr(mail, "outbox") + """ + ) + result = django_pytester.runpytest_subprocess("-v") + output = "\n".join(result.outlines) + assert "::test_skipped_settings SKIPPED" in output + assert "::test_mailoutbox PASSED" in output + assert "::test_mail PASSED" in output From cf170faeff64ef9d0d966c622a42379b30064508 Mon Sep 17 00:00:00 2001 From: kingbuzzman <buzzi.javier@gmail.com> Date: Wed, 2 Apr 2025 15:46:14 -0400 Subject: [PATCH 17/23] Slight change to ensure that there really isnt any settings --- tests/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 1ef17498..ea59945d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -137,7 +137,8 @@ def django_pytester( # Copy the test app to make it available in the new test run shutil.copytree(str(app_source), str(test_app_path)) - tpkg_path.joinpath("the_settings.py").write_text(test_settings) + if options["has_settings"]: + tpkg_path.joinpath("the_settings.py").write_text(test_settings) # For suprocess tests, pytest's `pythonpath` setting doesn't currently # work, only the envvar does. From 534a7f2b7ed952d7b6c90fc8f7f9829619742c73 Mon Sep 17 00:00:00 2001 From: kingbuzzman <buzzi.javier@gmail.com> Date: Wed, 2 Apr 2025 16:06:22 -0400 Subject: [PATCH 18/23] Gigantic simplification --- pytest_django/plugin.py | 7 +------ tests/test_fixtures.py | 14 +++++--------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index faaa3535..e1d56156 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -601,10 +601,6 @@ def _dj_autoclear_mailbox(request: pytest.FixtureRequest) -> None: if hasattr(mail, "outbox"): mail.outbox.clear() - else: - request.node.warn( - pytest.PytestWarning("Error when trying to clear mailbox, possible misconfiguration") - ) @pytest.fixture() @@ -613,8 +609,7 @@ def mailoutbox( _dj_autoclear_mailbox: None, ) -> list[django.core.mail.EmailMessage] | None: """A clean email outbox to which Django-generated emails are sent.""" - if not django_settings_is_configured(): - return None + skip_if_no_django() from django.core import mail diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 500c34b0..0d6327ea 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -841,9 +841,6 @@ def test_mail_auto_fixture_misconfigured(django_pytester: DjangoPytester) -> Non along with mail.outbox = []. If this function doesn't run for whatever reason, the mailoutbox fixture will not work properly. """ - expected_warning_message = ( - "PytestWarning: Error when trying to clear mailbox, possible misconfiguration" - ) django_pytester.create_test_module( """ import pytest @@ -869,7 +866,6 @@ def test_without_fixture(): result = django_pytester.runpytest_subprocess("-q") output = "\n".join(result.outlines) assert "2 passed" in output - assert expected_warning_message in output @pytest.mark.django_project(has_settings=False) @@ -877,10 +873,10 @@ def test_no_settings(django_pytester: DjangoPytester) -> None: django_pytester.create_test_module( """ def test_skipped_settings(settings): - pass + assert False - def test_mailoutbox(mailoutbox): - assert mailoutbox is None + def test_skipped_mailoutbox(mailoutbox): + assert False def test_mail(): from django.core import mail @@ -890,5 +886,5 @@ def test_mail(): result = django_pytester.runpytest_subprocess("-v") output = "\n".join(result.outlines) assert "::test_skipped_settings SKIPPED" in output - assert "::test_mailoutbox PASSED" in output - assert "::test_mail PASSED" in output + assert "::test_skipped_mailoutbox SKIPPED" in output + assert "::test_mail PASSED" in output \ No newline at end of file From b330a26929cf06d1cbdbdf6b86a94cf998c8db96 Mon Sep 17 00:00:00 2001 From: kingbuzzman <buzzi.javier@gmail.com> Date: Wed, 2 Apr 2025 16:08:10 -0400 Subject: [PATCH 19/23] Removes unused import --- pytest_django/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index e1d56156..f8e1d071 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -593,7 +593,7 @@ def non_debugging_runtest(self) -> None: @pytest.fixture(autouse=True) -def _dj_autoclear_mailbox(request: pytest.FixtureRequest) -> None: +def _dj_autoclear_mailbox() -> None: if not django_settings_is_configured(): return From 80303a447062ba1bba42d15893a30d876bd2df52 Mon Sep 17 00:00:00 2001 From: kingbuzzman <buzzi.javier@gmail.com> Date: Wed, 2 Apr 2025 16:15:38 -0400 Subject: [PATCH 20/23] Updates linter --- tests/test_fixtures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 0d6327ea..62cb7f20 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -887,4 +887,4 @@ def test_mail(): output = "\n".join(result.outlines) assert "::test_skipped_settings SKIPPED" in output assert "::test_skipped_mailoutbox SKIPPED" in output - assert "::test_mail PASSED" in output \ No newline at end of file + assert "::test_mail PASSED" in output From 3223687b2bd08b1f3cb016a6481df9f2c1d1152b Mon Sep 17 00:00:00 2001 From: kingbuzzman <buzzi.javier@gmail.com> Date: Wed, 2 Apr 2025 17:10:38 -0400 Subject: [PATCH 21/23] Slight simplification when asserting tests --- tests/test_fixtures.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 62cb7f20..490dd8ef 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -863,9 +863,8 @@ def test_without_fixture(): assert not hasattr(mail, "outbox") """ ) - result = django_pytester.runpytest_subprocess("-q") - output = "\n".join(result.outlines) - assert "2 passed" in output + result = django_pytester.runpytest_subprocess() + result.assert_outcomes(passed=2) @pytest.mark.django_project(has_settings=False) @@ -883,8 +882,5 @@ def test_mail(): assert not hasattr(mail, "outbox") """ ) - result = django_pytester.runpytest_subprocess("-v") - output = "\n".join(result.outlines) - assert "::test_skipped_settings SKIPPED" in output - assert "::test_skipped_mailoutbox SKIPPED" in output - assert "::test_mail PASSED" in output + result = django_pytester.runpytest_subprocess() + result.assert_outcomes(passed=1, skipped=2) From 7acaee2530a4eb45acf4f6505e774d4f88273c8a Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Thu, 3 Apr 2025 16:11:12 -0400 Subject: [PATCH 22/23] Changes bluetech wanted --- pytest_django/plugin.py | 2 +- tests/conftest.py | 8 ++++---- tests/test_fixtures.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index f8e1d071..e8e629f4 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -615,7 +615,7 @@ def mailoutbox( if hasattr(mail, "outbox"): return mail.outbox # type: ignore[no-any-return] - return None + return [] @pytest.fixture() diff --git a/tests/conftest.py b/tests/conftest.py index ea59945d..e3bfa1f4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -30,13 +30,13 @@ def _marker_apifun( extra_settings: str = "", create_manage_py: bool = False, project_root: str | None = None, - has_settings: bool = True, + create_settings: bool = True, ): return { "extra_settings": extra_settings, "create_manage_py": create_manage_py, "project_root": project_root, - "has_settings": has_settings, + "create_settings": create_settings, } @@ -137,7 +137,7 @@ def django_pytester( # Copy the test app to make it available in the new test run shutil.copytree(str(app_source), str(test_app_path)) - if options["has_settings"]: + if options["create_settings"]: tpkg_path.joinpath("the_settings.py").write_text(test_settings) # For suprocess tests, pytest's `pythonpath` setting doesn't currently @@ -145,7 +145,7 @@ def django_pytester( pythonpath = os.pathsep.join(filter(None, [str(REPOSITORY_ROOT), os.getenv("PYTHONPATH", "")])) monkeypatch.setenv("PYTHONPATH", pythonpath) - if options["has_settings"]: + if options["create_settings"]: monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "tpkg.the_settings") else: monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False) diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 490dd8ef..9d55ad6d 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -867,7 +867,7 @@ def test_without_fixture(): result.assert_outcomes(passed=2) -@pytest.mark.django_project(has_settings=False) +@pytest.mark.django_project(create_settings=False) def test_no_settings(django_pytester: DjangoPytester) -> None: django_pytester.create_test_module( """ From 4975bc168b41c3a4951e108548a85ed815d31f28 Mon Sep 17 00:00:00 2001 From: Javier Buzzi <buzzi.javier@gmail.com> Date: Thu, 3 Apr 2025 16:14:40 -0400 Subject: [PATCH 23/23] Update test_fixtures.py --- tests/test_fixtures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 9d55ad6d..f88ed802 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -855,7 +855,7 @@ def django_test_environment(request): django_pytester.create_test_module( """ def test_with_fixture(settings, mailoutbox): - assert mailoutbox is None + assert mailoutbox == [] assert settings.EMAIL_BACKEND == "django.core.mail.backends.dummy.EmailBackend" def test_without_fixture():