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