##// END OF EJS Templates
Update decorators and test scripts.
Fernando Perez -
Show More
@@ -1,12 +1,10 b''
1 1 """Decorators for labeling test objects.
2 2
3 Decorators that merely return a modified version of the original
4 function object are straightforward. Decorators that return a new
5 function object need to use
6 nose.tools.make_decorator(original_function)(decorator) in returning
7 the decorator, in order to preserve metadata such as function name,
8 setup and teardown functions and so on - see nose.tools for more
9 information.
3 Decorators that merely return a modified version of the original function
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
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.
10 8
11 9 This module provides a set of useful decorators meant to be ready to use in
12 10 your own tests. See the bottom of the file for the ready-made ones, and if you
@@ -115,46 +113,132 b' def make_label_dec(label,ds=None):'
115 113
116 114 return decor
117 115
118 #-----------------------------------------------------------------------------
119 # Decorators for public use
120
121 skip_doctest = make_label_dec('skip_doctest',
122 """Decorator - mark a function or method for skipping its doctest.
123 116
124 This decorator allows you to mark a function whose docstring you wish to
125 omit from testing, while preserving the docstring for introspection, help,
126 etc.""")
127
128 def skip(msg=''):
129 """Decorator - mark a test function for skipping from test suite.
130
131 This function *is* already a decorator, it is not a factory like
132 make_label_dec or some of those in decorators_numpy.
117 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
118 # preserve function metadata better and allows the skip condition to be a
119 # callable.
120 def skipif(skip_condition, msg=None):
121 ''' Make function raise SkipTest exception if skip_condition is true
122
123 Parameters
124 ---------
125 skip_condition : bool or callable.
126 Flag to determine whether to skip test. If the condition is a
127 callable, it is used at runtime to dynamically make the decision. This
128 is useful for tests that may require costly imports, to delay the cost
129 until the test suite is actually executed.
130 msg : string
131 Message to give on raising a SkipTest exception
132
133 Returns
134 -------
135 decorator : function
136 Decorator, which, when applied to a function, causes SkipTest
137 to be raised when the skip_condition was True, and the function
138 to be called normally otherwise.
139
140 Notes
141 -----
142 You will see from the code that we had to further decorate the
143 decorator with the nose.tools.make_decorator function in order to
144 transmit function name, and various other metadata.
145 '''
146
147 def skip_decorator(f):
148 # Local import to avoid a hard nose dependency and only incur the
149 # import time overhead at actual test-time.
150 import nose
151
152 # Allow for both boolean or callable skip conditions.
153 if callable(skip_condition):
154 skip_val = lambda : skip_condition()
155 else:
156 skip_val = lambda : skip_condition
157
158 def get_msg(func,msg=None):
159 """Skip message with information about function being skipped."""
160 if msg is None: out = 'Test skipped due to test condition.'
161 else: out = msg
162 return "Skipping test: %s. %s" % (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 nose.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 nose.SkipTest(get_msg(f,msg))
177 else:
178 for x in f(*args, **kwargs):
179 yield x
180
181 # Choose the right skipper to use when building the actual generator.
182 if nose.util.isgenerator(f):
183 skipper = skipper_gen
184 else:
185 skipper = skipper_func
186
187 return nose.tools.make_decorator(f)(skipper)
188
189 return skip_decorator
190
191 # A version with the condition set to true, common case just to attacha message
192 # to a skip decorator
193 def skip(msg=None):
194 """Decorator factory - mark a test function for skipping from test suite.
133 195
134 196 :Parameters:
135
136 func : function
137 Test function to be skipped
138
139 197 msg : string
140 198 Optional message to be added.
199
200 :Returns:
201 decorator : function
202 Decorator, which, when applied to a function, causes SkipTest
203 to be raised, with the optional message added.
141 204 """
142 205
143 import nose
206 return skipif(True,msg)
144 207
145 def inner(func):
146 208
147 def wrapper(*a,**k):
148 if msg: out = '\n'+msg
149 else: out = ''
150 raise nose.SkipTest("Skipping test for function: %s%s" %
151 (func.__name__,out))
209 #-----------------------------------------------------------------------------
210 # Utility functions for decorators
211 def numpy_not_available():
212 """Can numpy be imported? Returns true if numpy does NOT import.
152 213
153 return apply_wrapper(wrapper,func)
214 This is used to make a decorator to skip tests that require numpy to be
215 available, but delay the 'import numpy' to test execution time.
216 """
217 try:
218 import numpy
219 np_not_avail = False
220 except ImportError:
221 np_not_avail = True
222
223 return np_not_avail
224
225 #-----------------------------------------------------------------------------
226 # Decorators for public use
227
228 skip_doctest = make_label_dec('skip_doctest',
229 """Decorator - mark a function or method for skipping its doctest.
154 230
155 return inner
231 This decorator allows you to mark a function whose docstring you wish to
232 omit from testing, while preserving the docstring for introspection, help,
233 etc.""")
156 234
157 235 # Decorators to skip certain tests on specific platforms.
158 skip_win32 = skipif(sys.platform=='win32',"This test does not run under Windows")
236 skip_win32 = skipif(sys.platform=='win32',
237 "This test does not run under Windows")
159 238 skip_linux = skipif(sys.platform=='linux2',"This test does not run under Linux")
160 skip_osx = skipif(sys.platform=='darwin',"This test does not run under OSX")
239 skip_osx = skipif(sys.platform=='darwin',"This test does not run under OS X")
240
241
242 skipif_not_numpy = skipif(numpy_not_available,"This test requires numpy")
243
244 skipknownfailure = skip('This test is known to fail')
@@ -30,13 +30,16 b' def main():'
30 30 '--exe',
31 31 ]
32 32
33 has_ip = False
33 # Detect if any tests were required by explicitly calling an IPython
34 # submodule or giving a specific path
35 has_tests = False
34 36 for arg in sys.argv:
35 if 'IPython' in arg:
36 has_ip = True
37 if 'IPython' in arg or arg.endswith('.py') or \
38 (':' in arg and '.py' in arg):
39 has_tests = True
37 40 break
38
39 if not has_ip:
41 # If nothing was specifically requested, test full IPython
42 if not has_tests:
40 43 argv.append('IPython')
41 44
42 45 # construct list of plugins, omitting the existing doctest plugin
@@ -49,5 +52,4 b' def main():'
49 52 #print '*** adding plugin:',plug.name # dbg
50 53 plugins.append(plug)
51 54
52
53 55 TestProgram(argv=argv,plugins=plugins)
@@ -1,10 +1,21 b''
1 """ Tests for various magic functions
1 """Tests for various magic functions.
2 2
3 Needs to be run by nose (to make ipython session available)
3 Needs to be run by nose (to make ipython session available).
4 4 """
5 5
6 # Standard library imports
7 import os
8 import sys
9
10 # Third-party imports
11 import nose.tools as nt
12
13 # From our own code
6 14 from IPython.testing import decorators as dec
7 15
16 #-----------------------------------------------------------------------------
17 # Test functions begin
18
8 19 def test_rehashx():
9 20 # clear up everything
10 21 _ip.IP.alias_table.clear()
@@ -58,14 +69,12 b' def doctest_hist_r():'
58 69
59 70
60 71 def test_shist():
61 # Simple tests of ShadowHist class
72 # Simple tests of ShadowHist class - test generator.
62 73 import os, shutil, tempfile
63 import nose.tools as nt
64 74
65 75 from IPython.Extensions import pickleshare
66 76 from IPython.history import ShadowHist
67 77
68
69 78 tfile = tempfile.mktemp('','tmp-ipython-')
70 79
71 80 db = pickleshare.PickleShareDB(tfile)
@@ -82,11 +91,25 b' def test_shist():'
82 91
83 92 shutil.rmtree(tfile)
84 93
94 @dec.skipif_not_numpy
95 def test_numpy_clear_array_undec():
96 _ip.ex('import numpy as np')
97 _ip.ex('a = np.empty(2)')
98
99 yield nt.assert_true,'a' in _ip.user_ns
100 _ip.magic('clear array')
101 yield nt.assert_false,'a' in _ip.user_ns
102
85 103
86 @dec.skip_numpy_not_avail
87 def doctest_clear_array():
88 """Check that array clearing works.
104 @dec.skip()
105 def test_fail_dec(*a,**k):
106 yield nt.assert_true, False
107
108 @dec.skip('This one shouldn not run')
109 def test_fail_dec2(*a,**k):
110 yield nt.assert_true, False
111
112 @dec.skipknownfailure
113 def test_fail_dec3(*a,**k):
114 yield nt.assert_true, False
89 115
90 >>> 1/0
91 """
92 pass # doctest only
General Comments 0
You need to be logged in to leave comments. Login now