#20636 closed Bug (fixed)
AttributeError: 'Settings' object has no attribute '_original_allowed_hosts'
Reported by: | Aymeric Augustin | Owned by: | nobody |
---|---|---|---|
Component: | Testing framework | Version: | dev |
Severity: | Release blocker | Keywords: | |
Cc: | Simon Charette | Triage Stage: | Unreviewed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When running the tests for http://github.com/aaugustin/django-sesame against stable/1.5.x, I'm hitting this exception after they complete:
Traceback (most recent call last): File "/Users/myk/Documents/dev/django/django/core/management/base.py", line 222, in run_from_argv self.execute(*args, **options.__dict__) File "/Users/myk/Documents/dev/django/django/core/management/commands/test.py", line 72, in execute super(Command, self).execute(*args, **options) File "/Users/myk/Documents/dev/django/django/core/management/base.py", line 255, in execute output = self.handle(*args, **options) File "/Users/myk/Documents/dev/django/django/core/management/commands/test.py", line 89, in handle failures = test_runner.run_tests(test_labels) File "/Users/myk/Documents/dev/django/django/test/simple.py", line 370, in run_tests self.teardown_test_environment() File "/Users/myk/Documents/dev/django/django/test/simple.py", line 341, in teardown_test_environment teardown_test_environment() File "/Users/myk/Documents/dev/django/django/test/utils.py", line 104, in teardown_test_environment settings.ALLOWED_HOSTS = settings._original_allowed_hosts File "/Users/myk/Documents/dev/django/django/conf/__init__.py", line 54, in __getattr__ return getattr(self._wrapped, name) AttributeError: 'Settings' object has no attribute '_original_allowed_hosts'
I'm positive the tests used to work, and this application is only a few dozen lines of code and doesn't do anything really weird with settings.
It uses @override_settings
, but I've tried to reproduce a similar pattern in Django's test suite and I didn't hit the bug:
from django.test.utils import override_settings @override_settings(MIDDLEWARE_CLASSES=('a',)) class Decorated(TestCase): def test_basic_math(self): self.assertEqual(2 + 2, 4) @override_settings(MIDDLEWARE_CLASSES=('b',)) class DoubleDecorated(TestCase): pass
I'm not sure why this happens, but since something that used to work now fails with a cryptic error, we should probably do something about it.
Change History (9)
comment:1 by , 11 years ago
Cc: | added |
---|
comment:2 by , 11 years ago
I did some debug and could confirm _original_allowed_hosts
was set, and later not found, on the same object (same id). Something must have deleted it in the mean time.
comment:3 by , 11 years ago
Here is what seems to happen
a) get_commands()
accesses settings.INSTALLED_APPS
, which triggers Settings.__init__
(instance A)
b) inside Settings.__init__
, import of settings module (sesame.tests.settings
)
c) as settings is inside tests module, this is triggering a new import chain (sesame.tests, django, etc.) ... until django.db accesses settings
d) LazySettings._wrapped
is still empty (remember we are still in Settings.__init__
), hence creation of a new Settings instance (B).
e) still inside the import process, override_settings
is setting its wrapped attribute to Settings B
f) initial Settings.__init__
finishes, so settings._wrapped
is instance A
g) setup_test_environment
set _original_allowed_hosts
on Settings A
h) after tests finishes, override_settings
restore settings._wrapped
to Settings B (value of override_settings.wrapped
, see e)
i) teardown_test_environment
is complaining that Settings B has no _original_allowed_hosts
.
We could point at several problems in this process:
override_settings.wrapped
could be set inenable()
instead of in__init__
(to be tested, but may be #20290)- Django should not access settings at module import time (I already addressed this for django.db in 1.6)
- Do not put your settings modules inside another module which imports much of Django
I let you choose which to address first...
comment:4 by , 11 years ago
@claudep I hit the exact same issue you described but I don't think it's the case with @aaugustin since the _original_allowed_hosts
is set and deleted on the same instance of Settings
.
comment:5 by , 11 years ago
I double-checked in case I had missed something, and I confirm that steps g) and i) operate on the same settings object. However, its _wrapped
attribute has changed!
I think I'm seeing a variant of the scenario described by Claude, and the root cause lies in his first bullet point: override_settings.wrapped
is set in __init__
rather than in enable
, which is indeed #20290.
I see three options:
- backport #20290,
- store
_original_allowed_hosts
somewhere else — likeoriginal_email_backend
which is stored on thedjango.core.mail
module. - catch and drop the AttributeError — after all we're in test teardown, we don't really care.
comment:6 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
I hit a similar issue last week. Some people on IRC suggested that it might be due to an unbalanced
override_setting
but it wasn't the case.Somehow I ended up with two
django.conf.Settings
instance, one that was assigned the_original_allowed_hosts
attribute while the test suite teardown mechanism attempted to delete it from the second one thus raising the same exception.I suggest you place
pdb
a breakpoint indjango.conf.Settings.__init__
and make sure only one instance is created. Hope that helps.