From 552a90b44456f24de228a6c7cd916c040787cf22 Mon Sep 17 00:00:00 2001 From: Oliver Beattie Date: Fri, 19 Apr 2013 10:44:47 +0100 Subject: [PATCH] Fixed #20290 -- Allow override_settings to be nested Refactored override_settings to store the underlying settings._wrapped value seen at runtime, not instantiation time. --- AUTHORS | 1 + django/test/utils.py | 3 ++- tests/servers/tests.py | 5 +++++ tests/settings_tests/tests.py | 27 ++++++++++++++++++++++++++- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 9413a518843..3eb0a68be9f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -97,6 +97,7 @@ answer newbie questions, and generally made Django that much better: Ned Batchelder batiste@dosimple.ch Batman + Oliver Beattie Brian Beck Shannon -jj Behrens Esdras Beleza diff --git a/django/test/utils.py b/django/test/utils.py index be586c75a6d..fc4558875e9 100644 --- a/django/test/utils.py +++ b/django/test/utils.py @@ -207,7 +207,6 @@ class override_settings(object): """ def __init__(self, **kwargs): self.options = kwargs - self.wrapped = settings._wrapped def __enter__(self): self.enable() @@ -246,6 +245,7 @@ class override_settings(object): override = UserSettingsHolder(settings._wrapped) for key, new_value in self.options.items(): setattr(override, key, new_value) + self.wrapped = settings._wrapped settings._wrapped = override for key, new_value in self.options.items(): setting_changed.send(sender=settings._wrapped.__class__, @@ -253,6 +253,7 @@ class override_settings(object): def disable(self): settings._wrapped = self.wrapped + del self.wrapped for key in self.options: new_value = getattr(settings, key, None) setting_changed.send(sender=settings._wrapped.__class__, diff --git a/tests/servers/tests.py b/tests/servers/tests.py index 3377793d684..be74afe820d 100644 --- a/tests/servers/tests.py +++ b/tests/servers/tests.py @@ -95,6 +95,11 @@ class LiveServerAddress(LiveServerBase): else: del os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] + @classmethod + def tearDownClass(cls): + # skip it, as setUpClass doesn't call its parent either + pass + @classmethod def raises_exception(cls, address, exception): os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = address diff --git a/tests/settings_tests/tests.py b/tests/settings_tests/tests.py index f8d66bb2b7c..625c4f31df9 100644 --- a/tests/settings_tests/tests.py +++ b/tests/settings_tests/tests.py @@ -9,17 +9,19 @@ from django.test.utils import override_settings from django.utils import unittest, six -@override_settings(TEST='override') +@override_settings(TEST='override', TEST_OUTER='outer') class FullyDecoratedTranTestCase(TransactionTestCase): available_apps = [] def test_override(self): self.assertEqual(settings.TEST, 'override') + self.assertEqual(settings.TEST_OUTER, 'outer') @override_settings(TEST='override2') def test_method_override(self): self.assertEqual(settings.TEST, 'override2') + self.assertEqual(settings.TEST_OUTER, 'outer') def test_decorated_testcase_name(self): self.assertEqual(FullyDecoratedTranTestCase.__name__, 'FullyDecoratedTranTestCase') @@ -168,6 +170,29 @@ class SettingsTests(TestCase): self.assertRaises(AttributeError, getattr, settings, 'USE_I18N') self.assertEqual(settings.USE_I18N, previous_i18n) + def test_override_settings_nested(self): + """ + Test that override_settings uses the actual _wrapped attribute at + runtime, not when it was instantiated. + """ + + self.assertRaises(AttributeError, getattr, settings, 'TEST') + self.assertRaises(AttributeError, getattr, settings, 'TEST2') + + inner = override_settings(TEST2='override') + with override_settings(TEST='override'): + self.assertEqual('override', settings.TEST) + with inner: + self.assertEqual('override', settings.TEST) + self.assertEqual('override', settings.TEST2) + # inner's __exit__ should have restored the settings of the outer + # context manager, not those when the class was instantiated + self.assertEqual('override', settings.TEST) + self.assertRaises(AttributeError, getattr, settings, 'TEST2') + + self.assertRaises(AttributeError, getattr, settings, 'TEST') + self.assertRaises(AttributeError, getattr, settings, 'TEST2') + def test_allowed_include_roots_string(self): """ ALLOWED_INCLUDE_ROOTS is not allowed to be incorrectly set to a string