1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
''' Nose test running
Implements test and bench functions for modules.
'''
import os
import sys
import re
import warnings
def import_nose():
""" Import nose only when needed.
"""
fine_nose = True
try:
import nose
from nose.tools import raises
except ImportError:
fine_nose = False
else:
nose_version = nose.__versioninfo__
if nose_version[0] < 1 and nose_version[1] < 10:
fine_nose = False
if not fine_nose:
raise ImportError('Need nose >=0.10 for tests - see '
'http://somethingaboutorange.com/mrl/projects/nose')
return nose
def run_module_suite(file_to_run = None):
if file_to_run is None:
f = sys._getframe(1)
file_to_run = f.f_locals.get('__file__', None)
assert file_to_run is not None
import_nose().run(argv=['',file_to_run])
class NoseTester(object):
""" Nose test runner.
Usage: NoseTester(<package>).test()
<package> is package path or module Default for package is None. A
value of None finds calling module path.
Typical call is from module __init__, and corresponds to this:
>>> test = NoseTester().test
This class is made available as numpy.testing.Tester:
>>> from scipy.testing import Tester
>>> test = Tester().test
"""
def __init__(self, package=None):
''' Test class init
Parameters
----------
package : string or module
If string, gives full path to package
If None, extract calling module path
Default is None
'''
if package is None:
f = sys._getframe(1)
package = f.f_locals.get('__file__', None)
assert package is not None
package = os.path.dirname(package)
elif isinstance(package, type(os)):
package = os.path.dirname(package.__file__)
self.package_path = package
# find the package name under test; this name is used to limit coverage
# reporting (if enabled)
pkg_temp = package
pkg_name = []
while 'site-packages' in pkg_temp:
pkg_temp, p2 = os.path.split(pkg_temp)
if p2 == 'site-packages':
break
pkg_name.append(p2)
# if package name determination failed, just default to numpy/scipy
if not pkg_name:
if 'scipy' in self.package_path:
self.package_name = 'scipy'
else:
self.package_name = 'numpy'
else:
pkg_name.reverse()
self.package_name = '.'.join(pkg_name)
def _add_doc(testtype):
''' Decorator to add docstring to functions using test labels
Parameters
----------
testtype : string
Type of test for function docstring
'''
def docit(func):
test_header = \
'''Parameters
----------
label : {'fast', 'full', '', attribute identifer}
Identifies %(testtype)s to run. This can be a string to pass to
the nosetests executable with the'-A' option, or one of
several special values.
Special values are:
'fast' - the default - which corresponds to
nosetests -A option of
'not slow'.
'full' - fast (as above) and slow %(testtype)s as in
no -A option to nosetests - same as ''
None or '' - run all %(testtype)ss
attribute_identifier - string passed directly to
nosetests as '-A'
verbose : integer
verbosity value for test outputs, 1-10
extra_argv : list
List with any extra args to pass to nosetests''' \
% {'testtype': testtype}
func.__doc__ = func.__doc__ % {
'test_header': test_header}
return func
return docit
@_add_doc('(testtype)')
def _test_argv(self, label, verbose, extra_argv):
''' Generate argv for nosetest command
%(test_header)s
'''
argv = [__file__, self.package_path, '-s']
if label and label != 'full':
if not isinstance(label, basestring):
raise TypeError, 'Selection label should be a string'
if label == 'fast':
label = 'not slow'
argv += ['-A', label]
argv += ['--verbosity', str(verbose)]
if extra_argv:
argv += extra_argv
return argv
@_add_doc('test')
def test(self, label='fast', verbose=1, extra_argv=None, doctests=False,
coverage=False, **kwargs):
''' Run tests for module using nose
%(test_header)s
doctests : boolean
If True, run doctests in module, default False
coverage : boolean
If True, report coverage of NumPy code, default False
(Requires the coverage module:
http://nedbatchelder.com/code/modules/coverage.html)
'''
old_args = set(['level', 'verbosity', 'all', 'sys_argv', 'testcase_pattern'])
unexpected_args = set(kwargs.keys()) - old_args
if len(unexpected_args) > 0:
ua = ', '.join(unexpected_args)
raise TypeError("test() got unexpected arguments: %s" % ua)
# issue a deprecation warning if any of the pre-1.2 arguments to
# test are given
if old_args.intersection(kwargs.keys()):
warnings.warn("This method's signature will change in the next release; the level, verbosity, all, sys_argv, and testcase_pattern keyword arguments will be removed. Please update your code.",
DeprecationWarning, stacklevel=2)
# Use old arguments if given (where it makes sense)
# For the moment, level and sys_argv are ignored
# replace verbose with verbosity
if kwargs.get('verbosity') is not None:
verbose = kwargs.get('verbosity')
# cap verbosity at 3 because nose becomes *very* verbose beyond that
verbose = min(verbose, 3)
# if all evaluates as True, omit attribute filter and run doctests
if kwargs.get('all'):
label = ''
doctests = True
argv = self._test_argv(label, verbose, extra_argv)
if doctests:
argv+=['--with-doctest','--doctest-tests']
if coverage:
argv+=['--cover-package=%s' % self.package_name, '--with-coverage',
'--cover-tests', '--cover-inclusive', '--cover-erase']
# bypass these samples under distutils
argv += ['--exclude','f2py_ext']
argv += ['--exclude','f2py_f90_ext']
argv += ['--exclude','gen_ext']
argv += ['--exclude','pyrex_ext']
argv += ['--exclude','swig_ext']
nose = import_nose()
# Because nose currently discards the test result object, but we need to
# return it to the user, override TestProgram.runTests to retain the result
class NumpyTestProgram(nose.core.TestProgram):
def runTests(self):
"""Run Tests. Returns true on success, false on failure, and sets
self.success to the same value.
"""
if self.testRunner is None:
self.testRunner = nose.core.TextTestRunner(stream=self.config.stream,
verbosity=self.config.verbosity,
config=self.config)
plug_runner = self.config.plugins.prepareTestRunner(self.testRunner)
if plug_runner is not None:
self.testRunner = plug_runner
self.result = self.testRunner.run(self.test)
self.success = self.result.wasSuccessful()
return self.success
t = NumpyTestProgram(argv=argv, exit=False)
return t.result
@_add_doc('benchmark')
def bench(self, label='fast', verbose=1, extra_argv=None):
''' Run benchmarks for module using nose
%(test_header)s'''
nose = import_nose()
argv = self._test_argv(label, verbose, extra_argv)
argv += ['--match', r'(?:^|[\\b_\\.%s-])[Bb]ench' % os.sep]
return nose.run(argv=argv)
|