##// END OF EJS Templates
Merge pull request #4259 from takluyver/win-test-exclusions...
Thomas Kluyver -
r12765:1bf5b7e4 merge
parent child Browse files
Show More
@@ -1,381 +1,381 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 - An @as_unittest decorator can be used to tag any normal parameter-less
20 20 function as a unittest TestCase. Then, both nose and normal unittest will
21 21 recognize it as such. This will make it easier to migrate away from Nose if
22 22 we ever need/want to while maintaining very lightweight tests.
23 23
24 24 NOTE: This file contains IPython-specific decorators. Using the machinery in
25 25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
26 26 available, OR use equivalent code in IPython.external._decorators, which
27 27 we've copied verbatim from numpy.
28 28
29 29 Authors
30 30 -------
31 31
32 32 - Fernando Perez <Fernando.Perez@berkeley.edu>
33 33 """
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Copyright (C) 2009-2011 The IPython Development Team
37 37 #
38 38 # Distributed under the terms of the BSD License. The full license is in
39 39 # the file COPYING, distributed as part of this software.
40 40 #-----------------------------------------------------------------------------
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Imports
44 44 #-----------------------------------------------------------------------------
45 45
46 46 # Stdlib imports
47 47 import sys
48 48 import os
49 49 import tempfile
50 50 import unittest
51 51
52 52 # Third-party imports
53 53
54 54 # This is Michele Simionato's decorator module, kept verbatim.
55 55 from IPython.external.decorator import decorator
56 56
57 57 # Expose the unittest-driven decorators
58 58 from ipunittest import ipdoctest, ipdocstring
59 59
60 60 # Grab the numpy-specific decorators which we keep in a file that we
61 61 # occasionally update from upstream: decorators.py is a copy of
62 62 # numpy.testing.decorators, we expose all of it here.
63 63 from IPython.external.decorators import *
64 64
65 65 # For onlyif_cmd_exists decorator
66 66 from IPython.utils.process import is_cmd_found
67 67
68 68 #-----------------------------------------------------------------------------
69 69 # Classes and functions
70 70 #-----------------------------------------------------------------------------
71 71
72 72 # Simple example of the basic idea
73 73 def as_unittest(func):
74 74 """Decorator to make a simple function into a normal test via unittest."""
75 75 class Tester(unittest.TestCase):
76 76 def test(self):
77 77 func()
78 78
79 79 Tester.__name__ = func.__name__
80 80
81 81 return Tester
82 82
83 83 # Utility functions
84 84
85 85 def apply_wrapper(wrapper,func):
86 86 """Apply a wrapper to a function for decoration.
87 87
88 88 This mixes Michele Simionato's decorator tool with nose's make_decorator,
89 89 to apply a wrapper in a decorator so that all nose attributes, as well as
90 90 function signature and other properties, survive the decoration cleanly.
91 91 This will ensure that wrapped functions can still be well introspected via
92 92 IPython, for example.
93 93 """
94 94 import nose.tools
95 95
96 96 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
97 97
98 98
99 99 def make_label_dec(label,ds=None):
100 100 """Factory function to create a decorator that applies one or more labels.
101 101
102 102 Parameters
103 103 ----------
104 104 label : string or sequence
105 105 One or more labels that will be applied by the decorator to the functions
106 106 it decorates. Labels are attributes of the decorated function with their
107 107 value set to True.
108 108
109 109 ds : string
110 110 An optional docstring for the resulting decorator. If not given, a
111 111 default docstring is auto-generated.
112 112
113 113 Returns
114 114 -------
115 115 A decorator.
116 116
117 117 Examples
118 118 --------
119 119
120 120 A simple labeling decorator:
121 121
122 122 >>> slow = make_label_dec('slow')
123 123 >>> slow.__doc__
124 124 "Labels a test as 'slow'."
125 125
126 126 And one that uses multiple labels and a custom docstring:
127 127
128 128 >>> rare = make_label_dec(['slow','hard'],
129 129 ... "Mix labels 'slow' and 'hard' for rare tests.")
130 130 >>> rare.__doc__
131 131 "Mix labels 'slow' and 'hard' for rare tests."
132 132
133 133 Now, let's test using this one:
134 134 >>> @rare
135 135 ... def f(): pass
136 136 ...
137 137 >>>
138 138 >>> f.slow
139 139 True
140 140 >>> f.hard
141 141 True
142 142 """
143 143
144 144 if isinstance(label,basestring):
145 145 labels = [label]
146 146 else:
147 147 labels = label
148 148
149 149 # Validate that the given label(s) are OK for use in setattr() by doing a
150 150 # dry run on a dummy function.
151 151 tmp = lambda : None
152 152 for label in labels:
153 153 setattr(tmp,label,True)
154 154
155 155 # This is the actual decorator we'll return
156 156 def decor(f):
157 157 for label in labels:
158 158 setattr(f,label,True)
159 159 return f
160 160
161 161 # Apply the user's docstring, or autogenerate a basic one
162 162 if ds is None:
163 163 ds = "Labels a test as %r." % label
164 164 decor.__doc__ = ds
165 165
166 166 return decor
167 167
168 168
169 169 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
170 170 # preserve function metadata better and allows the skip condition to be a
171 171 # callable.
172 172 def skipif(skip_condition, msg=None):
173 173 ''' Make function raise SkipTest exception if skip_condition is true
174 174
175 175 Parameters
176 176 ----------
177 177 skip_condition : bool or callable.
178 178 Flag to determine whether to skip test. If the condition is a
179 179 callable, it is used at runtime to dynamically make the decision. This
180 180 is useful for tests that may require costly imports, to delay the cost
181 181 until the test suite is actually executed.
182 182 msg : string
183 183 Message to give on raising a SkipTest exception
184 184
185 185 Returns
186 186 -------
187 187 decorator : function
188 188 Decorator, which, when applied to a function, causes SkipTest
189 189 to be raised when the skip_condition was True, and the function
190 190 to be called normally otherwise.
191 191
192 192 Notes
193 193 -----
194 194 You will see from the code that we had to further decorate the
195 195 decorator with the nose.tools.make_decorator function in order to
196 196 transmit function name, and various other metadata.
197 197 '''
198 198
199 199 def skip_decorator(f):
200 200 # Local import to avoid a hard nose dependency and only incur the
201 201 # import time overhead at actual test-time.
202 202 import nose
203 203
204 204 # Allow for both boolean or callable skip conditions.
205 205 if callable(skip_condition):
206 206 skip_val = skip_condition
207 207 else:
208 208 skip_val = lambda : skip_condition
209 209
210 210 def get_msg(func,msg=None):
211 211 """Skip message with information about function being skipped."""
212 212 if msg is None: out = 'Test skipped due to test condition.'
213 213 else: out = msg
214 214 return "Skipping test: %s. %s" % (func.__name__,out)
215 215
216 216 # We need to define *two* skippers because Python doesn't allow both
217 217 # return with value and yield inside the same function.
218 218 def skipper_func(*args, **kwargs):
219 219 """Skipper for normal test functions."""
220 220 if skip_val():
221 221 raise nose.SkipTest(get_msg(f,msg))
222 222 else:
223 223 return f(*args, **kwargs)
224 224
225 225 def skipper_gen(*args, **kwargs):
226 226 """Skipper for test generators."""
227 227 if skip_val():
228 228 raise nose.SkipTest(get_msg(f,msg))
229 229 else:
230 230 for x in f(*args, **kwargs):
231 231 yield x
232 232
233 233 # Choose the right skipper to use when building the actual generator.
234 234 if nose.util.isgenerator(f):
235 235 skipper = skipper_gen
236 236 else:
237 237 skipper = skipper_func
238 238
239 239 return nose.tools.make_decorator(f)(skipper)
240 240
241 241 return skip_decorator
242 242
243 243 # A version with the condition set to true, common case just to attach a message
244 244 # to a skip decorator
245 245 def skip(msg=None):
246 246 """Decorator factory - mark a test function for skipping from test suite.
247 247
248 248 Parameters
249 249 ----------
250 250 msg : string
251 251 Optional message to be added.
252 252
253 253 Returns
254 254 -------
255 255 decorator : function
256 256 Decorator, which, when applied to a function, causes SkipTest
257 257 to be raised, with the optional message added.
258 258 """
259 259
260 260 return skipif(True,msg)
261 261
262 262
263 263 def onlyif(condition, msg):
264 264 """The reverse from skipif, see skipif for details."""
265 265
266 266 if callable(condition):
267 267 skip_condition = lambda : not condition()
268 268 else:
269 269 skip_condition = lambda : not condition
270 270
271 271 return skipif(skip_condition, msg)
272 272
273 273 #-----------------------------------------------------------------------------
274 274 # Utility functions for decorators
275 275 def module_not_available(module):
276 276 """Can module be imported? Returns true if module does NOT import.
277 277
278 278 This is used to make a decorator to skip tests that require module to be
279 279 available, but delay the 'import numpy' to test execution time.
280 280 """
281 281 try:
282 282 mod = __import__(module)
283 283 mod_not_avail = False
284 284 except ImportError:
285 285 mod_not_avail = True
286 286
287 287 return mod_not_avail
288 288
289 289
290 290 def decorated_dummy(dec, name):
291 291 """Return a dummy function decorated with dec, with the given name.
292 292
293 293 Examples
294 294 --------
295 295 import IPython.testing.decorators as dec
296 296 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
297 297 """
298 298 dummy = lambda: None
299 299 dummy.__name__ = name
300 300 return dec(dummy)
301 301
302 302 #-----------------------------------------------------------------------------
303 303 # Decorators for public use
304 304
305 305 # Decorators to skip certain tests on specific platforms.
306 306 skip_win32 = skipif(sys.platform == 'win32',
307 307 "This test does not run under Windows")
308 308 skip_linux = skipif(sys.platform.startswith('linux'),
309 309 "This test does not run under Linux")
310 310 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
311 311
312 312
313 313 # Decorators to skip tests if not on specific platforms.
314 314 skip_if_not_win32 = skipif(sys.platform != 'win32',
315 315 "This test only runs under Windows")
316 316 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
317 317 "This test only runs under Linux")
318 318 skip_if_not_osx = skipif(sys.platform != 'darwin',
319 319 "This test only runs under OSX")
320 320
321 321
322 322 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
323 323 os.environ.get('DISPLAY', '') == '')
324 324 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
325 325
326 326 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
327 327
328 328 # not a decorator itself, returns a dummy function to be used as setup
329 329 def skip_file_no_x11(name):
330 330 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
331 331
332 332 # Other skip decorators
333 333
334 334 # generic skip without module
335 335 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
336 336
337 337 skipif_not_numpy = skip_without('numpy')
338 338
339 339 skipif_not_matplotlib = skip_without('matplotlib')
340 340
341 341 skipif_not_sympy = skip_without('sympy')
342 342
343 343 skip_known_failure = knownfailureif(True,'This test is known to fail')
344 344
345 345 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
346 346 'This test is known to fail on Python 3.')
347 347
348 348 # A null 'decorator', useful to make more readable code that needs to pick
349 349 # between different decorators based on OS or other conditions
350 350 null_deco = lambda f: f
351 351
352 352 # Some tests only run where we can use unicode paths. Note that we can't just
353 353 # check os.path.supports_unicode_filenames, which is always False on Linux.
354 354 try:
355 355 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
356 356 except UnicodeEncodeError:
357 357 unicode_paths = False
358 358 else:
359 359 unicode_paths = True
360 360 f.close()
361 361
362 362 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
363 363 "where we can use unicode in filenames."))
364 364
365 365
366 366 def onlyif_cmds_exist(*commands):
367 367 """
368 368 Decorator to skip test when at least one of `commands` is not found.
369 369 """
370 370 for cmd in commands:
371 371 try:
372 372 if not is_cmd_found(cmd):
373 373 return skip("This test runs only if command '{0}' "
374 374 "is installed".format(cmd))
375 375 except ImportError as e:
376 376 # is_cmd_found uses pywin32 on windows, which might not be available
377 if sys.platform == 'win32' and 'pywin32' in e.message:
377 if sys.platform == 'win32' and 'pywin32' in str(e):
378 378 return skip("This test runs only if pywin32 and command '{0}' "
379 379 "is installed".format(cmd))
380 380 raise e
381 381 return null_deco
@@ -1,436 +1,432 b''
1 1 # -*- coding: utf-8 -*-
2 2 """IPython Test Suite Runner.
3 3
4 4 This module provides a main entry point to a user script to test IPython
5 5 itself from the command line. There are two ways of running this script:
6 6
7 7 1. With the syntax `iptest all`. This runs our entire test suite by
8 8 calling this script (with different arguments) recursively. This
9 9 causes modules and package to be tested in different processes, using nose
10 10 or trial where appropriate.
11 11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 12 the script simply calls nose, but with special command line flags and
13 13 plugins loaded.
14 14
15 15 """
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Copyright (C) 2009-2011 The IPython Development Team
19 19 #
20 20 # Distributed under the terms of the BSD License. The full license is in
21 21 # the file COPYING, distributed as part of this software.
22 22 #-----------------------------------------------------------------------------
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Imports
26 26 #-----------------------------------------------------------------------------
27 27 from __future__ import print_function
28 28
29 29 # Stdlib
30 30 import glob
31 31 import os
32 32 import os.path as path
33 33 import re
34 34 import sys
35 35 import warnings
36 36
37 37 # Now, proceed to import nose itself
38 38 import nose.plugins.builtin
39 39 from nose.plugins.xunit import Xunit
40 40 from nose import SkipTest
41 41 from nose.core import TestProgram
42 42 from nose.plugins import Plugin
43 43
44 44 # Our own imports
45 45 from IPython.utils.importstring import import_item
46 46 from IPython.testing.plugin.ipdoctest import IPythonDoctest
47 47 from IPython.external.decorators import KnownFailure, knownfailureif
48 48
49 49 pjoin = path.join
50 50
51 51
52 52 #-----------------------------------------------------------------------------
53 53 # Globals
54 54 #-----------------------------------------------------------------------------
55 55
56 56
57 57 #-----------------------------------------------------------------------------
58 58 # Warnings control
59 59 #-----------------------------------------------------------------------------
60 60
61 61 # Twisted generates annoying warnings with Python 2.6, as will do other code
62 62 # that imports 'sets' as of today
63 63 warnings.filterwarnings('ignore', 'the sets module is deprecated',
64 64 DeprecationWarning )
65 65
66 66 # This one also comes from Twisted
67 67 warnings.filterwarnings('ignore', 'the sha module is deprecated',
68 68 DeprecationWarning)
69 69
70 70 # Wx on Fedora11 spits these out
71 71 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
72 72 UserWarning)
73 73
74 74 # ------------------------------------------------------------------------------
75 75 # Monkeypatch Xunit to count known failures as skipped.
76 76 # ------------------------------------------------------------------------------
77 77 def monkeypatch_xunit():
78 78 try:
79 79 knownfailureif(True)(lambda: None)()
80 80 except Exception as e:
81 81 KnownFailureTest = type(e)
82 82
83 83 def addError(self, test, err, capt=None):
84 84 if issubclass(err[0], KnownFailureTest):
85 85 err = (SkipTest,) + err[1:]
86 86 return self.orig_addError(test, err, capt)
87 87
88 88 Xunit.orig_addError = Xunit.addError
89 89 Xunit.addError = addError
90 90
91 91 #-----------------------------------------------------------------------------
92 92 # Check which dependencies are installed and greater than minimum version.
93 93 #-----------------------------------------------------------------------------
94 94 def extract_version(mod):
95 95 return mod.__version__
96 96
97 97 def test_for(item, min_version=None, callback=extract_version):
98 98 """Test to see if item is importable, and optionally check against a minimum
99 99 version.
100 100
101 101 If min_version is given, the default behavior is to check against the
102 102 `__version__` attribute of the item, but specifying `callback` allows you to
103 103 extract the value you are interested in. e.g::
104 104
105 105 In [1]: import sys
106 106
107 107 In [2]: from IPython.testing.iptest import test_for
108 108
109 109 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
110 110 Out[3]: True
111 111
112 112 """
113 113 try:
114 114 check = import_item(item)
115 115 except (ImportError, RuntimeError):
116 116 # GTK reports Runtime error if it can't be initialized even if it's
117 117 # importable.
118 118 return False
119 119 else:
120 120 if min_version:
121 121 if callback:
122 122 # extra processing step to get version to compare
123 123 check = callback(check)
124 124
125 125 return check >= min_version
126 126 else:
127 127 return True
128 128
129 129 # Global dict where we can store information on what we have and what we don't
130 130 # have available at test run time
131 131 have = {}
132 132
133 133 have['curses'] = test_for('_curses')
134 134 have['matplotlib'] = test_for('matplotlib')
135 135 have['numpy'] = test_for('numpy')
136 136 have['pexpect'] = test_for('IPython.external.pexpect')
137 137 have['pymongo'] = test_for('pymongo')
138 138 have['pygments'] = test_for('pygments')
139 139 have['qt'] = test_for('IPython.external.qt')
140 140 have['rpy2'] = test_for('rpy2')
141 141 have['sqlite3'] = test_for('sqlite3')
142 142 have['cython'] = test_for('Cython')
143 143 have['oct2py'] = test_for('oct2py')
144 144 have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
145 145 have['jinja2'] = test_for('jinja2')
146 146 have['wx'] = test_for('wx')
147 147 have['wx.aui'] = test_for('wx.aui')
148 148 have['azure'] = test_for('azure')
149 149 have['sphinx'] = test_for('sphinx')
150 150
151 151 min_zmq = (2,1,11)
152 152
153 153 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
154 154
155 155 #-----------------------------------------------------------------------------
156 156 # Test suite definitions
157 157 #-----------------------------------------------------------------------------
158 158
159 159 test_group_names = ['parallel', 'kernel', 'kernel.inprocess', 'config', 'core',
160 160 'extensions', 'lib', 'terminal', 'testing', 'utils',
161 161 'nbformat', 'qt', 'html', 'nbconvert'
162 162 ]
163 163
164 164 class TestSection(object):
165 165 def __init__(self, name, includes):
166 166 self.name = name
167 167 self.includes = includes
168 168 self.excludes = []
169 169 self.dependencies = []
170 170 self.enabled = True
171 171
172 172 def exclude(self, module):
173 173 if not module.startswith('IPython'):
174 174 module = self.includes[0] + "." + module
175 175 self.excludes.append(module.replace('.', os.sep))
176 176
177 177 def requires(self, *packages):
178 178 self.dependencies.extend(packages)
179 179
180 180 @property
181 181 def will_run(self):
182 182 return self.enabled and all(have[p] for p in self.dependencies)
183 183
184 184 # Name -> (include, exclude, dependencies_met)
185 185 test_sections = {n:TestSection(n, ['IPython.%s' % n]) for n in test_group_names}
186 186
187 187 # Exclusions and dependencies
188 188 # ---------------------------
189 189
190 190 # core:
191 191 sec = test_sections['core']
192 192 if not have['sqlite3']:
193 193 sec.exclude('tests.test_history')
194 194 sec.exclude('history')
195 195 if not have['matplotlib']:
196 196 sec.exclude('pylabtools'),
197 197 sec.exclude('tests.test_pylabtools')
198 198
199 199 # lib:
200 200 sec = test_sections['lib']
201 201 if not have['wx']:
202 202 sec.exclude('inputhookwx')
203 203 if not have['pexpect']:
204 204 sec.exclude('irunner')
205 205 sec.exclude('tests.test_irunner')
206 206 if not have['zmq']:
207 207 sec.exclude('kernel')
208 208 # We do this unconditionally, so that the test suite doesn't import
209 209 # gtk, changing the default encoding and masking some unicode bugs.
210 210 sec.exclude('inputhookgtk')
211 211 # Testing inputhook will need a lot of thought, to figure out
212 212 # how to have tests that don't lock up with the gui event
213 213 # loops in the picture
214 214 sec.exclude('inputhook')
215 215
216 216 # testing:
217 217 sec = test_sections['lib']
218 218 # This guy is probably attic material
219 219 sec.exclude('mkdoctests')
220 220 # These have to be skipped on win32 because the use echo, rm, cd, etc.
221 221 # See ticket https://github.com/ipython/ipython/issues/87
222 222 if sys.platform == 'win32':
223 223 sec.exclude('plugin.test_exampleip')
224 224 sec.exclude('plugin.dtexample')
225 225
226 226 # terminal:
227 227 if (not have['pexpect']) or (not have['zmq']):
228 228 test_sections['terminal'].exclude('console')
229 229
230 230 # parallel
231 231 sec = test_sections['parallel']
232 232 sec.requires('zmq')
233 233 if not have['pymongo']:
234 234 sec.exclude('controller.mongodb')
235 235 sec.exclude('tests.test_mongodb')
236 236
237 237 # kernel:
238 238 sec = test_sections['kernel']
239 239 sec.requires('zmq')
240 240 # The in-process kernel tests are done in a separate section
241 241 sec.exclude('inprocess')
242 242 # importing gtk sets the default encoding, which we want to avoid
243 243 sec.exclude('zmq.gui.gtkembed')
244 244 if not have['matplotlib']:
245 245 sec.exclude('zmq.pylab')
246 246
247 247 # kernel.inprocess:
248 248 test_sections['kernel.inprocess'].requires('zmq')
249 249
250 250 # extensions:
251 251 sec = test_sections['extensions']
252 252 if not have['cython']:
253 253 sec.exclude('cythonmagic')
254 254 sec.exclude('tests.test_cythonmagic')
255 255 if not have['oct2py']:
256 256 sec.exclude('octavemagic')
257 257 sec.exclude('tests.test_octavemagic')
258 258 if not have['rpy2'] or not have['numpy']:
259 259 sec.exclude('rmagic')
260 260 sec.exclude('tests.test_rmagic')
261 261 # autoreload does some strange stuff, so move it to its own test section
262 262 sec.exclude('autoreload')
263 263 sec.exclude('tests.test_autoreload')
264 264 test_sections['autoreload'] = TestSection('autoreload',
265 265 ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
266 266 test_group_names.append('autoreload')
267 267
268 268 # qt:
269 269 test_sections['qt'].requires('zmq', 'qt', 'pygments')
270 270
271 271 # html:
272 272 sec = test_sections['html']
273 273 sec.requires('zmq', 'tornado')
274 274 # The notebook 'static' directory contains JS, css and other
275 275 # files for web serving. Occasionally projects may put a .py
276 276 # file in there (MathJax ships a conf.py), so we might as
277 277 # well play it safe and skip the whole thing.
278 278 sec.exclude('static')
279 279 sec.exclude('fabfile')
280 280 if not have['jinja2']:
281 281 sec.exclude('notebookapp')
282 282 if not have['azure']:
283 283 sec.exclude('services.notebooks.azurenbmanager')
284 284
285 285 # config:
286 286 # Config files aren't really importable stand-alone
287 287 test_sections['config'].exclude('profile')
288 288
289 289 # nbconvert:
290 290 sec = test_sections['nbconvert']
291 291 sec.requires('pygments', 'jinja2', 'sphinx')
292 292 # Exclude nbconvert directories containing config files used to test.
293 293 # Executing the config files with iptest would cause an exception.
294 294 sec.exclude('tests.files')
295 295 sec.exclude('exporters.tests.files')
296 296 if not have['tornado']:
297 297 sec.exclude('nbconvert.post_processors.serve')
298 298 sec.exclude('nbconvert.post_processors.tests.test_serve')
299 299
300 300 #-----------------------------------------------------------------------------
301 301 # Functions and classes
302 302 #-----------------------------------------------------------------------------
303 303
304 304 def check_exclusions_exist():
305 305 from IPython.utils.path import get_ipython_package_dir
306 306 from IPython.utils.warn import warn
307 307 parent = os.path.dirname(get_ipython_package_dir())
308 308 for sec in test_sections:
309 309 for pattern in sec.exclusions:
310 310 fullpath = pjoin(parent, pattern)
311 311 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
312 312 warn("Excluding nonexistent file: %r" % pattern)
313 313
314 314
315 315 class ExclusionPlugin(Plugin):
316 316 """A nose plugin to effect our exclusions of files and directories.
317 317 """
318 318 name = 'exclusions'
319 319 score = 3000 # Should come before any other plugins
320 320
321 321 def __init__(self, exclude_patterns=None):
322 322 """
323 323 Parameters
324 324 ----------
325 325
326 326 exclude_patterns : sequence of strings, optional
327 These patterns are compiled as regular expressions, subsequently used
328 to exclude any filename which matches them from inclusion in the test
329 suite (using pattern.search(), NOT pattern.match() ).
327 Filenames containing these patterns (as raw strings, not as regular
328 expressions) are excluded from the tests.
330 329 """
331
332 if exclude_patterns is None:
333 exclude_patterns = []
334 self.exclude_patterns = [re.compile(p) for p in exclude_patterns]
330 self.exclude_patterns = exclude_patterns or []
335 331 super(ExclusionPlugin, self).__init__()
336 332
337 333 def options(self, parser, env=os.environ):
338 334 Plugin.options(self, parser, env)
339 335
340 336 def configure(self, options, config):
341 337 Plugin.configure(self, options, config)
342 338 # Override nose trying to disable plugin.
343 339 self.enabled = True
344 340
345 341 def wantFile(self, filename):
346 342 """Return whether the given filename should be scanned for tests.
347 343 """
348 if any(pat.search(filename) for pat in self.exclude_patterns):
344 if any(pat in filename for pat in self.exclude_patterns):
349 345 return False
350 346 return None
351 347
352 348 def wantDirectory(self, directory):
353 349 """Return whether the given directory should be scanned for tests.
354 350 """
355 if any(pat.search(directory) for pat in self.exclude_patterns):
351 if any(pat in directory for pat in self.exclude_patterns):
356 352 return False
357 353 return None
358 354
359 355
360 356 def run_iptest():
361 357 """Run the IPython test suite using nose.
362 358
363 359 This function is called when this script is **not** called with the form
364 360 `iptest all`. It simply calls nose with appropriate command line flags
365 361 and accepts all of the standard nose arguments.
366 362 """
367 363 # Apply our monkeypatch to Xunit
368 364 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
369 365 monkeypatch_xunit()
370 366
371 367 warnings.filterwarnings('ignore',
372 368 'This will be removed soon. Use IPython.testing.util instead')
373 369
374 370 arg1 = sys.argv[1]
375 371 if arg1 in test_sections:
376 372 section = test_sections[arg1]
377 373 sys.argv[1:2] = section.includes
378 374 elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
379 375 section = test_sections[arg1[8:]]
380 376 sys.argv[1:2] = section.includes
381 377 else:
382 378 section = TestSection(arg1, includes=[arg1])
383 379
384 380
385 381 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
386 382
387 383 '--with-ipdoctest',
388 384 '--ipdoctest-tests','--ipdoctest-extension=txt',
389 385
390 386 # We add --exe because of setuptools' imbecility (it
391 387 # blindly does chmod +x on ALL files). Nose does the
392 388 # right thing and it tries to avoid executables,
393 389 # setuptools unfortunately forces our hand here. This
394 390 # has been discussed on the distutils list and the
395 391 # setuptools devs refuse to fix this problem!
396 392 '--exe',
397 393 ]
398 394 if '-a' not in argv and '-A' not in argv:
399 395 argv = argv + ['-a', '!crash']
400 396
401 397 if nose.__version__ >= '0.11':
402 398 # I don't fully understand why we need this one, but depending on what
403 399 # directory the test suite is run from, if we don't give it, 0 tests
404 400 # get run. Specifically, if the test suite is run from the source dir
405 401 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
406 402 # even if the same call done in this directory works fine). It appears
407 403 # that if the requested package is in the current dir, nose bails early
408 404 # by default. Since it's otherwise harmless, leave it in by default
409 405 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
410 406 argv.append('--traverse-namespace')
411 407
412 408 # use our plugin for doctesting. It will remove the standard doctest plugin
413 409 # if it finds it enabled
414 410 plugins = [ExclusionPlugin(section.excludes), IPythonDoctest(), KnownFailure()]
415 411
416 412 # Use working directory set by parent process (see iptestcontroller)
417 413 if 'IPTEST_WORKING_DIR' in os.environ:
418 414 os.chdir(os.environ['IPTEST_WORKING_DIR'])
419 415
420 416 # We need a global ipython running in this process, but the special
421 417 # in-process group spawns its own IPython kernels, so for *that* group we
422 418 # must avoid also opening the global one (otherwise there's a conflict of
423 419 # singletons). Ultimately the solution to this problem is to refactor our
424 420 # assumptions about what needs to be a singleton and what doesn't (app
425 421 # objects should, individual shells shouldn't). But for now, this
426 422 # workaround allows the test suite for the inprocess module to complete.
427 423 if 'kernel.inprocess' not in section.name:
428 424 from IPython.testing import globalipapp
429 425 globalipapp.start_ipython()
430 426
431 427 # Now nose can run
432 428 TestProgram(argv=argv, addplugins=plugins)
433 429
434 430 if __name__ == '__main__':
435 431 run_iptest()
436 432
General Comments 0
You need to be logged in to leave comments. Login now