##// END OF EJS Templates
Remove warning filtering in iptest.
Matthias Bussonnier -
Show More
@@ -1,441 +1,432 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Suite Runner.
2 """IPython Test Suite Runner.
3
3
4 This module provides a main entry point to a user script to test IPython
4 This module provides a main entry point to a user script to test IPython
5 itself from the command line. There are two ways of running this script:
5 itself from the command line. There are two ways of running this script:
6
6
7 1. With the syntax `iptest all`. This runs our entire test suite by
7 1. With the syntax `iptest all`. This runs our entire test suite by
8 calling this script (with different arguments) recursively. This
8 calling this script (with different arguments) recursively. This
9 causes modules and package to be tested in different processes, using nose
9 causes modules and package to be tested in different processes, using nose
10 or trial where appropriate.
10 or trial where appropriate.
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 the script simply calls nose, but with special command line flags and
12 the script simply calls nose, but with special command line flags and
13 plugins loaded.
13 plugins loaded.
14
14
15 """
15 """
16
16
17 # Copyright (c) IPython Development Team.
17 # Copyright (c) IPython Development Team.
18 # Distributed under the terms of the Modified BSD License.
18 # Distributed under the terms of the Modified BSD License.
19
19
20 from __future__ import print_function
20 from __future__ import print_function
21
21
22 import glob
22 import glob
23 from io import BytesIO
23 from io import BytesIO
24 import os
24 import os
25 import os.path as path
25 import os.path as path
26 import sys
26 import sys
27 from threading import Thread, Lock, Event
27 from threading import Thread, Lock, Event
28 import warnings
28 import warnings
29
29
30 import nose.plugins.builtin
30 import nose.plugins.builtin
31 from nose.plugins.xunit import Xunit
31 from nose.plugins.xunit import Xunit
32 from nose import SkipTest
32 from nose import SkipTest
33 from nose.core import TestProgram
33 from nose.core import TestProgram
34 from nose.plugins import Plugin
34 from nose.plugins import Plugin
35 from nose.util import safe_str
35 from nose.util import safe_str
36
36
37 from IPython import version_info
37 from IPython import version_info
38 from IPython.utils.py3compat import bytes_to_str
38 from IPython.utils.py3compat import bytes_to_str
39 from IPython.utils.importstring import import_item
39 from IPython.utils.importstring import import_item
40 from IPython.testing.plugin.ipdoctest import IPythonDoctest
40 from IPython.testing.plugin.ipdoctest import IPythonDoctest
41 from IPython.external.decorators import KnownFailure, knownfailureif
41 from IPython.external.decorators import KnownFailure, knownfailureif
42
42
43 pjoin = path.join
43 pjoin = path.join
44
44
45
45
46 # Enable printing all warnings raise by IPython's modules
46 # Enable printing all warnings raise by IPython's modules
47 warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*')
47 warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*')
48
48
49
50 if version_info < (4,2):
51 # ignore some warnings from traitlets until 6.0
52 warnings.filterwarnings('ignore', message='.*on_trait_change is deprecated: use observe instead.*')
53 warnings.filterwarnings('ignore', message='.*was set from the constructor.*', category=Warning, module='IPython.*')
54 warnings.filterwarnings('ignore', message='.*use the instance .help string directly, like x.help.*', category=DeprecationWarning, module='IPython.*')
55 else :
56 warnings.warn('iptest has been filtering out for Traitlets warnings messages, for 2 minor versions (since 4.x), please consider updating to use new API')
57
58 if version_info < (6,):
49 if version_info < (6,):
59 # nose.tools renames all things from `camelCase` to `snake_case` which raise an
50 # nose.tools renames all things from `camelCase` to `snake_case` which raise an
60 # warning with the runner they also import from standard import library. (as of Dec 2015)
51 # warning with the runner they also import from standard import library. (as of Dec 2015)
61 # Ignore, let's revisit that in a couple of years for IPython 6.
52 # Ignore, let's revisit that in a couple of years for IPython 6.
62 warnings.filterwarnings('ignore', message='.*Please use assertEqual instead', category=Warning, module='IPython.*')
53 warnings.filterwarnings('ignore', message='.*Please use assertEqual instead', category=Warning, module='IPython.*')
63
54
64
55
65 # ------------------------------------------------------------------------------
56 # ------------------------------------------------------------------------------
66 # Monkeypatch Xunit to count known failures as skipped.
57 # Monkeypatch Xunit to count known failures as skipped.
67 # ------------------------------------------------------------------------------
58 # ------------------------------------------------------------------------------
68 def monkeypatch_xunit():
59 def monkeypatch_xunit():
69 try:
60 try:
70 knownfailureif(True)(lambda: None)()
61 knownfailureif(True)(lambda: None)()
71 except Exception as e:
62 except Exception as e:
72 KnownFailureTest = type(e)
63 KnownFailureTest = type(e)
73
64
74 def addError(self, test, err, capt=None):
65 def addError(self, test, err, capt=None):
75 if issubclass(err[0], KnownFailureTest):
66 if issubclass(err[0], KnownFailureTest):
76 err = (SkipTest,) + err[1:]
67 err = (SkipTest,) + err[1:]
77 return self.orig_addError(test, err, capt)
68 return self.orig_addError(test, err, capt)
78
69
79 Xunit.orig_addError = Xunit.addError
70 Xunit.orig_addError = Xunit.addError
80 Xunit.addError = addError
71 Xunit.addError = addError
81
72
82 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
83 # Check which dependencies are installed and greater than minimum version.
74 # Check which dependencies are installed and greater than minimum version.
84 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
85 def extract_version(mod):
76 def extract_version(mod):
86 return mod.__version__
77 return mod.__version__
87
78
88 def test_for(item, min_version=None, callback=extract_version):
79 def test_for(item, min_version=None, callback=extract_version):
89 """Test to see if item is importable, and optionally check against a minimum
80 """Test to see if item is importable, and optionally check against a minimum
90 version.
81 version.
91
82
92 If min_version is given, the default behavior is to check against the
83 If min_version is given, the default behavior is to check against the
93 `__version__` attribute of the item, but specifying `callback` allows you to
84 `__version__` attribute of the item, but specifying `callback` allows you to
94 extract the value you are interested in. e.g::
85 extract the value you are interested in. e.g::
95
86
96 In [1]: import sys
87 In [1]: import sys
97
88
98 In [2]: from IPython.testing.iptest import test_for
89 In [2]: from IPython.testing.iptest import test_for
99
90
100 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
91 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
101 Out[3]: True
92 Out[3]: True
102
93
103 """
94 """
104 try:
95 try:
105 check = import_item(item)
96 check = import_item(item)
106 except (ImportError, RuntimeError):
97 except (ImportError, RuntimeError):
107 # GTK reports Runtime error if it can't be initialized even if it's
98 # GTK reports Runtime error if it can't be initialized even if it's
108 # importable.
99 # importable.
109 return False
100 return False
110 else:
101 else:
111 if min_version:
102 if min_version:
112 if callback:
103 if callback:
113 # extra processing step to get version to compare
104 # extra processing step to get version to compare
114 check = callback(check)
105 check = callback(check)
115
106
116 return check >= min_version
107 return check >= min_version
117 else:
108 else:
118 return True
109 return True
119
110
120 # Global dict where we can store information on what we have and what we don't
111 # Global dict where we can store information on what we have and what we don't
121 # have available at test run time
112 # have available at test run time
122 have = {'matplotlib': test_for('matplotlib'),
113 have = {'matplotlib': test_for('matplotlib'),
123 'pygments': test_for('pygments'),
114 'pygments': test_for('pygments'),
124 'sqlite3': test_for('sqlite3')}
115 'sqlite3': test_for('sqlite3')}
125
116
126 #-----------------------------------------------------------------------------
117 #-----------------------------------------------------------------------------
127 # Test suite definitions
118 # Test suite definitions
128 #-----------------------------------------------------------------------------
119 #-----------------------------------------------------------------------------
129
120
130 test_group_names = ['core',
121 test_group_names = ['core',
131 'extensions', 'lib', 'terminal', 'testing', 'utils',
122 'extensions', 'lib', 'terminal', 'testing', 'utils',
132 ]
123 ]
133
124
134 class TestSection(object):
125 class TestSection(object):
135 def __init__(self, name, includes):
126 def __init__(self, name, includes):
136 self.name = name
127 self.name = name
137 self.includes = includes
128 self.includes = includes
138 self.excludes = []
129 self.excludes = []
139 self.dependencies = []
130 self.dependencies = []
140 self.enabled = True
131 self.enabled = True
141
132
142 def exclude(self, module):
133 def exclude(self, module):
143 if not module.startswith('IPython'):
134 if not module.startswith('IPython'):
144 module = self.includes[0] + "." + module
135 module = self.includes[0] + "." + module
145 self.excludes.append(module.replace('.', os.sep))
136 self.excludes.append(module.replace('.', os.sep))
146
137
147 def requires(self, *packages):
138 def requires(self, *packages):
148 self.dependencies.extend(packages)
139 self.dependencies.extend(packages)
149
140
150 @property
141 @property
151 def will_run(self):
142 def will_run(self):
152 return self.enabled and all(have[p] for p in self.dependencies)
143 return self.enabled and all(have[p] for p in self.dependencies)
153
144
154 # Name -> (include, exclude, dependencies_met)
145 # Name -> (include, exclude, dependencies_met)
155 test_sections = {n:TestSection(n, ['IPython.%s' % n]) for n in test_group_names}
146 test_sections = {n:TestSection(n, ['IPython.%s' % n]) for n in test_group_names}
156
147
157
148
158 # Exclusions and dependencies
149 # Exclusions and dependencies
159 # ---------------------------
150 # ---------------------------
160
151
161 # core:
152 # core:
162 sec = test_sections['core']
153 sec = test_sections['core']
163 if not have['sqlite3']:
154 if not have['sqlite3']:
164 sec.exclude('tests.test_history')
155 sec.exclude('tests.test_history')
165 sec.exclude('history')
156 sec.exclude('history')
166 if not have['matplotlib']:
157 if not have['matplotlib']:
167 sec.exclude('pylabtools'),
158 sec.exclude('pylabtools'),
168 sec.exclude('tests.test_pylabtools')
159 sec.exclude('tests.test_pylabtools')
169
160
170 # lib:
161 # lib:
171 sec = test_sections['lib']
162 sec = test_sections['lib']
172 sec.exclude('kernel')
163 sec.exclude('kernel')
173 if not have['pygments']:
164 if not have['pygments']:
174 sec.exclude('tests.test_lexers')
165 sec.exclude('tests.test_lexers')
175 # We do this unconditionally, so that the test suite doesn't import
166 # We do this unconditionally, so that the test suite doesn't import
176 # gtk, changing the default encoding and masking some unicode bugs.
167 # gtk, changing the default encoding and masking some unicode bugs.
177 sec.exclude('inputhookgtk')
168 sec.exclude('inputhookgtk')
178 # We also do this unconditionally, because wx can interfere with Unix signals.
169 # We also do this unconditionally, because wx can interfere with Unix signals.
179 # There are currently no tests for it anyway.
170 # There are currently no tests for it anyway.
180 sec.exclude('inputhookwx')
171 sec.exclude('inputhookwx')
181 # Testing inputhook will need a lot of thought, to figure out
172 # Testing inputhook will need a lot of thought, to figure out
182 # how to have tests that don't lock up with the gui event
173 # how to have tests that don't lock up with the gui event
183 # loops in the picture
174 # loops in the picture
184 sec.exclude('inputhook')
175 sec.exclude('inputhook')
185
176
186 # testing:
177 # testing:
187 sec = test_sections['testing']
178 sec = test_sections['testing']
188 # These have to be skipped on win32 because they use echo, rm, cd, etc.
179 # These have to be skipped on win32 because they use echo, rm, cd, etc.
189 # See ticket https://github.com/ipython/ipython/issues/87
180 # See ticket https://github.com/ipython/ipython/issues/87
190 if sys.platform == 'win32':
181 if sys.platform == 'win32':
191 sec.exclude('plugin.test_exampleip')
182 sec.exclude('plugin.test_exampleip')
192 sec.exclude('plugin.dtexample')
183 sec.exclude('plugin.dtexample')
193
184
194 # don't run jupyter_console tests found via shim
185 # don't run jupyter_console tests found via shim
195 test_sections['terminal'].exclude('console')
186 test_sections['terminal'].exclude('console')
196
187
197 # extensions:
188 # extensions:
198 sec = test_sections['extensions']
189 sec = test_sections['extensions']
199 # This is deprecated in favour of rpy2
190 # This is deprecated in favour of rpy2
200 sec.exclude('rmagic')
191 sec.exclude('rmagic')
201 # autoreload does some strange stuff, so move it to its own test section
192 # autoreload does some strange stuff, so move it to its own test section
202 sec.exclude('autoreload')
193 sec.exclude('autoreload')
203 sec.exclude('tests.test_autoreload')
194 sec.exclude('tests.test_autoreload')
204 test_sections['autoreload'] = TestSection('autoreload',
195 test_sections['autoreload'] = TestSection('autoreload',
205 ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
196 ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
206 test_group_names.append('autoreload')
197 test_group_names.append('autoreload')
207
198
208
199
209 #-----------------------------------------------------------------------------
200 #-----------------------------------------------------------------------------
210 # Functions and classes
201 # Functions and classes
211 #-----------------------------------------------------------------------------
202 #-----------------------------------------------------------------------------
212
203
213 def check_exclusions_exist():
204 def check_exclusions_exist():
214 from IPython.paths import get_ipython_package_dir
205 from IPython.paths import get_ipython_package_dir
215 from warnings import warn
206 from warnings import warn
216 parent = os.path.dirname(get_ipython_package_dir())
207 parent = os.path.dirname(get_ipython_package_dir())
217 for sec in test_sections:
208 for sec in test_sections:
218 for pattern in sec.exclusions:
209 for pattern in sec.exclusions:
219 fullpath = pjoin(parent, pattern)
210 fullpath = pjoin(parent, pattern)
220 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
211 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
221 warn("Excluding nonexistent file: %r" % pattern)
212 warn("Excluding nonexistent file: %r" % pattern)
222
213
223
214
224 class ExclusionPlugin(Plugin):
215 class ExclusionPlugin(Plugin):
225 """A nose plugin to effect our exclusions of files and directories.
216 """A nose plugin to effect our exclusions of files and directories.
226 """
217 """
227 name = 'exclusions'
218 name = 'exclusions'
228 score = 3000 # Should come before any other plugins
219 score = 3000 # Should come before any other plugins
229
220
230 def __init__(self, exclude_patterns=None):
221 def __init__(self, exclude_patterns=None):
231 """
222 """
232 Parameters
223 Parameters
233 ----------
224 ----------
234
225
235 exclude_patterns : sequence of strings, optional
226 exclude_patterns : sequence of strings, optional
236 Filenames containing these patterns (as raw strings, not as regular
227 Filenames containing these patterns (as raw strings, not as regular
237 expressions) are excluded from the tests.
228 expressions) are excluded from the tests.
238 """
229 """
239 self.exclude_patterns = exclude_patterns or []
230 self.exclude_patterns = exclude_patterns or []
240 super(ExclusionPlugin, self).__init__()
231 super(ExclusionPlugin, self).__init__()
241
232
242 def options(self, parser, env=os.environ):
233 def options(self, parser, env=os.environ):
243 Plugin.options(self, parser, env)
234 Plugin.options(self, parser, env)
244
235
245 def configure(self, options, config):
236 def configure(self, options, config):
246 Plugin.configure(self, options, config)
237 Plugin.configure(self, options, config)
247 # Override nose trying to disable plugin.
238 # Override nose trying to disable plugin.
248 self.enabled = True
239 self.enabled = True
249
240
250 def wantFile(self, filename):
241 def wantFile(self, filename):
251 """Return whether the given filename should be scanned for tests.
242 """Return whether the given filename should be scanned for tests.
252 """
243 """
253 if any(pat in filename for pat in self.exclude_patterns):
244 if any(pat in filename for pat in self.exclude_patterns):
254 return False
245 return False
255 return None
246 return None
256
247
257 def wantDirectory(self, directory):
248 def wantDirectory(self, directory):
258 """Return whether the given directory should be scanned for tests.
249 """Return whether the given directory should be scanned for tests.
259 """
250 """
260 if any(pat in directory for pat in self.exclude_patterns):
251 if any(pat in directory for pat in self.exclude_patterns):
261 return False
252 return False
262 return None
253 return None
263
254
264
255
265 class StreamCapturer(Thread):
256 class StreamCapturer(Thread):
266 daemon = True # Don't hang if main thread crashes
257 daemon = True # Don't hang if main thread crashes
267 started = False
258 started = False
268 def __init__(self, echo=False):
259 def __init__(self, echo=False):
269 super(StreamCapturer, self).__init__()
260 super(StreamCapturer, self).__init__()
270 self.echo = echo
261 self.echo = echo
271 self.streams = []
262 self.streams = []
272 self.buffer = BytesIO()
263 self.buffer = BytesIO()
273 self.readfd, self.writefd = os.pipe()
264 self.readfd, self.writefd = os.pipe()
274 self.buffer_lock = Lock()
265 self.buffer_lock = Lock()
275 self.stop = Event()
266 self.stop = Event()
276
267
277 def run(self):
268 def run(self):
278 self.started = True
269 self.started = True
279
270
280 while not self.stop.is_set():
271 while not self.stop.is_set():
281 chunk = os.read(self.readfd, 1024)
272 chunk = os.read(self.readfd, 1024)
282
273
283 with self.buffer_lock:
274 with self.buffer_lock:
284 self.buffer.write(chunk)
275 self.buffer.write(chunk)
285 if self.echo:
276 if self.echo:
286 sys.stdout.write(bytes_to_str(chunk))
277 sys.stdout.write(bytes_to_str(chunk))
287
278
288 os.close(self.readfd)
279 os.close(self.readfd)
289 os.close(self.writefd)
280 os.close(self.writefd)
290
281
291 def reset_buffer(self):
282 def reset_buffer(self):
292 with self.buffer_lock:
283 with self.buffer_lock:
293 self.buffer.truncate(0)
284 self.buffer.truncate(0)
294 self.buffer.seek(0)
285 self.buffer.seek(0)
295
286
296 def get_buffer(self):
287 def get_buffer(self):
297 with self.buffer_lock:
288 with self.buffer_lock:
298 return self.buffer.getvalue()
289 return self.buffer.getvalue()
299
290
300 def ensure_started(self):
291 def ensure_started(self):
301 if not self.started:
292 if not self.started:
302 self.start()
293 self.start()
303
294
304 def halt(self):
295 def halt(self):
305 """Safely stop the thread."""
296 """Safely stop the thread."""
306 if not self.started:
297 if not self.started:
307 return
298 return
308
299
309 self.stop.set()
300 self.stop.set()
310 os.write(self.writefd, b'\0') # Ensure we're not locked in a read()
301 os.write(self.writefd, b'\0') # Ensure we're not locked in a read()
311 self.join()
302 self.join()
312
303
313 class SubprocessStreamCapturePlugin(Plugin):
304 class SubprocessStreamCapturePlugin(Plugin):
314 name='subprocstreams'
305 name='subprocstreams'
315 def __init__(self):
306 def __init__(self):
316 Plugin.__init__(self)
307 Plugin.__init__(self)
317 self.stream_capturer = StreamCapturer()
308 self.stream_capturer = StreamCapturer()
318 self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
309 self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
319 # This is ugly, but distant parts of the test machinery need to be able
310 # This is ugly, but distant parts of the test machinery need to be able
320 # to redirect streams, so we make the object globally accessible.
311 # to redirect streams, so we make the object globally accessible.
321 nose.iptest_stdstreams_fileno = self.get_write_fileno
312 nose.iptest_stdstreams_fileno = self.get_write_fileno
322
313
323 def get_write_fileno(self):
314 def get_write_fileno(self):
324 if self.destination == 'capture':
315 if self.destination == 'capture':
325 self.stream_capturer.ensure_started()
316 self.stream_capturer.ensure_started()
326 return self.stream_capturer.writefd
317 return self.stream_capturer.writefd
327 elif self.destination == 'discard':
318 elif self.destination == 'discard':
328 return os.open(os.devnull, os.O_WRONLY)
319 return os.open(os.devnull, os.O_WRONLY)
329 else:
320 else:
330 return sys.__stdout__.fileno()
321 return sys.__stdout__.fileno()
331
322
332 def configure(self, options, config):
323 def configure(self, options, config):
333 Plugin.configure(self, options, config)
324 Plugin.configure(self, options, config)
334 # Override nose trying to disable plugin.
325 # Override nose trying to disable plugin.
335 if self.destination == 'capture':
326 if self.destination == 'capture':
336 self.enabled = True
327 self.enabled = True
337
328
338 def startTest(self, test):
329 def startTest(self, test):
339 # Reset log capture
330 # Reset log capture
340 self.stream_capturer.reset_buffer()
331 self.stream_capturer.reset_buffer()
341
332
342 def formatFailure(self, test, err):
333 def formatFailure(self, test, err):
343 # Show output
334 # Show output
344 ec, ev, tb = err
335 ec, ev, tb = err
345 captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
336 captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
346 if captured.strip():
337 if captured.strip():
347 ev = safe_str(ev)
338 ev = safe_str(ev)
348 out = [ev, '>> begin captured subprocess output <<',
339 out = [ev, '>> begin captured subprocess output <<',
349 captured,
340 captured,
350 '>> end captured subprocess output <<']
341 '>> end captured subprocess output <<']
351 return ec, '\n'.join(out), tb
342 return ec, '\n'.join(out), tb
352
343
353 return err
344 return err
354
345
355 formatError = formatFailure
346 formatError = formatFailure
356
347
357 def finalize(self, result):
348 def finalize(self, result):
358 self.stream_capturer.halt()
349 self.stream_capturer.halt()
359
350
360
351
361 def run_iptest():
352 def run_iptest():
362 """Run the IPython test suite using nose.
353 """Run the IPython test suite using nose.
363
354
364 This function is called when this script is **not** called with the form
355 This function is called when this script is **not** called with the form
365 `iptest all`. It simply calls nose with appropriate command line flags
356 `iptest all`. It simply calls nose with appropriate command line flags
366 and accepts all of the standard nose arguments.
357 and accepts all of the standard nose arguments.
367 """
358 """
368 # Apply our monkeypatch to Xunit
359 # Apply our monkeypatch to Xunit
369 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
360 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
370 monkeypatch_xunit()
361 monkeypatch_xunit()
371
362
372 warnings.filterwarnings('ignore',
363 warnings.filterwarnings('ignore',
373 'This will be removed soon. Use IPython.testing.util instead')
364 'This will be removed soon. Use IPython.testing.util instead')
374
365
375 arg1 = sys.argv[1]
366 arg1 = sys.argv[1]
376 if arg1 in test_sections:
367 if arg1 in test_sections:
377 section = test_sections[arg1]
368 section = test_sections[arg1]
378 sys.argv[1:2] = section.includes
369 sys.argv[1:2] = section.includes
379 elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
370 elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
380 section = test_sections[arg1[8:]]
371 section = test_sections[arg1[8:]]
381 sys.argv[1:2] = section.includes
372 sys.argv[1:2] = section.includes
382 else:
373 else:
383 section = TestSection(arg1, includes=[arg1])
374 section = TestSection(arg1, includes=[arg1])
384
375
385
376
386 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
377 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
387 # We add --exe because of setuptools' imbecility (it
378 # We add --exe because of setuptools' imbecility (it
388 # blindly does chmod +x on ALL files). Nose does the
379 # blindly does chmod +x on ALL files). Nose does the
389 # right thing and it tries to avoid executables,
380 # right thing and it tries to avoid executables,
390 # setuptools unfortunately forces our hand here. This
381 # setuptools unfortunately forces our hand here. This
391 # has been discussed on the distutils list and the
382 # has been discussed on the distutils list and the
392 # setuptools devs refuse to fix this problem!
383 # setuptools devs refuse to fix this problem!
393 '--exe',
384 '--exe',
394 ]
385 ]
395 if '-a' not in argv and '-A' not in argv:
386 if '-a' not in argv and '-A' not in argv:
396 argv = argv + ['-a', '!crash']
387 argv = argv + ['-a', '!crash']
397
388
398 if nose.__version__ >= '0.11':
389 if nose.__version__ >= '0.11':
399 # I don't fully understand why we need this one, but depending on what
390 # I don't fully understand why we need this one, but depending on what
400 # directory the test suite is run from, if we don't give it, 0 tests
391 # directory the test suite is run from, if we don't give it, 0 tests
401 # get run. Specifically, if the test suite is run from the source dir
392 # get run. Specifically, if the test suite is run from the source dir
402 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
393 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
403 # even if the same call done in this directory works fine). It appears
394 # even if the same call done in this directory works fine). It appears
404 # that if the requested package is in the current dir, nose bails early
395 # that if the requested package is in the current dir, nose bails early
405 # by default. Since it's otherwise harmless, leave it in by default
396 # by default. Since it's otherwise harmless, leave it in by default
406 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
397 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
407 argv.append('--traverse-namespace')
398 argv.append('--traverse-namespace')
408
399
409 plugins = [ ExclusionPlugin(section.excludes), KnownFailure(),
400 plugins = [ ExclusionPlugin(section.excludes), KnownFailure(),
410 SubprocessStreamCapturePlugin() ]
401 SubprocessStreamCapturePlugin() ]
411
402
412 # we still have some vestigial doctests in core
403 # we still have some vestigial doctests in core
413 if (section.name.startswith(('core', 'IPython.core'))):
404 if (section.name.startswith(('core', 'IPython.core'))):
414 plugins.append(IPythonDoctest())
405 plugins.append(IPythonDoctest())
415 argv.extend([
406 argv.extend([
416 '--with-ipdoctest',
407 '--with-ipdoctest',
417 '--ipdoctest-tests',
408 '--ipdoctest-tests',
418 '--ipdoctest-extension=txt',
409 '--ipdoctest-extension=txt',
419 ])
410 ])
420
411
421
412
422 # Use working directory set by parent process (see iptestcontroller)
413 # Use working directory set by parent process (see iptestcontroller)
423 if 'IPTEST_WORKING_DIR' in os.environ:
414 if 'IPTEST_WORKING_DIR' in os.environ:
424 os.chdir(os.environ['IPTEST_WORKING_DIR'])
415 os.chdir(os.environ['IPTEST_WORKING_DIR'])
425
416
426 # We need a global ipython running in this process, but the special
417 # We need a global ipython running in this process, but the special
427 # in-process group spawns its own IPython kernels, so for *that* group we
418 # in-process group spawns its own IPython kernels, so for *that* group we
428 # must avoid also opening the global one (otherwise there's a conflict of
419 # must avoid also opening the global one (otherwise there's a conflict of
429 # singletons). Ultimately the solution to this problem is to refactor our
420 # singletons). Ultimately the solution to this problem is to refactor our
430 # assumptions about what needs to be a singleton and what doesn't (app
421 # assumptions about what needs to be a singleton and what doesn't (app
431 # objects should, individual shells shouldn't). But for now, this
422 # objects should, individual shells shouldn't). But for now, this
432 # workaround allows the test suite for the inprocess module to complete.
423 # workaround allows the test suite for the inprocess module to complete.
433 if 'kernel.inprocess' not in section.name:
424 if 'kernel.inprocess' not in section.name:
434 from IPython.testing import globalipapp
425 from IPython.testing import globalipapp
435 globalipapp.start_ipython()
426 globalipapp.start_ipython()
436
427
437 # Now nose can run
428 # Now nose can run
438 TestProgram(argv=argv, addplugins=plugins)
429 TestProgram(argv=argv, addplugins=plugins)
439
430
440 if __name__ == '__main__':
431 if __name__ == '__main__':
441 run_iptest()
432 run_iptest()
General Comments 0
You need to be logged in to leave comments. Login now