##// END OF EJS Templates
remove unnecessary yield
Paul Ivanov -
Show More
@@ -1,326 +1,326 b''
1 1 """Decorators for labeling test objects.
2 2
3 3 Decorators that merely return a modified version of the original function
4 4 object are straightforward. Decorators that return a new function object need
5 5 to use nose.tools.make_decorator(original_function)(decorator) in returning the
6 6 decorator, in order to preserve metadata such as function name, setup and
7 7 teardown functions and so on - see nose.tools for more information.
8 8
9 9 This module provides a set of useful decorators meant to be ready to use in
10 10 your own tests. See the bottom of the file for the ready-made ones, and if you
11 11 find yourself writing a new one that may be of generic use, add it here.
12 12
13 13 Included decorators:
14 14
15 15
16 16 Lightweight testing that remains unittest-compatible.
17 17
18 18 - @parametric, for parametric test support that is vastly easier to use than
19 19 nose's for debugging. With ours, if a test fails, the stack under inspection
20 20 is that of the test and not that of the test framework.
21 21
22 22 - An @as_unittest decorator can be used to tag any normal parameter-less
23 23 function as a unittest TestCase. Then, both nose and normal unittest will
24 24 recognize it as such. This will make it easier to migrate away from Nose if
25 25 we ever need/want to while maintaining very lightweight tests.
26 26
27 27 NOTE: This file contains IPython-specific decorators and imports the
28 28 numpy.testing.decorators file, which we've copied verbatim. Any of our own
29 29 code will be added at the bottom if we end up extending this.
30 30
31 31 Authors
32 32 -------
33 33
34 34 - Fernando Perez <Fernando.Perez@berkeley.edu>
35 35 """
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Copyright (C) 2009-2010 The IPython Development Team
39 39 #
40 40 # Distributed under the terms of the BSD License. The full license is in
41 41 # the file COPYING, distributed as part of this software.
42 42 #-----------------------------------------------------------------------------
43 43
44 44 #-----------------------------------------------------------------------------
45 45 # Imports
46 46 #-----------------------------------------------------------------------------
47 47
48 48 # Stdlib imports
49 49 import inspect
50 50 import sys
51 51 import unittest
52 52
53 53 # Third-party imports
54 54
55 55 # This is Michele Simionato's decorator module, kept verbatim.
56 56 from IPython.external.decorator import decorator, update_wrapper
57 57
58 58 # We already have python3-compliant code for parametric tests
59 59 if sys.version[0]=='2':
60 60 from _paramtestpy2 import parametric, ParametricTestCase
61 61 else:
62 62 from _paramtestpy3 import parametric, ParametricTestCase
63 63
64 64 # Expose the unittest-driven decorators
65 65 from ipunittest import ipdoctest, ipdocstring
66 66
67 67 # Grab the numpy-specific decorators which we keep in a file that we
68 68 # occasionally update from upstream: decorators.py is a copy of
69 69 # numpy.testing.decorators, we expose all of it here.
70 70 from IPython.external.decorators import *
71 71
72 72 #-----------------------------------------------------------------------------
73 73 # Classes and functions
74 74 #-----------------------------------------------------------------------------
75 75
76 76 # Simple example of the basic idea
77 77 def as_unittest(func):
78 78 """Decorator to make a simple function into a normal test via unittest."""
79 79 class Tester(unittest.TestCase):
80 80 def test(self):
81 81 func()
82 82
83 83 Tester.__name__ = func.__name__
84 84
85 85 return Tester
86 86
87 87 # Utility functions
88 88
89 89 def apply_wrapper(wrapper,func):
90 90 """Apply a wrapper to a function for decoration.
91 91
92 92 This mixes Michele Simionato's decorator tool with nose's make_decorator,
93 93 to apply a wrapper in a decorator so that all nose attributes, as well as
94 94 function signature and other properties, survive the decoration cleanly.
95 95 This will ensure that wrapped functions can still be well introspected via
96 96 IPython, for example.
97 97 """
98 98 import nose.tools
99 99
100 100 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
101 101
102 102
103 103 def make_label_dec(label,ds=None):
104 104 """Factory function to create a decorator that applies one or more labels.
105 105
106 106 Parameters
107 107 ----------
108 108 label : string or sequence
109 109 One or more labels that will be applied by the decorator to the functions
110 110 it decorates. Labels are attributes of the decorated function with their
111 111 value set to True.
112 112
113 113 ds : string
114 114 An optional docstring for the resulting decorator. If not given, a
115 115 default docstring is auto-generated.
116 116
117 117 Returns
118 118 -------
119 119 A decorator.
120 120
121 121 Examples
122 122 --------
123 123
124 124 A simple labeling decorator:
125 125 >>> slow = make_label_dec('slow')
126 126 >>> print slow.__doc__
127 127 Labels a test as 'slow'.
128 128
129 129 And one that uses multiple labels and a custom docstring:
130 130 >>> rare = make_label_dec(['slow','hard'],
131 131 ... "Mix labels 'slow' and 'hard' for rare tests.")
132 132 >>> print rare.__doc__
133 133 Mix labels 'slow' and 'hard' for rare tests.
134 134
135 135 Now, let's test using this one:
136 136 >>> @rare
137 137 ... def f(): pass
138 138 ...
139 139 >>>
140 140 >>> f.slow
141 141 True
142 142 >>> f.hard
143 143 True
144 144 """
145 145
146 146 if isinstance(label,basestring):
147 147 labels = [label]
148 148 else:
149 149 labels = label
150 150
151 151 # Validate that the given label(s) are OK for use in setattr() by doing a
152 152 # dry run on a dummy function.
153 153 tmp = lambda : None
154 154 for label in labels:
155 155 setattr(tmp,label,True)
156 156
157 157 # This is the actual decorator we'll return
158 158 def decor(f):
159 159 for label in labels:
160 160 setattr(f,label,True)
161 161 return f
162 162
163 163 # Apply the user's docstring, or autogenerate a basic one
164 164 if ds is None:
165 165 ds = "Labels a test as %r." % label
166 166 decor.__doc__ = ds
167 167
168 168 return decor
169 169
170 170
171 171 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
172 172 # preserve function metadata better and allows the skip condition to be a
173 173 # callable.
174 174 def skipif(skip_condition, msg=None):
175 175 ''' Make function raise SkipTest exception if skip_condition is true
176 176
177 177 Parameters
178 178 ----------
179 179 skip_condition : bool or callable.
180 180 Flag to determine whether to skip test. If the condition is a
181 181 callable, it is used at runtime to dynamically make the decision. This
182 182 is useful for tests that may require costly imports, to delay the cost
183 183 until the test suite is actually executed.
184 184 msg : string
185 185 Message to give on raising a SkipTest exception
186 186
187 187 Returns
188 188 -------
189 189 decorator : function
190 190 Decorator, which, when applied to a function, causes SkipTest
191 191 to be raised when the skip_condition was True, and the function
192 192 to be called normally otherwise.
193 193
194 194 Notes
195 195 -----
196 196 You will see from the code that we had to further decorate the
197 197 decorator with the nose.tools.make_decorator function in order to
198 198 transmit function name, and various other metadata.
199 199 '''
200 200
201 201 def skip_decorator(f):
202 202 # Local import to avoid a hard nose dependency and only incur the
203 203 # import time overhead at actual test-time.
204 204 import nose
205 205
206 206 # Allow for both boolean or callable skip conditions.
207 207 if callable(skip_condition):
208 208 skip_val = skip_condition
209 209 else:
210 210 skip_val = lambda : skip_condition
211 211
212 212 def get_msg(func,msg=None):
213 213 """Skip message with information about function being skipped."""
214 214 if msg is None: out = 'Test skipped due to test condition.'
215 215 else: out = msg
216 216 return "Skipping test: %s. %s" % (func.__name__,out)
217 217
218 218 # We need to define *two* skippers because Python doesn't allow both
219 219 # return with value and yield inside the same function.
220 220 def skipper_func(*args, **kwargs):
221 221 """Skipper for normal test functions."""
222 222 if skip_val():
223 223 raise nose.SkipTest(get_msg(f,msg))
224 224 else:
225 225 return f(*args, **kwargs)
226 226
227 227 def skipper_gen(*args, **kwargs):
228 228 """Skipper for test generators."""
229 229 if skip_val():
230 230 raise nose.SkipTest(get_msg(f,msg))
231 231 else:
232 232 for x in f(*args, **kwargs):
233 233 yield x
234 234
235 235 # Choose the right skipper to use when building the actual generator.
236 236 if nose.util.isgenerator(f):
237 237 skipper = skipper_gen
238 238 else:
239 239 skipper = skipper_func
240 240
241 241 return nose.tools.make_decorator(f)(skipper)
242 242
243 243 return skip_decorator
244 244
245 245 # A version with the condition set to true, common case just to attacha message
246 246 # to a skip decorator
247 247 def skip(msg=None):
248 248 """Decorator factory - mark a test function for skipping from test suite.
249 249
250 250 Parameters
251 251 ----------
252 252 msg : string
253 253 Optional message to be added.
254 254
255 255 Returns
256 256 -------
257 257 decorator : function
258 258 Decorator, which, when applied to a function, causes SkipTest
259 259 to be raised, with the optional message added.
260 260 """
261 261
262 262 return skipif(True,msg)
263 263
264 264
265 265 def onlyif(condition, msg):
266 266 """The reverse from skipif, see skipif for details."""
267 267
268 268 if callable(condition):
269 269 skip_condition = lambda : not condition()
270 270 else:
271 271 skip_condition = lambda : not condition
272 272
273 273 return skipif(skip_condition, msg)
274 274
275 275 #-----------------------------------------------------------------------------
276 276 # Utility functions for decorators
277 277 def module_not_available(module):
278 278 """Can module be imported? Returns true if module does NOT import.
279 279
280 280 This is used to make a decorator to skip tests that require module to be
281 281 available, but delay the 'import numpy' to test execution time.
282 282 """
283 283 try:
284 284 mod = __import__(module)
285 285 mod_not_avail = False
286 286 except ImportError:
287 287 mod_not_avail = True
288 288
289 yield mod_not_avail
289 return mod_not_avail
290 290
291 291 #-----------------------------------------------------------------------------
292 292 # Decorators for public use
293 293
294 294 skip_doctest = make_label_dec('skip_doctest',
295 295 """Decorator - mark a function or method for skipping its doctest.
296 296
297 297 This decorator allows you to mark a function whose docstring you wish to
298 298 omit from testing, while preserving the docstring for introspection, help,
299 299 etc.""")
300 300
301 301 # Decorators to skip certain tests on specific platforms.
302 302 skip_win32 = skipif(sys.platform == 'win32',
303 303 "This test does not run under Windows")
304 304 skip_linux = skipif(sys.platform == 'linux2',
305 305 "This test does not run under Linux")
306 306 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
307 307
308 308
309 309 # Decorators to skip tests if not on specific platforms.
310 310 skip_if_not_win32 = skipif(sys.platform != 'win32',
311 311 "This test only runs under Windows")
312 312 skip_if_not_linux = skipif(sys.platform != 'linux2',
313 313 "This test only runs under Linux")
314 314 skip_if_not_osx = skipif(sys.platform != 'darwin',
315 315 "This test only runs under OSX")
316 316
317 317 # Other skip decorators
318 318 skipif_not_numpy = skipif(module_not_available('numpy'),"This test requires numpy")
319 319
320 320 skipif_not_sympy = skipif(module_not_available('sympy'),"This test requires sympy")
321 321
322 322 skip_known_failure = knownfailureif(True,'This test is known to fail')
323 323
324 324 # A null 'decorator', useful to make more readable code that needs to pick
325 325 # between different decorators based on OS or other conditions
326 326 null_deco = lambda f: f
General Comments 0
You need to be logged in to leave comments. Login now