33
def create_decorator_sample(style, unlock_error=None, meth=None):
34
"""Create a DecoratorSample object, using specific lock operators.
36
:param style: The type of lock decorators to use (fast/pretty/None)
37
:param unlock_error: If specified, an error to raise from unlock.
38
:param meth: a function to be decorated and added as a 'meth_read' and
39
'meth_write' to the object.
40
:return: An instantiated DecoratorSample object.
45
needs_read_lock = decorators.needs_read_lock
46
needs_write_lock = decorators.needs_write_lock
47
elif style == 'pretty':
48
needs_read_lock = decorators._pretty_needs_read_lock
49
needs_write_lock = decorators._pretty_needs_write_lock
51
needs_read_lock = decorators._fast_needs_read_lock
52
needs_write_lock = decorators._fast_needs_write_lock
54
class DecoratorSample(object):
55
"""Sample class that uses decorators.
57
Log when requests go through lock_read()/unlock() or
65
self.actions.append('lock_read')
66
return lock.LogicalLockResult(self.unlock)
69
self.actions.append('lock_write')
70
return lock.LogicalLockResult(self.unlock)
72
@decorators.only_raises(SampleUnlockError)
75
self.actions.append('unlock_fail')
78
self.actions.append('unlock')
82
"""Frob the sample object"""
83
self.actions.append('frob')
87
def bank(self, bar, biz=None):
88
"""Bank the sample, but using bar and biz."""
89
self.actions.append(('bank', bar, biz))
93
def fail_during_read(self):
94
self.actions.append('fail_during_read')
95
raise TypeError('during read')
98
def fail_during_write(self):
99
self.actions.append('fail_during_write')
100
raise TypeError('during write')
103
meth_read = needs_read_lock(meth)
104
meth_write = needs_write_lock(meth)
106
return DecoratorSample()
109
class TestDecoratorActions(TestCase):
111
_decorator_style = None # default
113
def test_read_lock_locks_and_unlocks(self):
114
sam = create_decorator_sample(self._decorator_style)
115
self.assertEqual('newbie', sam.frob())
116
self.assertEqual(['lock_read', 'frob', 'unlock'], sam.actions)
118
def test_write_lock_locks_and_unlocks(self):
119
sam = create_decorator_sample(self._decorator_style)
120
self.assertEqual(('bar', 'bing'), sam.bank('bar', biz='bing'))
121
self.assertEqual(['lock_write', ('bank', 'bar', 'bing'), 'unlock'],
124
def test_read_lock_unlocks_during_failure(self):
125
sam = create_decorator_sample(self._decorator_style)
126
self.assertRaises(TypeError, sam.fail_during_read)
127
self.assertEqual(['lock_read', 'fail_during_read', 'unlock'],
130
def test_write_lock_unlocks_during_failure(self):
131
sam = create_decorator_sample(self._decorator_style)
132
self.assertRaises(TypeError, sam.fail_during_write)
133
self.assertEqual(['lock_write', 'fail_during_write', 'unlock'],
136
def test_read_lock_raises_original_error(self):
137
sam = create_decorator_sample(self._decorator_style,
138
unlock_error=SampleUnlockError())
139
self.assertRaises(TypeError, sam.fail_during_read)
140
self.assertEqual(['lock_read', 'fail_during_read', 'unlock_fail'],
143
def test_write_lock_raises_original_error(self):
144
sam = create_decorator_sample(self._decorator_style,
145
unlock_error=SampleUnlockError())
146
self.assertRaises(TypeError, sam.fail_during_write)
147
self.assertEqual(['lock_write', 'fail_during_write', 'unlock_fail'],
150
def test_read_lock_raises_unlock_error(self):
151
sam = create_decorator_sample(self._decorator_style,
152
unlock_error=SampleUnlockError())
153
self.assertRaises(SampleUnlockError, sam.frob)
154
self.assertEqual(['lock_read', 'frob', 'unlock_fail'], sam.actions)
156
def test_write_lock_raises_unlock_error(self):
157
sam = create_decorator_sample(self._decorator_style,
158
unlock_error=SampleUnlockError())
159
self.assertRaises(SampleUnlockError, sam.bank, 'bar', biz='bing')
160
self.assertEqual(['lock_write', ('bank', 'bar', 'bing'),
161
'unlock_fail'], sam.actions)
163
def test_read_lock_preserves_default_str_kwarg_identity(self):
164
a_constant = 'A str used as a constant'
165
def meth(self, param=a_constant):
167
sam = create_decorator_sample(self._decorator_style, meth=meth)
168
self.assertIs(a_constant, sam.meth_read())
170
def test_write_lock_preserves_default_str_kwarg_identity(self):
171
a_constant = 'A str used as a constant'
172
def meth(self, param=a_constant):
174
sam = create_decorator_sample(self._decorator_style, meth=meth)
175
self.assertIs(a_constant, sam.meth_write())
178
class TestFastDecoratorActions(TestDecoratorActions):
180
_decorator_style = 'fast'
183
class TestPrettyDecoratorActions(TestDecoratorActions):
185
_decorator_style = 'pretty'
188
class TestDecoratorDocs(TestCase):
189
"""Test method decorators"""
191
def test_read_lock_passthrough(self):
192
"""@needs_read_lock exposes underlying name and doc."""
193
sam = create_decorator_sample(None)
194
self.assertEqual('frob', sam.frob.__name__)
195
self.assertDocstring('Frob the sample object', sam.frob)
197
def test_write_lock_passthrough(self):
198
"""@needs_write_lock exposes underlying name and doc."""
199
sam = create_decorator_sample(None)
200
self.assertEqual('bank', sam.bank.__name__)
201
self.assertDocstring('Bank the sample, but using bar and biz.',
204
def test_argument_passthrough(self):
205
"""Test that arguments get passed around properly."""
206
sam = create_decorator_sample(None)
207
sam.bank('1', biz='2')
208
self.assertEqual(['lock_write',
214
class TestPrettyDecorators(TestCase):
215
"""Test that pretty decorators generate nice looking wrappers."""
217
def get_formatted_args(self, func):
218
"""Return a nicely formatted string for the arguments to a function.
220
This generates something like "(foo, bar=None)".
222
return inspect.formatargspec(*inspect.getargspec(func))
224
def test__pretty_needs_read_lock(self):
225
"""Test that _pretty_needs_read_lock generates a nice wrapper."""
227
@decorators._pretty_needs_read_lock
228
def my_function(foo, bar, baz=None, biz=1):
229
"""Just a function that supplies several arguments."""
231
self.assertEqual('my_function', my_function.__name__)
232
self.assertEqual('my_function_read_locked',
233
my_function.__code__.co_name)
234
self.assertEqual('(foo, bar, baz=None, biz=1)',
235
self.get_formatted_args(my_function))
236
self.assertDocstring(
237
'Just a function that supplies several arguments.', my_function)
239
def test__fast_needs_read_lock(self):
240
"""Test the output of _fast_needs_read_lock."""
242
@decorators._fast_needs_read_lock
243
def my_function(foo, bar, baz=None, biz=1):
244
"""Just a function that supplies several arguments."""
246
self.assertEqual('my_function', my_function.__name__)
247
self.assertEqual('read_locked', my_function.__code__.co_name)
248
self.assertEqual('(self, *args, **kwargs)',
249
self.get_formatted_args(my_function))
250
self.assertDocstring(
251
'Just a function that supplies several arguments.', my_function)
253
def test__pretty_needs_write_lock(self):
254
"""Test that _pretty_needs_write_lock generates a nice wrapper."""
256
@decorators._pretty_needs_write_lock
257
def my_function(foo, bar, baz=None, biz=1):
258
"""Just a function that supplies several arguments."""
260
self.assertEqual('my_function', my_function.__name__)
261
self.assertEqual('my_function_write_locked',
262
my_function.__code__.co_name)
263
self.assertEqual('(foo, bar, baz=None, biz=1)',
264
self.get_formatted_args(my_function))
265
self.assertDocstring(
266
'Just a function that supplies several arguments.', my_function)
268
def test__fast_needs_write_lock(self):
269
"""Test the output of _fast_needs_write_lock."""
271
@decorators._fast_needs_write_lock
272
def my_function(foo, bar, baz=None, biz=1):
273
"""Just a function that supplies several arguments."""
275
self.assertEqual('my_function', my_function.__name__)
276
self.assertEqual('write_locked', my_function.__code__.co_name)
277
self.assertEqual('(self, *args, **kwargs)',
278
self.get_formatted_args(my_function))
279
self.assertDocstring(
280
'Just a function that supplies several arguments.', my_function)
282
def test_use_decorators(self):
283
"""Test that you can switch the type of the decorators."""
284
cur_read = decorators.needs_read_lock
285
cur_write = decorators.needs_write_lock
287
decorators.use_fast_decorators()
288
self.assertIs(decorators._fast_needs_read_lock,
289
decorators.needs_read_lock)
290
self.assertIs(decorators._fast_needs_write_lock,
291
decorators.needs_write_lock)
293
decorators.use_pretty_decorators()
294
self.assertIs(decorators._pretty_needs_read_lock,
295
decorators.needs_read_lock)
296
self.assertIs(decorators._pretty_needs_write_lock,
297
decorators.needs_write_lock)
299
# One more switch to make sure it wasn't just good luck that the
300
# functions pointed to the correct version
301
decorators.use_fast_decorators()
302
self.assertIs(decorators._fast_needs_read_lock,
303
decorators.needs_read_lock)
304
self.assertIs(decorators._fast_needs_write_lock,
305
decorators.needs_write_lock)
307
decorators.needs_read_lock = cur_read
308
decorators.needs_write_lock = cur_write
311
33
class TestOnlyRaisesDecorator(TestCase):
313
35
def raise_ZeroDivisionError(self):
316
38
def test_raises_approved_error(self):
317
39
decorator = decorators.only_raises(ZeroDivisionError)
318
40
decorated_meth = decorator(self.raise_ZeroDivisionError)