1"""
2Decorators for labeling and modifying behavior of test objects.
3
4Decorators that merely return a modified version of the original
5function object are straightforward. Decorators that return a new
6function object need to use
7::
8
9 nose.tools.make_decorator(original_function)(decorator)
10
11in returning the decorator, in order to preserve meta-data such as
12function name, setup and teardown functions and so on - see
13``nose.tools`` for more information.
14
15"""
16import collections.abc
17import warnings
18
19from .utils import SkipTest, assert_warns, HAS_REFCOUNT
20
21__all__ = ['slow', 'setastest', 'skipif', 'knownfailureif', 'deprecated',
22 'parametrize', '_needs_refcount',]
23
24
25def slow(t):
26 """
27 .. deprecated:: 1.21
28 This decorator is retained for compatibility with the nose testing framework, which is being phased out.
29 Please use the nose2 or pytest frameworks instead.
30
31 Label a test as 'slow'.
32
33 The exact definition of a slow test is obviously both subjective and
34 hardware-dependent, but in general any individual test that requires more
35 than a second or two should be labeled as slow (the whole suite consists of
36 thousands of tests, so even a second is significant).
37
38 Parameters
39 ----------
40 t : callable
41 The test to label as slow.
42
43 Returns
44 -------
45 t : callable
46 The decorated test `t`.
47
48 Examples
49 --------
50 The `numpy.testing` module includes ``import decorators as dec``.
51 A test can be decorated as slow like this::
52
53 from numpy.testing import *
54
55 @dec.slow
56 def test_big(self):
57 print('Big, slow test')
58
59 """
60 # Numpy 1.21, 2020-12-20
61 warnings.warn('the np.testing.dec decorators are included for nose support, and are '
62 'deprecated since NumPy v1.21. Use the nose2 or pytest frameworks instead.', DeprecationWarning, stacklevel=2)
63
64 t.slow = True
65 return t
66
67def setastest(tf=True):
68 """
69 .. deprecated:: 1.21
70 This decorator is retained for compatibility with the nose testing framework, which is being phased out.
71 Please use the nose2 or pytest frameworks instead.
72
73 Signals to nose that this function is or is not a test.
74
75 Parameters
76 ----------
77 tf : bool
78 If True, specifies that the decorated callable is a test.
79 If False, specifies that the decorated callable is not a test.
80 Default is True.
81
82 Notes
83 -----
84 This decorator can't use the nose namespace, because it can be
85 called from a non-test module. See also ``istest`` and ``nottest`` in
86 ``nose.tools``.
87
88 Examples
89 --------
90 `setastest` can be used in the following way::
91
92 from numpy.testing import dec
93
94 @dec.setastest(False)
95 def func_with_test_in_name(arg1, arg2):
96 pass
97
98 """
99 # Numpy 1.21, 2020-12-20
100 warnings.warn('the np.testing.dec decorators are included for nose support, and are '
101 'deprecated since NumPy v1.21. Use the nose2 or pytest frameworks instead.', DeprecationWarning, stacklevel=2)
102 def set_test(t):
103 t.__test__ = tf
104 return t
105 return set_test
106
107def skipif(skip_condition, msg=None):
108 """
109 .. deprecated:: 1.21
110 This decorator is retained for compatibility with the nose testing framework, which is being phased out.
111 Please use the nose2 or pytest frameworks instead.
112
113 Make function raise SkipTest exception if a given condition is true.
114
115 If the condition is a callable, it is used at runtime to dynamically
116 make the decision. This is useful for tests that may require costly
117 imports, to delay the cost until the test suite is actually executed.
118
119 Parameters
120 ----------
121 skip_condition : bool or callable
122 Flag to determine whether to skip the decorated test.
123 msg : str, optional
124 Message to give on raising a SkipTest exception. Default is None.
125
126 Returns
127 -------
128 decorator : function
129 Decorator which, when applied to a function, causes SkipTest
130 to be raised when `skip_condition` is True, and the function
131 to be called normally otherwise.
132
133 Notes
134 -----
135 The decorator itself is decorated with the ``nose.tools.make_decorator``
136 function in order to transmit function name, and various other metadata.
137
138 """
139
140 def skip_decorator(f):
141 # Local import to avoid a hard nose dependency and only incur the
142 # import time overhead at actual test-time.
143 import nose
144
145 # Numpy 1.21, 2020-12-20
146 warnings.warn('the np.testing.dec decorators are included for nose support, and are '
147 'deprecated since NumPy v1.21. Use the nose2 or pytest frameworks instead.', DeprecationWarning, stacklevel=2)
148
149 # Allow for both boolean or callable skip conditions.
150 if isinstance(skip_condition, collections.abc.Callable):
151 skip_val = lambda: skip_condition()
152 else:
153 skip_val = lambda: skip_condition
154
155 def get_msg(func,msg=None):
156 """Skip message with information about function being skipped."""
157 if msg is None:
158 out = 'Test skipped due to test condition'
159 else:
160 out = msg
161
162 return f'Skipping test: {func.__name__}: {out}'
163
164 # We need to define *two* skippers because Python doesn't allow both
165 # return with value and yield inside the same function.
166 def skipper_func(*args, **kwargs):
167 """Skipper for normal test functions."""
168 if skip_val():
169 raise SkipTest(get_msg(f, msg))
170 else:
171 return f(*args, **kwargs)
172
173 def skipper_gen(*args, **kwargs):
174 """Skipper for test generators."""
175 if skip_val():
176 raise SkipTest(get_msg(f, msg))
177 else:
178 yield from f(*args, **kwargs)
179
180 # Choose the right skipper to use when building the actual decorator.
181 if nose.util.isgenerator(f):
182 skipper = skipper_gen
183 else:
184 skipper = skipper_func
185
186 return nose.tools.make_decorator(f)(skipper)
187
188 return skip_decorator
189
190
191def knownfailureif(fail_condition, msg=None):
192 """
193 .. deprecated:: 1.21
194 This decorator is retained for compatibility with the nose testing framework, which is being phased out.
195 Please use the nose2 or pytest frameworks instead.
196
197 Make function raise KnownFailureException exception if given condition is true.
198
199 If the condition is a callable, it is used at runtime to dynamically
200 make the decision. This is useful for tests that may require costly
201 imports, to delay the cost until the test suite is actually executed.
202
203 Parameters
204 ----------
205 fail_condition : bool or callable
206 Flag to determine whether to mark the decorated test as a known
207 failure (if True) or not (if False).
208 msg : str, optional
209 Message to give on raising a KnownFailureException exception.
210 Default is None.
211
212 Returns
213 -------
214 decorator : function
215 Decorator, which, when applied to a function, causes
216 KnownFailureException to be raised when `fail_condition` is True,
217 and the function to be called normally otherwise.
218
219 Notes
220 -----
221 The decorator itself is decorated with the ``nose.tools.make_decorator``
222 function in order to transmit function name, and various other metadata.
223
224 """
225 # Numpy 1.21, 2020-12-20
226 warnings.warn('the np.testing.dec decorators are included for nose support, and are '
227 'deprecated since NumPy v1.21. Use the nose2 or pytest frameworks instead.', DeprecationWarning, stacklevel=2)
228
229 if msg is None:
230 msg = 'Test skipped due to known failure'
231
232 # Allow for both boolean or callable known failure conditions.
233 if isinstance(fail_condition, collections.abc.Callable):
234 fail_val = lambda: fail_condition()
235 else:
236 fail_val = lambda: fail_condition
237
238 def knownfail_decorator(f):
239 # Local import to avoid a hard nose dependency and only incur the
240 # import time overhead at actual test-time.
241 import nose
242 from .noseclasses import KnownFailureException
243
244 def knownfailer(*args, **kwargs):
245 if fail_val():
246 raise KnownFailureException(msg)
247 else:
248 return f(*args, **kwargs)
249 return nose.tools.make_decorator(f)(knownfailer)
250
251 return knownfail_decorator
252
253def deprecated(conditional=True):
254 """
255 .. deprecated:: 1.21
256 This decorator is retained for compatibility with the nose testing framework, which is being phased out.
257 Please use the nose2 or pytest frameworks instead.
258
259 Filter deprecation warnings while running the test suite.
260
261 This decorator can be used to filter DeprecationWarning's, to avoid
262 printing them during the test suite run, while checking that the test
263 actually raises a DeprecationWarning.
264
265 Parameters
266 ----------
267 conditional : bool or callable, optional
268 Flag to determine whether to mark test as deprecated or not. If the
269 condition is a callable, it is used at runtime to dynamically make the
270 decision. Default is True.
271
272 Returns
273 -------
274 decorator : function
275 The `deprecated` decorator itself.
276
277 Notes
278 -----
279 .. versionadded:: 1.4.0
280
281 """
282 def deprecate_decorator(f):
283 # Local import to avoid a hard nose dependency and only incur the
284 # import time overhead at actual test-time.
285 import nose
286
287 # Numpy 1.21, 2020-12-20
288 warnings.warn('the np.testing.dec decorators are included for nose support, and are '
289 'deprecated since NumPy v1.21. Use the nose2 or pytest frameworks instead.', DeprecationWarning, stacklevel=2)
290
291 def _deprecated_imp(*args, **kwargs):
292 # Poor man's replacement for the with statement
293 with assert_warns(DeprecationWarning):
294 f(*args, **kwargs)
295
296 if isinstance(conditional, collections.abc.Callable):
297 cond = conditional()
298 else:
299 cond = conditional
300 if cond:
301 return nose.tools.make_decorator(f)(_deprecated_imp)
302 else:
303 return f
304 return deprecate_decorator
305
306
307def parametrize(vars, input):
308 """
309 .. deprecated:: 1.21
310 This decorator is retained for compatibility with the nose testing framework, which is being phased out.
311 Please use the nose2 or pytest frameworks instead.
312
313 Pytest compatibility class. This implements the simplest level of
314 pytest.mark.parametrize for use in nose as an aid in making the transition
315 to pytest. It achieves that by adding a dummy var parameter and ignoring
316 the doc_func parameter of the base class. It does not support variable
317 substitution by name, nor does it support nesting or classes. See the
318 pytest documentation for usage.
319
320 .. versionadded:: 1.14.0
321
322 """
323 from .parameterized import parameterized
324
325 # Numpy 1.21, 2020-12-20
326 warnings.warn('the np.testing.dec decorators are included for nose support, and are '
327 'deprecated since NumPy v1.21. Use the nose2 or pytest frameworks instead.', DeprecationWarning, stacklevel=2)
328
329 return parameterized(input)
330
331_needs_refcount = skipif(not HAS_REFCOUNT, "python has no sys.getrefcount")