ソースを参照

Fixed #20290 -- Allow override_settings to be nested

Refactored override_settings to store the underlying settings._wrapped
value seen at runtime, not instantiation time.
Oliver Beattie 12 年 前
コミット
552a90b444
4 ファイル変更34 行追加2 行削除
  1. 1 0
      AUTHORS
  2. 2 1
      django/test/utils.py
  3. 5 0
      tests/servers/tests.py
  4. 26 1
      tests/settings_tests/tests.py

+ 1 - 0
AUTHORS

@@ -97,6 +97,7 @@ answer newbie questions, and generally made Django that much better:
     Ned Batchelder <http://www.nedbatchelder.com/>
     batiste@dosimple.ch
     Batman
+    Oliver Beattie <oliver@obeattie.com>
     Brian Beck <http://blog.brianbeck.com/>
     Shannon -jj Behrens <http://jjinux.blogspot.com/>
     Esdras Beleza <linux@esdrasbeleza.com>

+ 2 - 1
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__,

+ 5 - 0
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

+ 26 - 1
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