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