##// END OF EJS Templates
Let iptest pass arguments correctly to nose (in-process or in subprocess)....
Fernando Perez -
Show More
@@ -1,420 +1,397 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) or trial recursively. This
8 calling this script (with different arguments) or trial 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 For now, this script requires that both nose and twisted are installed. This
15 For now, this script requires that both nose and twisted are installed. This
16 will change in the future.
16 will change in the future.
17 """
17 """
18
18
19 from __future__ import absolute_import
20
21 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
22 # Module imports
20 # Module imports
23 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
24
22
25 # Stdlib
23 # Stdlib
26 import os
24 import os
27 import os.path as path
25 import os.path as path
28 import signal
26 import signal
29 import sys
27 import sys
30 import subprocess
28 import subprocess
31 import tempfile
29 import tempfile
32 import time
30 import time
33 import warnings
31 import warnings
34
32
35 # Note: monkeypatch!
33 # Note: monkeypatch!
36 # We need to monkeypatch a small problem in nose itself first, before importing
34 # We need to monkeypatch a small problem in nose itself first, before importing
37 # it for actual use. This should get into nose upstream, but its release cycle
35 # it for actual use. This should get into nose upstream, but its release cycle
38 # is slow and we need it for our parametric tests to work correctly.
36 # is slow and we need it for our parametric tests to work correctly.
39 from . import nosepatch
37 from IPython.testing import nosepatch
40 # Now, proceed to import nose itself
38 # Now, proceed to import nose itself
41 import nose.plugins.builtin
39 import nose.plugins.builtin
42 from nose.core import TestProgram
40 from nose.core import TestProgram
43
41
44 # Our own imports
42 # Our own imports
45 from IPython.utils import genutils
43 from IPython.utils import genutils
46 from IPython.utils.platutils import find_cmd, FindCmdError
44 from IPython.utils.platutils import find_cmd, FindCmdError
47 from . import globalipapp
45 from IPython.testing import globalipapp
48 from . import tools
46 from IPython.testing import tools
49 from .plugin.ipdoctest import IPythonDoctest
47 from IPython.testing.plugin.ipdoctest import IPythonDoctest
50
48
51 pjoin = path.join
49 pjoin = path.join
52
50
53 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
54 # Warnings control
52 # Warnings control
55 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
56 # Twisted generates annoying warnings with Python 2.6, as will do other code
54 # Twisted generates annoying warnings with Python 2.6, as will do other code
57 # that imports 'sets' as of today
55 # that imports 'sets' as of today
58 warnings.filterwarnings('ignore', 'the sets module is deprecated',
56 warnings.filterwarnings('ignore', 'the sets module is deprecated',
59 DeprecationWarning )
57 DeprecationWarning )
60
58
61 # This one also comes from Twisted
59 # This one also comes from Twisted
62 warnings.filterwarnings('ignore', 'the sha module is deprecated',
60 warnings.filterwarnings('ignore', 'the sha module is deprecated',
63 DeprecationWarning)
61 DeprecationWarning)
64
62
65 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
66 # Logic for skipping doctests
64 # Logic for skipping doctests
67 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
68
66
69 def test_for(mod):
67 def test_for(mod):
70 """Test to see if mod is importable."""
68 """Test to see if mod is importable."""
71 try:
69 try:
72 __import__(mod)
70 __import__(mod)
73 except ImportError:
71 except ImportError:
74 return False
72 return False
75 else:
73 else:
76 return True
74 return True
77
75
78
76
79 have_curses = test_for('_curses')
77 have_curses = test_for('_curses')
80 have_wx = test_for('wx')
78 have_wx = test_for('wx')
81 have_wx_aui = test_for('wx.aui')
79 have_wx_aui = test_for('wx.aui')
82 have_zi = test_for('zope.interface')
80 have_zi = test_for('zope.interface')
83 have_twisted = test_for('twisted')
81 have_twisted = test_for('twisted')
84 have_foolscap = test_for('foolscap')
82 have_foolscap = test_for('foolscap')
85 have_objc = test_for('objc')
83 have_objc = test_for('objc')
86 have_pexpect = test_for('pexpect')
84 have_pexpect = test_for('pexpect')
87 have_gtk = test_for('gtk')
85 have_gtk = test_for('gtk')
88 have_gobject = test_for('gobject')
86 have_gobject = test_for('gobject')
89
87
90
88
91 def make_exclude():
89 def make_exclude():
92 """Make patterns of modules and packages to exclude from testing.
90 """Make patterns of modules and packages to exclude from testing.
93
91
94 For the IPythonDoctest plugin, we need to exclude certain patterns that
92 For the IPythonDoctest plugin, we need to exclude certain patterns that
95 cause testing problems. We should strive to minimize the number of
93 cause testing problems. We should strive to minimize the number of
96 skipped modules, since this means untested code. As the testing
94 skipped modules, since this means untested code. As the testing
97 machinery solidifies, this list should eventually become empty.
95 machinery solidifies, this list should eventually become empty.
98 These modules and packages will NOT get scanned by nose at all for tests.
96 These modules and packages will NOT get scanned by nose at all for tests.
99 """
97 """
100 # Simple utility to make IPython paths more readably, we need a lot of
98 # Simple utility to make IPython paths more readably, we need a lot of
101 # these below
99 # these below
102 ipjoin = lambda *paths: pjoin('IPython', *paths)
100 ipjoin = lambda *paths: pjoin('IPython', *paths)
103
101
104 exclusions = [ipjoin('external'),
102 exclusions = [ipjoin('external'),
105 ipjoin('frontend', 'process', 'winprocess.py'),
103 ipjoin('frontend', 'process', 'winprocess.py'),
106 pjoin('IPython_doctest_plugin'),
104 pjoin('IPython_doctest_plugin'),
107 ipjoin('quarantine'),
105 ipjoin('quarantine'),
108 ipjoin('deathrow'),
106 ipjoin('deathrow'),
109 ipjoin('testing', 'attic'),
107 ipjoin('testing', 'attic'),
110 # This guy is probably attic material
108 # This guy is probably attic material
111 ipjoin('testing', 'mkdoctests'),
109 ipjoin('testing', 'mkdoctests'),
112 # Testing inputhook will need a lot of thought, to figure out
110 # Testing inputhook will need a lot of thought, to figure out
113 # how to have tests that don't lock up with the gui event
111 # how to have tests that don't lock up with the gui event
114 # loops in the picture
112 # loops in the picture
115 ipjoin('lib', 'inputhook'),
113 ipjoin('lib', 'inputhook'),
116 # Config files aren't really importable stand-alone
114 # Config files aren't really importable stand-alone
117 ipjoin('config', 'default'),
115 ipjoin('config', 'default'),
118 ipjoin('config', 'profile'),
116 ipjoin('config', 'profile'),
119 ]
117 ]
120
118
121 if not have_wx:
119 if not have_wx:
122 exclusions.append(ipjoin('gui'))
120 exclusions.append(ipjoin('gui'))
123 exclusions.append(ipjoin('frontend', 'wx'))
121 exclusions.append(ipjoin('frontend', 'wx'))
124 exclusions.append(ipjoin('lib', 'inputhookwx'))
122 exclusions.append(ipjoin('lib', 'inputhookwx'))
125
123
126 if not have_gtk or not have_gobject:
124 if not have_gtk or not have_gobject:
127 exclusions.append(ipjoin('lib', 'inputhookgtk'))
125 exclusions.append(ipjoin('lib', 'inputhookgtk'))
128
126
129 if not have_wx_aui:
127 if not have_wx_aui:
130 exclusions.append(ipjoin('gui', 'wx', 'wxIPython'))
128 exclusions.append(ipjoin('gui', 'wx', 'wxIPython'))
131
129
132 if not have_objc:
130 if not have_objc:
133 exclusions.append(ipjoin('frontend', 'cocoa'))
131 exclusions.append(ipjoin('frontend', 'cocoa'))
134
132
135 if not sys.platform == 'win32':
133 if not sys.platform == 'win32':
136 exclusions.append(ipjoin('utils', 'platutils_win32'))
134 exclusions.append(ipjoin('utils', 'platutils_win32'))
137
135
138 # These have to be skipped on win32 because the use echo, rm, cd, etc.
136 # These have to be skipped on win32 because the use echo, rm, cd, etc.
139 # See ticket https://bugs.launchpad.net/bugs/366982
137 # See ticket https://bugs.launchpad.net/bugs/366982
140 if sys.platform == 'win32':
138 if sys.platform == 'win32':
141 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
139 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
142 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
140 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
143
141
144 if not os.name == 'posix':
142 if not os.name == 'posix':
145 exclusions.append(ipjoin('utils', 'platutils_posix'))
143 exclusions.append(ipjoin('utils', 'platutils_posix'))
146
144
147 if not have_pexpect:
145 if not have_pexpect:
148 exclusions.extend([ipjoin('scripts', 'irunner'),
146 exclusions.extend([ipjoin('scripts', 'irunner'),
149 ipjoin('lib', 'irunner')])
147 ipjoin('lib', 'irunner')])
150
148
151 # This is scary. We still have things in frontend and testing that
149 # This is scary. We still have things in frontend and testing that
152 # are being tested by nose that use twisted. We need to rethink
150 # are being tested by nose that use twisted. We need to rethink
153 # how we are isolating dependencies in testing.
151 # how we are isolating dependencies in testing.
154 if not (have_twisted and have_zi and have_foolscap):
152 if not (have_twisted and have_zi and have_foolscap):
155 exclusions.extend(
153 exclusions.extend(
156 [ipjoin('frontend', 'asyncfrontendbase'),
154 [ipjoin('frontend', 'asyncfrontendbase'),
157 ipjoin('frontend', 'prefilterfrontend'),
155 ipjoin('frontend', 'prefilterfrontend'),
158 ipjoin('frontend', 'frontendbase'),
156 ipjoin('frontend', 'frontendbase'),
159 ipjoin('frontend', 'linefrontendbase'),
157 ipjoin('frontend', 'linefrontendbase'),
160 ipjoin('frontend', 'tests', 'test_linefrontend'),
158 ipjoin('frontend', 'tests', 'test_linefrontend'),
161 ipjoin('frontend', 'tests', 'test_frontendbase'),
159 ipjoin('frontend', 'tests', 'test_frontendbase'),
162 ipjoin('frontend', 'tests', 'test_prefilterfrontend'),
160 ipjoin('frontend', 'tests', 'test_prefilterfrontend'),
163 ipjoin('frontend', 'tests', 'test_asyncfrontendbase'),
161 ipjoin('frontend', 'tests', 'test_asyncfrontendbase'),
164 ipjoin('testing', 'parametric'),
162 ipjoin('testing', 'parametric'),
165 ipjoin('testing', 'util'),
163 ipjoin('testing', 'util'),
166 ipjoin('testing', 'tests', 'test_decorators_trial'),
164 ipjoin('testing', 'tests', 'test_decorators_trial'),
167 ] )
165 ] )
168
166
169 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
167 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
170 if sys.platform == 'win32':
168 if sys.platform == 'win32':
171 exclusions = [s.replace('\\','\\\\') for s in exclusions]
169 exclusions = [s.replace('\\','\\\\') for s in exclusions]
172
170
173 return exclusions
171 return exclusions
174
172
175
173
176 #-----------------------------------------------------------------------------
174 #-----------------------------------------------------------------------------
177 # Functions and classes
175 # Functions and classes
178 #-----------------------------------------------------------------------------
176 #-----------------------------------------------------------------------------
179
177
180 class IPTester(object):
178 class IPTester(object):
181 """Call that calls iptest or trial in a subprocess.
179 """Call that calls iptest or trial in a subprocess.
182 """
180 """
183 #: string, name of test runner that will be called
181 #: string, name of test runner that will be called
184 runner = None
182 runner = None
185 #: list, parameters for test runner
183 #: list, parameters for test runner
186 params = None
184 params = None
187 #: list, arguments of system call to be made to call test runner
185 #: list, arguments of system call to be made to call test runner
188 call_args = None
186 call_args = None
189 #: list, process ids of subprocesses we start (for cleanup)
187 #: list, process ids of subprocesses we start (for cleanup)
190 pids = None
188 pids = None
191
189
192 def __init__(self,runner='iptest',params=None):
190 def __init__(self, runner='iptest', params=None):
193 """Create new test runner."""
191 """Create new test runner."""
194 if runner == 'iptest':
192 if runner == 'iptest':
195 # Find our own 'iptest' script OS-level entry point
193 # Find our own 'iptest' script OS-level entry point. Don't look
196 try:
194 # system-wide, so we are sure we pick up *this one*. And pass
197 iptest_path = os.path.abspath(find_cmd('iptest'))
195 # through to subprocess call our own sys.argv
198 except FindCmdError:
196 self.runner = tools.cmd2argv(__file__) + sys.argv[1:]
199 # Script not installed (may be the case for testing situations
200 # that are running from a source tree only), pull from internal
201 # path:
202 pak_dir = os.path.abspath(genutils.get_ipython_package_dir())
203 iptest_path = pjoin(pak_dir, 'scripts', 'iptest')
204 self.runner = tools.cmd2argv(iptest_path) + ['-v']
205 else:
197 else:
206 self.runner = tools.cmd2argv(os.path.abspath(find_cmd('trial')))
198 self.runner = tools.cmd2argv(os.path.abspath(find_cmd('trial')))
207 if params is None:
199 if params is None:
208 params = []
200 params = []
209 if isinstance(params,str):
201 if isinstance(params, str):
210 params = [params]
202 params = [params]
211 self.params = params
203 self.params = params
212
204
213 # Assemble call
205 # Assemble call
214 self.call_args = self.runner+self.params
206 self.call_args = self.runner+self.params
215
207
216 # Store pids of anything we start to clean up on deletion, if possible
208 # Store pids of anything we start to clean up on deletion, if possible
217 # (on posix only, since win32 has no os.kill)
209 # (on posix only, since win32 has no os.kill)
218 self.pids = []
210 self.pids = []
219
211
220 if sys.platform == 'win32':
212 if sys.platform == 'win32':
221 def _run_cmd(self):
213 def _run_cmd(self):
222 # On Windows, use os.system instead of subprocess.call, because I
214 # On Windows, use os.system instead of subprocess.call, because I
223 # was having problems with subprocess and I just don't know enough
215 # was having problems with subprocess and I just don't know enough
224 # about win32 to debug this reliably. Os.system may be the 'old
216 # about win32 to debug this reliably. Os.system may be the 'old
225 # fashioned' way to do it, but it works just fine. If someone
217 # fashioned' way to do it, but it works just fine. If someone
226 # later can clean this up that's fine, as long as the tests run
218 # later can clean this up that's fine, as long as the tests run
227 # reliably in win32.
219 # reliably in win32.
228 return os.system(' '.join(self.call_args))
220 return os.system(' '.join(self.call_args))
229 else:
221 else:
230 def _run_cmd(self):
222 def _run_cmd(self):
231 subp = subprocess.Popen(self.call_args)
223 subp = subprocess.Popen(self.call_args)
232 self.pids.append(subp.pid)
224 self.pids.append(subp.pid)
233 # If this fails, the pid will be left in self.pids and cleaned up
225 # If this fails, the pid will be left in self.pids and cleaned up
234 # later, but if the wait call succeeds, then we can clear the
226 # later, but if the wait call succeeds, then we can clear the
235 # stored pid.
227 # stored pid.
236 retcode = subp.wait()
228 retcode = subp.wait()
237 self.pids.pop()
229 self.pids.pop()
238 return retcode
230 return retcode
239
231
240 def run(self):
232 def run(self):
241 """Run the stored commands"""
233 """Run the stored commands"""
242 try:
234 try:
243 return self._run_cmd()
235 return self._run_cmd()
244 except:
236 except:
245 import traceback
237 import traceback
246 traceback.print_exc()
238 traceback.print_exc()
247 return 1 # signal failure
239 return 1 # signal failure
248
240
249 def __del__(self):
241 def __del__(self):
250 """Cleanup on exit by killing any leftover processes."""
242 """Cleanup on exit by killing any leftover processes."""
251
243
252 if not hasattr(os, 'kill'):
244 if not hasattr(os, 'kill'):
253 return
245 return
254
246
255 for pid in self.pids:
247 for pid in self.pids:
256 try:
248 try:
257 print 'Cleaning stale PID:', pid
249 print 'Cleaning stale PID:', pid
258 os.kill(pid, signal.SIGKILL)
250 os.kill(pid, signal.SIGKILL)
259 except OSError:
251 except OSError:
260 # This is just a best effort, if we fail or the process was
252 # This is just a best effort, if we fail or the process was
261 # really gone, ignore it.
253 # really gone, ignore it.
262 pass
254 pass
263
255
264
256
265 def make_runners():
257 def make_runners():
266 """Define the top-level packages that need to be tested.
258 """Define the top-level packages that need to be tested.
267 """
259 """
268
260
269 nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib',
261 nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib',
270 'scripts', 'testing', 'utils',
262 'scripts', 'testing', 'utils',
271 # Note that we list the kernel here, though the bulk of it
263 # Note that we list the kernel here, though the bulk of it
272 # is twisted-based, because nose picks up doctests that
264 # is twisted-based, because nose picks up doctests that
273 # twisted doesn't.
265 # twisted doesn't.
274 'kernel']
266 'kernel']
267 # The machinery in kernel needs twisted for real testing
275 trial_packages = ['kernel']
268 trial_packages = ['kernel']
276
269
277 if have_wx:
270 if have_wx:
278 nose_packages.append('gui')
271 nose_packages.append('gui')
279
272
280 #nose_packages = ['core'] # dbg
273 #nose_packages = ['config', 'utils'] # dbg
281 #trial_packages = [] # dbg
274 #trial_packages = [] # dbg
282
275
283 nose_packages = ['IPython.%s' % m for m in nose_packages ]
276 nose_packages = ['IPython.%s' % m for m in nose_packages ]
284 trial_packages = ['IPython.%s' % m for m in trial_packages ]
277 trial_packages = ['IPython.%s' % m for m in trial_packages ]
285
278
286 # Make runners, most with nose
279 # Make runners, most with nose
287 nose_testers = [IPTester(params=v) for v in nose_packages]
280 nose_testers = [IPTester(params=v) for v in nose_packages]
288 runners = dict(zip(nose_packages, nose_testers))
281 runners = zip(nose_packages, nose_testers)
282
289 # And add twisted ones if conditions are met
283 # And add twisted ones if conditions are met
290 if have_zi and have_twisted and have_foolscap:
284 if have_zi and have_twisted and have_foolscap:
291 trial_testers = [IPTester('trial',params=v) for v in trial_packages]
285 trial_testers = [IPTester('trial', params=v) for v in trial_packages]
292 runners.update(dict(zip(trial_packages,trial_testers)))
286 runners.extend(zip(trial_packages, trial_testers))
293
287
294 return runners
288 return runners
295
289
296
290
297 def run_iptest():
291 def run_iptest():
298 """Run the IPython test suite using nose.
292 """Run the IPython test suite using nose.
299
293
300 This function is called when this script is **not** called with the form
294 This function is called when this script is **not** called with the form
301 `iptest all`. It simply calls nose with appropriate command line flags
295 `iptest all`. It simply calls nose with appropriate command line flags
302 and accepts all of the standard nose arguments.
296 and accepts all of the standard nose arguments.
303 """
297 """
304
298
305 warnings.filterwarnings('ignore',
299 warnings.filterwarnings('ignore',
306 'This will be removed soon. Use IPython.testing.util instead')
300 'This will be removed soon. Use IPython.testing.util instead')
307
301
308 argv = sys.argv + [ '--detailed-errors',
302 argv = sys.argv + [ '--detailed-errors',
309 # Loading ipdoctest causes problems with Twisted, but
303 # Loading ipdoctest causes problems with Twisted, but
310 # our test suite runner now separates things and runs
304 # our test suite runner now separates things and runs
311 # all Twisted tests with trial.
305 # all Twisted tests with trial.
312 '--with-ipdoctest',
306 '--with-ipdoctest',
313 '--ipdoctest-tests','--ipdoctest-extension=txt',
307 '--ipdoctest-tests','--ipdoctest-extension=txt',
314
308
315 #'-x','-s', # dbg
316
317 # We add --exe because of setuptools' imbecility (it
309 # We add --exe because of setuptools' imbecility (it
318 # blindly does chmod +x on ALL files). Nose does the
310 # blindly does chmod +x on ALL files). Nose does the
319 # right thing and it tries to avoid executables,
311 # right thing and it tries to avoid executables,
320 # setuptools unfortunately forces our hand here. This
312 # setuptools unfortunately forces our hand here. This
321 # has been discussed on the distutils list and the
313 # has been discussed on the distutils list and the
322 # setuptools devs refuse to fix this problem!
314 # setuptools devs refuse to fix this problem!
323 '--exe',
315 '--exe',
324 ]
316 ]
325
317
326 # Detect if any tests were required by explicitly calling an IPython
327 # submodule or giving a specific path
328 has_tests = False
329 for arg in sys.argv:
330 if 'IPython' in arg or arg.endswith('.py') or \
331 (':' in arg and '.py' in arg):
332 has_tests = True
333 break
334
335 # If nothing was specifically requested, test full IPython
336 if not has_tests:
337 argv.append('IPython')
338
318
339 ## # Construct list of plugins, omitting the existing doctest plugin, which
319 # Construct list of plugins, omitting the existing doctest plugin, which
340 ## # ours replaces (and extends).
320 # ours replaces (and extends).
341 plugins = [IPythonDoctest(make_exclude())]
321 plugins = [IPythonDoctest(make_exclude())]
342 for p in nose.plugins.builtin.plugins:
322 for p in nose.plugins.builtin.plugins:
343 plug = p()
323 plug = p()
344 if plug.name == 'doctest':
324 if plug.name == 'doctest':
345 continue
325 continue
346 plugins.append(plug)
326 plugins.append(plug)
347
327
348 # We need a global ipython running in this process
328 # We need a global ipython running in this process
349 globalipapp.start_ipython()
329 globalipapp.start_ipython()
350 # Now nose can run
330 # Now nose can run
351 TestProgram(argv=argv,plugins=plugins)
331 TestProgram(argv=argv, plugins=plugins)
352
332
353
333
354 def run_iptestall():
334 def run_iptestall():
355 """Run the entire IPython test suite by calling nose and trial.
335 """Run the entire IPython test suite by calling nose and trial.
356
336
357 This function constructs :class:`IPTester` instances for all IPython
337 This function constructs :class:`IPTester` instances for all IPython
358 modules and package and then runs each of them. This causes the modules
338 modules and package and then runs each of them. This causes the modules
359 and packages of IPython to be tested each in their own subprocess using
339 and packages of IPython to be tested each in their own subprocess using
360 nose or twisted.trial appropriately.
340 nose or twisted.trial appropriately.
361 """
341 """
362
342
363 runners = make_runners()
343 runners = make_runners()
364
344
365 # Run the test runners in a temporary dir so we can nuke it when finished
345 # Run the test runners in a temporary dir so we can nuke it when finished
366 # to clean up any junk files left over by accident. This also makes it
346 # to clean up any junk files left over by accident. This also makes it
367 # robust against being run in non-writeable directories by mistake, as the
347 # robust against being run in non-writeable directories by mistake, as the
368 # temp dir will always be user-writeable.
348 # temp dir will always be user-writeable.
369 curdir = os.getcwd()
349 curdir = os.getcwd()
370 testdir = tempfile.gettempdir()
350 testdir = tempfile.gettempdir()
371 os.chdir(testdir)
351 os.chdir(testdir)
372
352
373 # Run all test runners, tracking execution time
353 # Run all test runners, tracking execution time
374 failed = {}
354 failed = []
375 t_start = time.time()
355 t_start = time.time()
376 try:
356 try:
377 for name,runner in runners.iteritems():
357 for (name, runner) in runners:
378 print '*'*77
358 print '*'*70
379 print 'IPython test group:',name
359 print 'IPython test group:',name
380 res = runner.run()
360 res = runner.run()
381 if res:
361 if res:
382 failed[name] = res
362 failed.append( (name, runner) )
383 finally:
363 finally:
384 os.chdir(curdir)
364 os.chdir(curdir)
385 t_end = time.time()
365 t_end = time.time()
386 t_tests = t_end - t_start
366 t_tests = t_end - t_start
387 nrunners = len(runners)
367 nrunners = len(runners)
388 nfail = len(failed)
368 nfail = len(failed)
389 # summarize results
369 # summarize results
390 print
370 print
391 print '*'*77
371 print '*'*70
392 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
372 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
393 print
373 print
394 if not failed:
374 if not failed:
395 print 'OK'
375 print 'OK'
396 else:
376 else:
397 # If anything went wrong, point out what command to rerun manually to
377 # If anything went wrong, point out what command to rerun manually to
398 # see the actual errors and individual summary
378 # see the actual errors and individual summary
399 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
379 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
400 for name in failed:
380 for name, failed_runner in failed:
401 failed_runner = runners[name]
402 print '-'*40
381 print '-'*40
403 print 'Runner failed:',name
382 print 'Runner failed:',name
404 print 'You may wish to rerun this one individually, with:'
383 print 'You may wish to rerun this one individually, with:'
405 print ' '.join(failed_runner.call_args)
384 print ' '.join(failed_runner.call_args)
406 print
385 print
407
386
408
387
409 def main():
388 def main():
410 if len(sys.argv) == 1:
389 for arg in sys.argv[1:]:
411 run_iptestall()
390 if arg.startswith('IPython'):
412 else:
413 if sys.argv[1] == 'all':
414 run_iptestall()
415 else:
416 run_iptest()
391 run_iptest()
392 else:
393 run_iptestall()
417
394
418
395
419 if __name__ == '__main__':
396 if __name__ == '__main__':
420 main()
397 main()
@@ -1,38 +1,37 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
1 # encoding: utf-8
3
2
4 def test_import_coloransi():
3 def test_import_coloransi():
5 from IPython.utils import coloransi
4 from IPython.utils import coloransi
6
5
7 def test_import_DPyGetOpt():
6 def test_import_DPyGetOpt():
8 from IPython.utils import DPyGetOpt
7 from IPython.utils import DPyGetOpt
9
8
10 def test_import_generics():
9 def test_import_generics():
11 from IPython.utils import generics
10 from IPython.utils import generics
12
11
13 def test_import_genutils():
12 def test_import_genutils():
14 from IPython.utils import genutils
13 from IPython.utils import genutils
15
14
16 def test_import_ipstruct():
15 def test_import_ipstruct():
17 from IPython.utils import ipstruct
16 from IPython.utils import ipstruct
18
17
19 def test_import_platutils():
18 def test_import_platutils():
20 from IPython.utils import platutils
19 from IPython.utils import platutils
21
20
22 def test_import_PyColorize():
21 def test_import_PyColorize():
23 from IPython.utils import PyColorize
22 from IPython.utils import PyColorize
24
23
25 def test_import_rlineimpl():
24 def test_import_rlineimpl():
26 from IPython.utils import rlineimpl
25 from IPython.utils import rlineimpl
27
26
28 def test_import_strdispatch():
27 def test_import_strdispatch():
29 from IPython.utils import strdispatch
28 from IPython.utils import strdispatch
30
29
31 def test_import_upgradedir():
30 def test_import_upgradedir():
32 from IPython.utils import upgradedir
31 from IPython.utils import upgradedir
33
32
34 def test_import_wildcard():
33 def test_import_wildcard():
35 from IPython.utils import wildcard
34 from IPython.utils import wildcard
36
35
37 def test_import_winconsole():
36 def test_import_winconsole():
38 from IPython.utils import winconsole
37 from IPython.utils import winconsole
General Comments 0
You need to be logged in to leave comments. Login now