##// END OF EJS Templates
Update numpy's decorators.py from upstream.
Fernando Perez -
Show More
@@ -1,90 +1,275 b''
1 """Decorators for labeling test objects
1 """
2 Decorators for labeling and modifying behavior of test objects.
2
3
3 Decorators that merely return a modified version of the original
4 Decorators that merely return a modified version of the original
4 function object are straightforward. Decorators that return a new
5 function object are straightforward. Decorators that return a new
5 function object need to use
6 function object need to use
6 nose.tools.make_decorator(original_function)(decorator) in returning
7 ::
7 the decorator, in order to preserve metadata such as function name,
8
8 setup and teardown functions and so on - see nose.tools for more
9 nose.tools.make_decorator(original_function)(decorator)
9 information.
10
11 in returning the decorator, in order to preserve meta-data such as
12 function name, setup and teardown functions and so on - see
13 ``nose.tools`` for more information.
10
14
11 """
15 """
16 import warnings
17 import sys
18
19 from numpy.testing.utils import \
20 WarningManager, WarningMessage
12
21
13 def slow(t):
22 def slow(t):
14 """Labels a test as 'slow'.
23 """
24 Label a test as 'slow'.
15
25
16 The exact definition of a slow test is obviously both subjective and
26 The exact definition of a slow test is obviously both subjective and
17 hardware-dependent, but in general any individual test that requires more
27 hardware-dependent, but in general any individual test that requires more
18 than a second or two should be labeled as slow (the whole suite consits of
28 than a second or two should be labeled as slow (the whole suite consits of
19 thousands of tests, so even a second is significant)."""
29 thousands of tests, so even a second is significant).
30
31 Parameters
32 ----------
33 t : callable
34 The test to label as slow.
35
36 Returns
37 -------
38 t : callable
39 The decorated test `t`.
40
41 Examples
42 --------
43 The `numpy.testing` module includes ``import decorators as dec``.
44 A test can be decorated as slow like this::
45
46 from numpy.testing import *
47
48 @dec.slow
49 def test_big(self):
50 print 'Big, slow test'
51
52 """
20
53
21 t.slow = True
54 t.slow = True
22 return t
55 return t
23
56
24 def setastest(tf=True):
57 def setastest(tf=True):
25 ''' Signals to nose that this function is or is not a test
58 """
59 Signals to nose that this function is or is not a test.
26
60
27 Parameters
61 Parameters
28 ----------
62 ----------
29 tf : bool
63 tf : bool
30 If True specifies this is a test, not a test otherwise
64 If True, specifies that the decorated callable is a test.
65 If False, specifies that the decorated callable is not a test.
66 Default is True.
67
68 Notes
69 -----
70 This decorator can't use the nose namespace, because it can be
71 called from a non-test module. See also ``istest`` and ``nottest`` in
72 ``nose.tools``.
31
73
32 This decorator cannot use the nose namespace, because it can be
74 Examples
33 called from a non-test module. See also istest and nottest in
75 --------
34 nose.tools
76 `setastest` can be used in the following way::
35
77
36 '''
78 from numpy.testing.decorators import setastest
79
80 @setastest(False)
81 def func_with_test_in_name(arg1, arg2):
82 pass
83
84 """
37 def set_test(t):
85 def set_test(t):
38 t.__test__ = tf
86 t.__test__ = tf
39 return t
87 return t
40 return set_test
88 return set_test
41
89
42 def skipif(skip_condition=True, msg=None):
90 def skipif(skip_condition, msg=None):
43 ''' Make function raise SkipTest exception if skip_condition is true
91 """
92 Make function raise SkipTest exception if a given condition is true.
93
94 If the condition is a callable, it is used at runtime to dynamically
95 make the decision. This is useful for tests that may require costly
96 imports, to delay the cost until the test suite is actually executed.
44
97
45 Parameters
98 Parameters
46 ----------
99 ----------
47 skip_condition : bool or callable.
100 skip_condition : bool or callable
48 Flag to determine whether to skip test. If the condition is a
101 Flag to determine whether to skip the decorated test.
49 callable, it is used at runtime to dynamically make the decision. This
102 msg : str, optional
50 is useful for tests that may require costly imports, to delay the cost
103 Message to give on raising a SkipTest exception. Default is None.
51 until the test suite is actually executed.
104
52 msg : string
105 Returns
53 Message to give on raising a SkipTest exception
106 -------
54
107 decorator : function
55 Returns
108 Decorator which, when applied to a function, causes SkipTest
56 -------
109 to be raised when `skip_condition` is True, and the function
57 decorator : function
110 to be called normally otherwise.
58 Decorator, which, when applied to a function, causes SkipTest
59 to be raised when the skip_condition was True, and the function
60 to be called normally otherwise.
61
111
62 Notes
112 Notes
63 -----
113 -----
64 You will see from the code that we had to further decorate the
114 The decorator itself is decorated with the ``nose.tools.make_decorator``
65 decorator with the nose.tools.make_decorator function in order to
115 function in order to transmit function name, and various other metadata.
66 transmit function name, and various other metadata.
116
67 '''
117 """
68 if msg is None:
118
69 msg = 'Test skipped due to test condition'
70 def skip_decorator(f):
119 def skip_decorator(f):
71 # Local import to avoid a hard nose dependency and only incur the
120 # Local import to avoid a hard nose dependency and only incur the
72 # import time overhead at actual test-time.
121 # import time overhead at actual test-time.
73 import nose
122 import nose
74 def skipper(*args, **kwargs):
123
75 if skip_condition:
124 # Allow for both boolean or callable skip conditions.
76 raise nose.SkipTest, msg
125 if callable(skip_condition):
126 skip_val = lambda : skip_condition()
127 else:
128 skip_val = lambda : skip_condition
129
130 def get_msg(func,msg=None):
131 """Skip message with information about function being skipped."""
132 if msg is None:
133 out = 'Test skipped due to test condition'
134 else:
135 out = '\n'+msg
136
137 return "Skipping test: %s%s" % (func.__name__,out)
138
139 # We need to define *two* skippers because Python doesn't allow both
140 # return with value and yield inside the same function.
141 def skipper_func(*args, **kwargs):
142 """Skipper for normal test functions."""
143 if skip_val():
144 raise nose.SkipTest(get_msg(f,msg))
77 else:
145 else:
78 return f(*args, **kwargs)
146 return f(*args, **kwargs)
147
148 def skipper_gen(*args, **kwargs):
149 """Skipper for test generators."""
150 if skip_val():
151 raise nose.SkipTest(get_msg(f,msg))
152 else:
153 for x in f(*args, **kwargs):
154 yield x
155
156 # Choose the right skipper to use when building the actual decorator.
157 if nose.util.isgenerator(f):
158 skipper = skipper_gen
159 else:
160 skipper = skipper_func
161
79 return nose.tools.make_decorator(f)(skipper)
162 return nose.tools.make_decorator(f)(skipper)
163
80 return skip_decorator
164 return skip_decorator
81
165
82 def skipknownfailure(f):
166
83 ''' Decorator to raise SkipTest for test known to fail
167 def knownfailureif(fail_condition, msg=None):
84 '''
168 """
85 # Local import to avoid a hard nose dependency and only incur the
169 Make function raise KnownFailureTest exception if given condition is true.
86 # import time overhead at actual test-time.
170
87 import nose
171 If the condition is a callable, it is used at runtime to dynamically
88 def skipper(*args, **kwargs):
172 make the decision. This is useful for tests that may require costly
89 raise nose.SkipTest, 'This test is known to fail'
173 imports, to delay the cost until the test suite is actually executed.
90 return nose.tools.make_decorator(f)(skipper)
174
175 Parameters
176 ----------
177 fail_condition : bool or callable
178 Flag to determine whether to mark the decorated test as a known
179 failure (if True) or not (if False).
180 msg : str, optional
181 Message to give on raising a KnownFailureTest exception.
182 Default is None.
183
184 Returns
185 -------
186 decorator : function
187 Decorator, which, when applied to a function, causes SkipTest
188 to be raised when `skip_condition` is True, and the function
189 to be called normally otherwise.
190
191 Notes
192 -----
193 The decorator itself is decorated with the ``nose.tools.make_decorator``
194 function in order to transmit function name, and various other metadata.
195
196 """
197 if msg is None:
198 msg = 'Test skipped due to known failure'
199
200 # Allow for both boolean or callable known failure conditions.
201 if callable(fail_condition):
202 fail_val = lambda : fail_condition()
203 else:
204 fail_val = lambda : fail_condition
205
206 def knownfail_decorator(f):
207 # Local import to avoid a hard nose dependency and only incur the
208 # import time overhead at actual test-time.
209 import nose
210 from noseclasses import KnownFailureTest
211 def knownfailer(*args, **kwargs):
212 if fail_val():
213 raise KnownFailureTest, msg
214 else:
215 return f(*args, **kwargs)
216 return nose.tools.make_decorator(f)(knownfailer)
217
218 return knownfail_decorator
219
220 def deprecated(conditional=True):
221 """
222 Filter deprecation warnings while running the test suite.
223
224 This decorator can be used to filter DeprecationWarning's, to avoid
225 printing them during the test suite run, while checking that the test
226 actually raises a DeprecationWarning.
227
228 Parameters
229 ----------
230 conditional : bool or callable, optional
231 Flag to determine whether to mark test as deprecated or not. If the
232 condition is a callable, it is used at runtime to dynamically make the
233 decision. Default is True.
234
235 Returns
236 -------
237 decorator : function
238 The `deprecated` decorator itself.
239
240 Notes
241 -----
242 .. versionadded:: 1.4.0
243
244 """
245 def deprecate_decorator(f):
246 # Local import to avoid a hard nose dependency and only incur the
247 # import time overhead at actual test-time.
248 import nose
249 from noseclasses import KnownFailureTest
250
251 def _deprecated_imp(*args, **kwargs):
252 # Poor man's replacement for the with statement
253 ctx = WarningManager(record=True)
254 l = ctx.__enter__()
255 warnings.simplefilter('always')
256 try:
257 f(*args, **kwargs)
258 if not len(l) > 0:
259 raise AssertionError("No warning raised when calling %s"
260 % f.__name__)
261 if not l[0].category is DeprecationWarning:
262 raise AssertionError("First warning for %s is not a " \
263 "DeprecationWarning( is %s)" % (f.__name__, l[0]))
264 finally:
265 ctx.__exit__()
266
267 if callable(conditional):
268 cond = conditional()
269 else:
270 cond = conditional
271 if cond:
272 return nose.tools.make_decorator(f)(_deprecated_imp)
273 else:
274 return f
275 return deprecate_decorator
General Comments 0
You need to be logged in to leave comments. Login now