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