pytest-dev / pytest-django

A Django plugin for pytest.
https://pytest-django.readthedocs.io/
Other
1.33k stars 341 forks source link

_dj_autoclear_mailbox ends quite often with AttributeError: module 'django.core.mail' has no attribute 'outbox' #993

Open mcepl opened 2 years ago

mcepl commented 2 years ago

When running the test suite for whitenoise plenty of tests ends with the following error (using pytest-6.2.5, pytest-django-4.5.2):

[   31s] _______ ERROR at setup of test_last_modified_not_set_when_mtime_is_zero ________
[   31s]
[   31s]     @pytest.fixture(scope="function", autouse=True)
[   31s]     def _dj_autoclear_mailbox() -> None:
[   31s]         if not django_settings_is_configured():
[   31s]             return
[   31s]
[   31s]         from django.core import mail
[   31s]
[   31s] >       if mail.outbox:
[   31s] E       AttributeError: module 'django.core.mail' has no attribute 'outbox'
[   31s]

When reading on the mail.outbox I found that it doesn’t exist quite often, so this fixture has protection against it. When I apply this patch:

---
 pytest_django/plugin.py |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

--- a/pytest_django/plugin.py
+++ b/pytest_django/plugin.py
@@ -502,7 +502,8 @@ def _dj_autoclear_mailbox() -> None:

     from django.core import mail

-    del mail.outbox[:]
+    if hasattr(mail, "outbox"):
+        del mail.outbox[:]

 @pytest.fixture(scope="function")

Tests pass without a problem.

hramezani commented 2 years ago

Based on Django documentation:

During test running, each outgoing email is saved in django.core.mail.outbox. This is a list of all EmailMessage instances that have been sent. The outbox attribute is a special attribute that is created only when the locmem email backend is used. It doesn’t normally exist as part of the django.core.mail module and you can’t import it directly.

Could you please add a test to show in what condition the above mentioned error happens?

mcepl commented 2 years ago

The above error is from running test suite of https://github.com/evansd/whitenoise

Complete build log contains records of all packages used and steps taken.

mcepl commented 2 years ago

@evansd Does this whole ticket make sense to you?

evansd commented 2 years ago

This sounds like an incompatibility between the versions of Django and pytest-django being used and nothing specific to whitenoise.

cfarsbot commented 2 years ago

Im having the Same errors, i created a custom django_db_setup() fixture and give my database definition to the settings.configure(DATABASES=) Im using pytest 7.0.1, pytest-django 4.2.5
I dont even use The Django email stuff, its just a basic graphene application.

wouter-vdb commented 1 year ago

I see the same issue occurring recently. Note that the error occurs in the _dj_autoclear_mailbox test fixture that is marked with autouse=True. So it occurs with any test.

I my case, it occurs in a project in which Django is set up manually because the project only needs to be able to generated html based on Django templates. For testing, the Django instance is set up as follows:

@fixture(autouse=True, scope="session")
def django():
    import django
    from django.conf import settings

    settings.configure(
        TIME_ZONE="Europe/Brussels",
        USE_I18N=True,
        USE_L10N=False,
    )
    django.setup()

Note that I can avoid the issue by adding the following in my root conftest:

@fixture(scope="function", autouse=True)
def _dj_autoclear_mailbox() -> None:
    # Override the `_dj_autoclear_mailbox` test fixture in `pytest_django`.
    pass
phillipuniverse commented 7 months ago

Reproduced with Django 4.2.7 with no settings configuration. For me, I happened to have Django in my venv but had not configured a settings in this particular test slice and ran into the exception.

Thanks @wouter-vd, your workaround did indeed fix it!