Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #19031 -- Added a warning when using override_settings with 'DA…

…TABASES'
  • Loading branch information...
commit 66f3d57b79eee0381c29ee4c76582d6b182bfad9 1 parent b82a2c4
Joeri Bekker authored May 18, 2013 timgraham committed July 12, 2013
13  django/test/signals.py
... ...
@@ -1,5 +1,6 @@
1 1
 import os
2 2
 import time
  3
+import warnings
3 4
 
4 5
 from django.conf import settings
5 6
 from django.db import connections
@@ -9,11 +10,14 @@
9 10
 
10 11
 template_rendered = Signal(providing_args=["template", "context"])
11 12
 
12  
-setting_changed = Signal(providing_args=["setting", "value"])
  13
+setting_changed = Signal(providing_args=["setting", "value", "enter"])
13 14
 
14 15
 # Most setting_changed receivers are supposed to be added below,
15 16
 # except for cases where the receiver is related to a contrib app.
16 17
 
  18
+# Settings that may not work well when using 'override_settings' (#19031)
  19
+COMPLEX_OVERRIDE_SETTINGS = set(['DATABASES'])
  20
+
17 21
 
18 22
 @receiver(setting_changed)
19 23
 def update_connections_time_zone(**kwargs):
@@ -74,8 +78,15 @@ def language_changed(**kwargs):
74 78
         if kwargs['setting'] == 'LOCALE_PATHS':
75 79
             trans_real._translations = {}
76 80
 
  81
+
77 82
 @receiver(setting_changed)
78 83
 def file_storage_changed(**kwargs):
79 84
     if kwargs['setting'] in ('MEDIA_ROOT', 'DEFAULT_FILE_STORAGE'):
80 85
         from django.core.files.storage import default_storage
81 86
         default_storage._wrapped = empty
  87
+
  88
+
  89
+@receiver(setting_changed)
  90
+def complex_setting_changed(**kwargs):
  91
+    if kwargs['enter'] and kwargs['setting'] in COMPLEX_OVERRIDE_SETTINGS:
  92
+        warnings.warn("Overriding setting %s can lead to unexpected behaviour." % kwargs['setting'])
4  django/test/utils.py
@@ -228,7 +228,7 @@ def enable(self):
228 228
         settings._wrapped = override
229 229
         for key, new_value in self.options.items():
230 230
             setting_changed.send(sender=settings._wrapped.__class__,
231  
-                                 setting=key, value=new_value)
  231
+                                 setting=key, value=new_value, enter=True)
232 232
 
233 233
     def disable(self):
234 234
         settings._wrapped = self.wrapped
@@ -236,7 +236,7 @@ def disable(self):
236 236
         for key in self.options:
237 237
             new_value = getattr(settings, key, None)
238 238
             setting_changed.send(sender=settings._wrapped.__class__,
239  
-                                 setting=key, value=new_value)
  239
+                                 setting=key, value=new_value, enter=False)
240 240
 
241 241
 
242 242
 def compare_xml(want, got):
8  docs/ref/signals.txt
@@ -553,7 +553,8 @@ This signal is sent when the value of a setting is changed through the
553 553
 :func:`django.test.utils.override_settings` decorator/context manager.
554 554
 
555 555
 It's actually sent twice: when the new value is applied ("setup") and when the
556  
-original value is restored ("teardown").
  556
+original value is restored ("teardown"). Use the ``enter`` argument to
  557
+distinguish between the two.
557 558
 
558 559
 Arguments sent with this signal:
559 560
 
@@ -567,6 +568,11 @@ Arguments sent with this signal:
567 568
     The value of the setting after the change. For settings that initially
568 569
     don't exist, in the "teardown" phase, ``value`` is ``None``.
569 570
 
  571
+``enter``
  572
+    .. versionadded:: 1.7
  573
+
  574
+        A boolean; ``True`` if the setting is applied, ``False`` if restored.
  575
+
570 576
 template_rendered
571 577
 -----------------
572 578
 
3  docs/releases/1.7.txt
@@ -38,6 +38,9 @@ Minor features
38 38
   contains extra parameters passed to the ``content-type`` header on a file
39 39
   upload.
40 40
 
  41
+* The ``enter`` argument was added to the
  42
+  :data:`~django.test.signals.setting_changed` signal.
  43
+
41 44
 Backwards incompatible changes in 1.7
42 45
 =====================================
43 46
 
17  docs/topics/testing/overview.txt
@@ -1403,6 +1403,23 @@ The decorator can also be applied to test case classes::
1403 1403
     the original ``LoginTestCase`` is still equally affected by the
1404 1404
     decorator.
1405 1405
 
  1406
+.. warning::
  1407
+
  1408
+    The settings file contains some settings that are only consulted during
  1409
+    initialization of Django internals. If you change them with
  1410
+    ``override_settings``, the setting is changed if you access it via the
  1411
+    ``django.conf.settings`` module, however, Django's internals access it
  1412
+    differently. Effectively, using ``override_settings`` with these settings
  1413
+    is probably not going to do what you expect it to do.
  1414
+
  1415
+    We do not recommend using ``override_settings`` with :setting:`DATABASES`.
  1416
+    Using ``override_settings`` with :setting:`CACHES` is possible, but a bit
  1417
+    tricky if you are using internals that make using of caching, like
  1418
+    :mod:`django.contrib.sessions`. For example, you will have to reinitialize
  1419
+    the session backend in a test that uses cached sessions and overrides
  1420
+    :setting:`CACHES`.
  1421
+
  1422
+
1406 1423
 You can also simulate the absence of a setting by deleting it after settings
1407 1424
 have been overriden, like this::
1408 1425
 
23  tests/settings_tests/tests.py
@@ -203,6 +203,29 @@ def test_allowed_include_roots_string(self):
203 203
             'ALLOWED_INCLUDE_ROOTS', '/var/www/ssi/')
204 204
 
205 205
 
  206
+class TestComplexSettingOverride(TestCase):
  207
+    def setUp(self):
  208
+        self.old_warn_override_settings = signals.COMPLEX_OVERRIDE_SETTINGS.copy()
  209
+        signals.COMPLEX_OVERRIDE_SETTINGS.add('TEST_WARN')
  210
+
  211
+    def tearDown(self):
  212
+        signals.COMPLEX_OVERRIDE_SETTINGS = self.old_warn_override_settings
  213
+        self.assertFalse('TEST_WARN' in signals.COMPLEX_OVERRIDE_SETTINGS)
  214
+
  215
+    def test_complex_override_warning(self):
  216
+        """Regression test for #19031"""
  217
+        with warnings.catch_warnings(record=True) as w:
  218
+            warnings.simplefilter("always")
  219
+
  220
+            override = override_settings(TEST_WARN='override')
  221
+            override.enable()
  222
+            self.assertEqual('override', settings.TEST_WARN)
  223
+            override.disable()
  224
+
  225
+            self.assertEqual(len(w), 1)
  226
+            self.assertEqual('Overriding setting TEST_WARN can lead to unexpected behaviour.', str(w[-1].message))
  227
+
  228
+
206 229
 class TrailingSlashURLTests(TestCase):
207 230
     """
208 231
     Tests for the MEDIA_URL and STATIC_URL settings.

0 notes on commit 66f3d57

Please sign in to comment.
Something went wrong with that request. Please try again.