1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 | from django.conf import settings
from django.test import TestCase
from django.utils.importlib import import_module
def restore_attrs(wrapper):
"""
Restore all attributes for a wrapped module to their original values
(removing any which weren't originally set).
"""
for key, value in wrapper._attrs_to_restore.iteritems():
setattr(wrapper._wrapped_module, key, value)
for setting in wrapper._delete_settings:
try:
delattr(wrapper._wrapped_module, setting)
except AttributeError:
pass
class ModuleWrapper(object):
"""
A wrapper for modules which will remember attribute changes made so they
can be reverted.
"""
def __init__(self, module):
"""
Initialise some containers to remember overwritten attributes to
restore and newly added attributes to delete.
"""
self.__dict__['_attrs_to_restore'] = {}
self.__dict__['_attrs_to_delete'] = set()
self.__dict__['_wrapped_module'] = module
def __getattr__(self, key):
"""
Retrieve an attribute.
"""
getattr(self._wrapped_module, key)
def __setattr__(self, key, value):
"""
Change an attribute, remembering its original value so it can be
reverted (or deleted if it didn't exist).
"""
attrs_to_restore = self._attrs_to_restore
try:
if key not in attrs_to_restore:
attrs_to_restore[key] = getattr(value, key)
except AttributeError:
self._attrs_to_delete.add(key)
setattr(self._wrapped_module, key, value)
def __delattr__(self, key):
"""
Remove an attribute, remembering its original value so it can be
restored.
Deleting attributes which don't exist will *not* raise an exception.
"""
try:
if key not in self._attrs_to_delete and\
key not in self._attrs_to_restore:
self._attrs_to_restore[key] = getattr(self._wrapped_module,
key)
delattr(self._wrapped_module, key)
except AttributeError:
pass
class ModuleWrapperTestCase(TestCase):
"""
A base test case that can be used to modify attributes in any number of
modules under the knowledge that they will be returned to their original
value (or removed if they didn't previously exist).
To set which modules should be used, set the modules attribute on your test
case subclass to a dictionary for modules which you would like to
temporarily change attributes for.
Each key should be the attribute which the wrapper will be available as and
each value a module (or a dotted string representation of a module).
For example::
class MyTestCase(ModuleWrapperTestCase):
modules = {'mymodule': myproject.mymodule}
#...
"""
modules = None
def _pre_setup(self, *args, **kwargs):
super(ModuleWrapperTestCase, self)._pre_setup(*args, **kwargs)
if self.modules:
for attr, module in self.modules.iteritems():
if isinstance(module, basestring):
module = import_module(module)
setattr(self, attr, ModuleWrapper(module))
def _post_teardown(self, *args, **kwargs):
if self.modules:
for attr in self.modules:
restore_attrs(getattr(self, attr))
super(ModuleWrapperTestCase, self)._post_teardown(*args, **kwargs)
class SettingsTestCase(ModuleWrapperTestCase):
"""
A base test case that can be used to modify settings in
``django.conf.settings`` under the knowledge that they will be returned
to their original value (or removed if they didn't previously exist).
"""
modules = {'settings': settings}
def restore_settings(self):
"""
Restore all settings to their original values (removing any which
weren't originally in settings).
"""
restore_attrs(self.settings)
|
Comments
This is very nice :) Thank you for sharing. Previously i have used modified version of this snippet http://www.djangosnippets.org/snippets/1011/
here is modified code: http://github.com/dominno/django-moderation/blob/master/src/moderation/tests/utils/testsettingsmanager.py
But i see that your version is better because allows to use it on any module that need to be changed globally.
Thank you again for sharing.
Dominik.
#
See also a solution for temporarily modifying settings inside an individual test in snippet 2156.
#