##// END OF EJS Templates
removing unnecessary print statements
Paul Ivanov -
Show More
@@ -1,664 +1,655
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 signal
34 34 import sys
35 35 import subprocess
36 36 import tempfile
37 37 import time
38 38 import warnings
39 39 import multiprocessing.pool
40 40
41 41 # Now, proceed to import nose itself
42 42 import nose.plugins.builtin
43 43 from nose.plugins.xunit import Xunit
44 44 from nose import SkipTest
45 45 from nose.core import TestProgram
46 46
47 47 # Our own imports
48 48 from IPython.utils import py3compat
49 49 from IPython.utils.importstring import import_item
50 50 from IPython.utils.path import get_ipython_module_path, get_ipython_package_dir
51 51 from IPython.utils.process import pycmd2argv
52 52 from IPython.utils.sysinfo import sys_info
53 53 from IPython.utils.tempdir import TemporaryDirectory
54 54 from IPython.utils.warn import warn
55 55
56 56 from IPython.testing import globalipapp
57 57 from IPython.testing.plugin.ipdoctest import IPythonDoctest
58 58 from IPython.external.decorators import KnownFailure, knownfailureif
59 59
60 60 pjoin = path.join
61 61
62 62
63 63 #-----------------------------------------------------------------------------
64 64 # Globals
65 65 #-----------------------------------------------------------------------------
66 66
67 67
68 68 #-----------------------------------------------------------------------------
69 69 # Warnings control
70 70 #-----------------------------------------------------------------------------
71 71
72 72 # Twisted generates annoying warnings with Python 2.6, as will do other code
73 73 # that imports 'sets' as of today
74 74 warnings.filterwarnings('ignore', 'the sets module is deprecated',
75 75 DeprecationWarning )
76 76
77 77 # This one also comes from Twisted
78 78 warnings.filterwarnings('ignore', 'the sha module is deprecated',
79 79 DeprecationWarning)
80 80
81 81 # Wx on Fedora11 spits these out
82 82 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
83 83 UserWarning)
84 84
85 85 # ------------------------------------------------------------------------------
86 86 # Monkeypatch Xunit to count known failures as skipped.
87 87 # ------------------------------------------------------------------------------
88 88 def monkeypatch_xunit():
89 89 try:
90 90 knownfailureif(True)(lambda: None)()
91 91 except Exception as e:
92 92 KnownFailureTest = type(e)
93 93
94 94 def addError(self, test, err, capt=None):
95 95 if issubclass(err[0], KnownFailureTest):
96 96 err = (SkipTest,) + err[1:]
97 97 return self.orig_addError(test, err, capt)
98 98
99 99 Xunit.orig_addError = Xunit.addError
100 100 Xunit.addError = addError
101 101
102 102 #-----------------------------------------------------------------------------
103 103 # Logic for skipping doctests
104 104 #-----------------------------------------------------------------------------
105 105 def extract_version(mod):
106 106 return mod.__version__
107 107
108 108 def test_for(item, min_version=None, callback=extract_version):
109 109 """Test to see if item is importable, and optionally check against a minimum
110 110 version.
111 111
112 112 If min_version is given, the default behavior is to check against the
113 113 `__version__` attribute of the item, but specifying `callback` allows you to
114 114 extract the value you are interested in. e.g::
115 115
116 116 In [1]: import sys
117 117
118 118 In [2]: from IPython.testing.iptest import test_for
119 119
120 120 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
121 121 Out[3]: True
122 122
123 123 """
124 124 try:
125 125 check = import_item(item)
126 126 except (ImportError, RuntimeError):
127 127 # GTK reports Runtime error if it can't be initialized even if it's
128 128 # importable.
129 129 return False
130 130 else:
131 131 if min_version:
132 132 if callback:
133 133 # extra processing step to get version to compare
134 134 check = callback(check)
135 135
136 136 return check >= min_version
137 137 else:
138 138 return True
139 139
140 140 # Global dict where we can store information on what we have and what we don't
141 141 # have available at test run time
142 142 have = {}
143 143
144 144 have['curses'] = test_for('_curses')
145 145 have['matplotlib'] = test_for('matplotlib')
146 146 have['numpy'] = test_for('numpy')
147 147 have['pexpect'] = test_for('IPython.external.pexpect')
148 148 have['pymongo'] = test_for('pymongo')
149 149 have['pygments'] = test_for('pygments')
150 150 have['qt'] = test_for('IPython.external.qt')
151 151 have['rpy2'] = test_for('rpy2')
152 152 have['sqlite3'] = test_for('sqlite3')
153 153 have['cython'] = test_for('Cython')
154 154 have['oct2py'] = test_for('oct2py')
155 155 have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
156 156 have['jinja2'] = test_for('jinja2')
157 157 have['wx'] = test_for('wx')
158 158 have['wx.aui'] = test_for('wx.aui')
159 159 have['azure'] = test_for('azure')
160 160 have['sphinx'] = test_for('sphinx')
161 161
162 162 min_zmq = (2,1,11)
163 163
164 164 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
165 165
166 166 #-----------------------------------------------------------------------------
167 167 # Functions and classes
168 168 #-----------------------------------------------------------------------------
169 169
170 170 def report():
171 171 """Return a string with a summary report of test-related variables."""
172 172
173 173 out = [ sys_info(), '\n']
174 174
175 175 avail = []
176 176 not_avail = []
177 177
178 178 for k, is_avail in have.items():
179 179 if is_avail:
180 180 avail.append(k)
181 181 else:
182 182 not_avail.append(k)
183 183
184 184 if avail:
185 185 out.append('\nTools and libraries available at test time:\n')
186 186 avail.sort()
187 187 out.append(' ' + ' '.join(avail)+'\n')
188 188
189 189 if not_avail:
190 190 out.append('\nTools and libraries NOT available at test time:\n')
191 191 not_avail.sort()
192 192 out.append(' ' + ' '.join(not_avail)+'\n')
193 193
194 194 return ''.join(out)
195 195
196 196
197 197 def make_exclude():
198 198 """Make patterns of modules and packages to exclude from testing.
199 199
200 200 For the IPythonDoctest plugin, we need to exclude certain patterns that
201 201 cause testing problems. We should strive to minimize the number of
202 202 skipped modules, since this means untested code.
203 203
204 204 These modules and packages will NOT get scanned by nose at all for tests.
205 205 """
206 206 # Simple utility to make IPython paths more readably, we need a lot of
207 207 # these below
208 208 ipjoin = lambda *paths: pjoin('IPython', *paths)
209 209
210 210 exclusions = [ipjoin('external'),
211 211 ipjoin('quarantine'),
212 212 ipjoin('deathrow'),
213 213 # This guy is probably attic material
214 214 ipjoin('testing', 'mkdoctests'),
215 215 # Testing inputhook will need a lot of thought, to figure out
216 216 # how to have tests that don't lock up with the gui event
217 217 # loops in the picture
218 218 ipjoin('lib', 'inputhook'),
219 219 # Config files aren't really importable stand-alone
220 220 ipjoin('config', 'profile'),
221 221 # The notebook 'static' directory contains JS, css and other
222 222 # files for web serving. Occasionally projects may put a .py
223 223 # file in there (MathJax ships a conf.py), so we might as
224 224 # well play it safe and skip the whole thing.
225 225 ipjoin('html', 'static'),
226 226 ipjoin('html', 'fabfile'),
227 227 ]
228 228 if not have['sqlite3']:
229 229 exclusions.append(ipjoin('core', 'tests', 'test_history'))
230 230 exclusions.append(ipjoin('core', 'history'))
231 231 if not have['wx']:
232 232 exclusions.append(ipjoin('lib', 'inputhookwx'))
233 233
234 234 if 'IPython.kernel.inprocess' not in sys.argv:
235 235 exclusions.append(ipjoin('kernel', 'inprocess'))
236 236
237 237 # FIXME: temporarily disable autoreload tests, as they can produce
238 238 # spurious failures in subsequent tests (cythonmagic).
239 239 exclusions.append(ipjoin('extensions', 'autoreload'))
240 240 exclusions.append(ipjoin('extensions', 'tests', 'test_autoreload'))
241 241
242 242 # We do this unconditionally, so that the test suite doesn't import
243 243 # gtk, changing the default encoding and masking some unicode bugs.
244 244 exclusions.append(ipjoin('lib', 'inputhookgtk'))
245 245 exclusions.append(ipjoin('kernel', 'zmq', 'gui', 'gtkembed'))
246 246
247 247 #Also done unconditionally, exclude nbconvert directories containing
248 248 #config files used to test. Executing the config files with iptest would
249 249 #cause an exception.
250 250 exclusions.append(ipjoin('nbconvert', 'tests', 'files'))
251 251 exclusions.append(ipjoin('nbconvert', 'exporters', 'tests', 'files'))
252 252
253 253 # These have to be skipped on win32 because the use echo, rm, cd, etc.
254 254 # See ticket https://github.com/ipython/ipython/issues/87
255 255 if sys.platform == 'win32':
256 256 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
257 257 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
258 258
259 259 if not have['pexpect']:
260 260 exclusions.extend([ipjoin('lib', 'irunner'),
261 261 ipjoin('lib', 'tests', 'test_irunner'),
262 262 ipjoin('terminal', 'console'),
263 263 ])
264 264
265 265 if not have['zmq']:
266 266 exclusions.append(ipjoin('lib', 'kernel'))
267 267 exclusions.append(ipjoin('kernel'))
268 268 exclusions.append(ipjoin('qt'))
269 269 exclusions.append(ipjoin('html'))
270 270 exclusions.append(ipjoin('consoleapp.py'))
271 271 exclusions.append(ipjoin('terminal', 'console'))
272 272 exclusions.append(ipjoin('parallel'))
273 273 elif not have['qt'] or not have['pygments']:
274 274 exclusions.append(ipjoin('qt'))
275 275
276 276 if not have['pymongo']:
277 277 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
278 278 exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb'))
279 279
280 280 if not have['matplotlib']:
281 281 exclusions.extend([ipjoin('core', 'pylabtools'),
282 282 ipjoin('core', 'tests', 'test_pylabtools'),
283 283 ipjoin('kernel', 'zmq', 'pylab'),
284 284 ])
285 285
286 286 if not have['cython']:
287 287 exclusions.extend([ipjoin('extensions', 'cythonmagic')])
288 288 exclusions.extend([ipjoin('extensions', 'tests', 'test_cythonmagic')])
289 289
290 290 if not have['oct2py']:
291 291 exclusions.extend([ipjoin('extensions', 'octavemagic')])
292 292 exclusions.extend([ipjoin('extensions', 'tests', 'test_octavemagic')])
293 293
294 294 if not have['tornado']:
295 295 exclusions.append(ipjoin('html'))
296 296
297 297 if not have['jinja2']:
298 298 exclusions.append(ipjoin('html', 'notebookapp'))
299 299
300 300 if not have['rpy2'] or not have['numpy']:
301 301 exclusions.append(ipjoin('extensions', 'rmagic'))
302 302 exclusions.append(ipjoin('extensions', 'tests', 'test_rmagic'))
303 303
304 304 if not have['azure']:
305 305 exclusions.append(ipjoin('html', 'services', 'notebooks', 'azurenbmanager'))
306 306
307 307 if not all((have['pygments'], have['jinja2'], have['sphinx'])):
308 308 exclusions.append(ipjoin('nbconvert'))
309 309
310 310 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
311 311 if sys.platform == 'win32':
312 312 exclusions = [s.replace('\\','\\\\') for s in exclusions]
313 313
314 314 # check for any exclusions that don't seem to exist:
315 315 parent, _ = os.path.split(get_ipython_package_dir())
316 316 for exclusion in exclusions:
317 317 if exclusion.endswith(('deathrow', 'quarantine')):
318 318 # ignore deathrow/quarantine, which exist in dev, but not install
319 319 continue
320 320 fullpath = pjoin(parent, exclusion)
321 321 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
322 322 warn("Excluding nonexistent file: %r" % exclusion)
323 323
324 324 return exclusions
325 325
326 326
327 327 class IPTester(object):
328 328 """Call that calls iptest or trial in a subprocess.
329 329 """
330 330 #: string, name of test runner that will be called
331 331 runner = None
332 332 #: list, parameters for test runner
333 333 params = None
334 334 #: list, arguments of system call to be made to call test runner
335 335 call_args = None
336 336 #: list, subprocesses we start (for cleanup)
337 337 processes = None
338 338 #: str, coverage xml output file
339 339 coverage_xml = None
340 340 buffer_output = False
341 341
342 342 def __init__(self, runner='iptest', params=None):
343 343 """Create new test runner."""
344 344 p = os.path
345 345 if runner == 'iptest':
346 346 iptest_app = os.path.abspath(get_ipython_module_path('IPython.testing.iptest'))
347 347 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
348 348 else:
349 349 raise Exception('Not a valid test runner: %s' % repr(runner))
350 350 if params is None:
351 351 params = []
352 352 if isinstance(params, str):
353 353 params = [params]
354 354 self.params = params
355 355
356 356 # Assemble call
357 357 self.call_args = self.runner+self.params
358 358
359 359 # Find the section we're testing (IPython.foo)
360 360 for sect in self.params:
361 361 if sect.startswith('IPython') or sect in special_test_suites: break
362 362 else:
363 363 raise ValueError("Section not found", self.params)
364 364
365 365 if '--with-xunit' in self.call_args:
366 366
367 367 self.call_args.append('--xunit-file')
368 368 # FIXME: when Windows uses subprocess.call, these extra quotes are unnecessary:
369 369 xunit_file = path.abspath(sect+'.xunit.xml')
370 370 if sys.platform == 'win32':
371 371 xunit_file = '"%s"' % xunit_file
372 372 self.call_args.append(xunit_file)
373 373
374 374 if '--with-xml-coverage' in self.call_args:
375 375 self.coverage_xml = path.abspath(sect+".coverage.xml")
376 376 self.call_args.remove('--with-xml-coverage')
377 377 self.call_args = ["coverage", "run", "--source="+sect] + self.call_args[1:]
378 378
379 379 # Store anything we start to clean up on deletion
380 380 self.processes = []
381 381
382 382 def _run_cmd(self):
383 383 with TemporaryDirectory() as IPYTHONDIR:
384 384 env = os.environ.copy()
385 385 env['IPYTHONDIR'] = IPYTHONDIR
386 386 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
387 387 output = subprocess.PIPE if self.buffer_output else None
388 388 subp = subprocess.Popen(self.call_args, stdout=output,
389 389 stderr=output, env=env)
390 390 self.processes.append(subp)
391 391 # If this fails, the process will be left in self.processes and
392 392 # cleaned up later, but if the wait call succeeds, then we can
393 393 # clear the stored process.
394 394 retcode = subp.wait()
395 395 self.processes.pop()
396 396 self.stdout = subp.stdout
397 397 self.stderr = subp.stderr
398 398 return retcode
399 399
400 400 def run(self):
401 401 """Run the stored commands"""
402 402 try:
403 403 retcode = self._run_cmd()
404 #print(self.stdout.read())
405 #print("std err")
406 #print(self.stderr.read())
407 404 except KeyboardInterrupt:
408 405 return -signal.SIGINT
409 406 except:
410 407 import traceback
411 408 traceback.print_exc()
412 409 return 1 # signal failure
413 410
414 411 if self.coverage_xml:
415 412 subprocess.call(["coverage", "xml", "-o", self.coverage_xml])
416 413 return retcode
417 414
418 415 def __del__(self):
419 416 """Cleanup on exit by killing any leftover processes."""
420 417 for subp in self.processes:
421 418 if subp.poll() is not None:
422 419 continue # process is already dead
423 420
424 421 try:
425 422 print('Cleaning up stale PID: %d' % subp.pid)
426 423 subp.kill()
427 424 except: # (OSError, WindowsError) ?
428 425 # This is just a best effort, if we fail or the process was
429 426 # really gone, ignore it.
430 427 pass
431 428 else:
432 429 for i in range(10):
433 430 if subp.poll() is None:
434 431 time.sleep(0.1)
435 432 else:
436 433 break
437 434
438 435 if subp.poll() is None:
439 436 # The process did not die...
440 437 print('... failed. Manual cleanup may be required.')
441 438
442 439
443 440 special_test_suites = {
444 441 'autoreload': ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'],
445 442 }
446 443
447 444 def make_runners(inc_slow=False):
448 445 """Define the top-level packages that need to be tested.
449 446 """
450 447
451 448 # Packages to be tested via nose, that only depend on the stdlib
452 449 nose_pkg_names = ['config', 'core', 'extensions', 'lib', 'terminal',
453 450 'testing', 'utils', 'nbformat']
454 451
455 452 if have['qt']:
456 453 nose_pkg_names.append('qt')
457 454
458 455 if have['tornado']:
459 456 nose_pkg_names.append('html')
460 457
461 458 if have['zmq']:
462 459 nose_pkg_names.insert(0, 'kernel')
463 460 nose_pkg_names.insert(1, 'kernel.inprocess')
464 461 if inc_slow:
465 462 nose_pkg_names.insert(0, 'parallel')
466 463
467 464 if all((have['pygments'], have['jinja2'], have['sphinx'])):
468 465 nose_pkg_names.append('nbconvert')
469 466
470 467 # For debugging this code, only load quick stuff
471 468 #nose_pkg_names = ['core', 'extensions'] # dbg
472 469
473 470 # Make fully qualified package names prepending 'IPython.' to our name lists
474 471 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
475 472
476 473 # Make runners
477 474 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
478 475
479 476 for name in special_test_suites:
480 477 runners.append((name, IPTester('iptest', params=name)))
481 478
482 479 return runners
483 480
484 481
485 482 def run_iptest():
486 483 """Run the IPython test suite using nose.
487 484
488 485 This function is called when this script is **not** called with the form
489 486 `iptest all`. It simply calls nose with appropriate command line flags
490 487 and accepts all of the standard nose arguments.
491 488 """
492 489 # Apply our monkeypatch to Xunit
493 490 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
494 491 monkeypatch_xunit()
495 492
496 493 warnings.filterwarnings('ignore',
497 494 'This will be removed soon. Use IPython.testing.util instead')
498 495
499 496 if sys.argv[1] in special_test_suites:
500 497 sys.argv[1:2] = special_test_suites[sys.argv[1]]
501 498 special_suite = True
502 499 else:
503 500 special_suite = False
504 501
505 502 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
506 503
507 504 '--with-ipdoctest',
508 505 '--ipdoctest-tests','--ipdoctest-extension=txt',
509 506
510 507 # We add --exe because of setuptools' imbecility (it
511 508 # blindly does chmod +x on ALL files). Nose does the
512 509 # right thing and it tries to avoid executables,
513 510 # setuptools unfortunately forces our hand here. This
514 511 # has been discussed on the distutils list and the
515 512 # setuptools devs refuse to fix this problem!
516 513 '--exe',
517 514 ]
518 515 if '-a' not in argv and '-A' not in argv:
519 516 argv = argv + ['-a', '!crash']
520 517
521 518 if nose.__version__ >= '0.11':
522 519 # I don't fully understand why we need this one, but depending on what
523 520 # directory the test suite is run from, if we don't give it, 0 tests
524 521 # get run. Specifically, if the test suite is run from the source dir
525 522 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
526 523 # even if the same call done in this directory works fine). It appears
527 524 # that if the requested package is in the current dir, nose bails early
528 525 # by default. Since it's otherwise harmless, leave it in by default
529 526 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
530 527 argv.append('--traverse-namespace')
531 528
532 529 # use our plugin for doctesting. It will remove the standard doctest plugin
533 530 # if it finds it enabled
534 531 ipdt = IPythonDoctest() if special_suite else IPythonDoctest(make_exclude())
535 532 plugins = [ipdt, KnownFailure()]
536 533
537 534 # We need a global ipython running in this process, but the special
538 535 # in-process group spawns its own IPython kernels, so for *that* group we
539 536 # must avoid also opening the global one (otherwise there's a conflict of
540 537 # singletons). Ultimately the solution to this problem is to refactor our
541 538 # assumptions about what needs to be a singleton and what doesn't (app
542 539 # objects should, individual shells shouldn't). But for now, this
543 540 # workaround allows the test suite for the inprocess module to complete.
544 541 if not 'IPython.kernel.inprocess' in sys.argv:
545 542 globalipapp.start_ipython()
546 543
547 544 # Now nose can run
548 545 TestProgram(argv=argv, addplugins=plugins)
549 546
550 547 def do_run(x):
551 548 print('IPython test group:',x[0])
552 549 ret = x[1].run()
553 550 return ret
554 551
555 552 def run_iptestall(inc_slow=False, fast=False):
556 553 """Run the entire IPython test suite by calling nose and trial.
557 554
558 555 This function constructs :class:`IPTester` instances for all IPython
559 556 modules and package and then runs each of them. This causes the modules
560 557 and packages of IPython to be tested each in their own subprocess using
561 558 nose.
562 559
563 560 Parameters
564 561 ----------
565 562
566 563 inc_slow : bool, optional
567 564 Include slow tests, like IPython.parallel. By default, these tests aren't
568 565 run.
569 566
570 567 fast : bool, option
571 568 Run the test suite in parallel, if True, using as many threads as there
572 569 are processors
573 570 """
574 571 if fast:
575 572 p = multiprocessing.pool.ThreadPool()
576 573 else:
577 574 p = multiprocessing.pool.ThreadPool(1)
578 575
579 576 runners = make_runners(inc_slow=inc_slow)
580 577
581 578 # Run the test runners in a temporary dir so we can nuke it when finished
582 579 # to clean up any junk files left over by accident. This also makes it
583 580 # robust against being run in non-writeable directories by mistake, as the
584 581 # temp dir will always be user-writeable.
585 582 curdir = os.getcwdu()
586 583 testdir = tempfile.gettempdir()
587 584 os.chdir(testdir)
588 585
589 586 # Run all test runners, tracking execution time
590 587 failed = []
591 588 t_start = time.time()
592 589
593 #runners = runners[::-1]
594
595 print([r[0] for r in runners])
596
597 590 try:
598
599 print(len(runners))
600 591 all_res = p.map(do_run, runners)
601 592 print('*'*70)
602 593 for ((name, runner), res) in zip(runners, all_res):
603 594 print(' '*70)
604 595 tgroup = 'IPython test group: ' + name
605 596 res_string = 'OK' if res == 0 else 'FAILED'
606 597 res_string = res_string.rjust(70 - len(tgroup), '.')
607 598 print(tgroup + res_string)
608 599 if res:
609 600 failed.append( (name, runner) )
610 601 if res == -signal.SIGINT:
611 602 print("Interrupted")
612 603 break
613 604 finally:
614 605 os.chdir(curdir)
615 606 t_end = time.time()
616 607 t_tests = t_end - t_start
617 608 nrunners = len(runners)
618 609 nfail = len(failed)
619 610 # summarize results
620 611 print()
621 612 print('*'*70)
622 613 print('Test suite completed for system with the following information:')
623 614 print(report())
624 615 print('Ran %s test groups in %.3fs' % (nrunners, t_tests))
625 616 print()
626 617 print('Status:')
627 618 if not failed:
628 619 print('OK')
629 620 else:
630 621 # If anything went wrong, point out what command to rerun manually to
631 622 # see the actual errors and individual summary
632 623 print('ERROR - %s out of %s test groups failed.' % (nfail, nrunners))
633 624 for name, failed_runner in failed:
634 625 print('-'*40)
635 626 print('Runner failed:',name)
636 627 print('You may wish to rerun this one individually, with:')
637 628 failed_call_args = [py3compat.cast_unicode(x) for x in failed_runner.call_args]
638 629 print(u' '.join(failed_call_args))
639 630 print()
640 631 # Ensure that our exit code indicates failure
641 632 sys.exit(1)
642 633
643 634
644 635 def main():
645 636 for arg in sys.argv[1:]:
646 637 if arg.startswith('IPython') or arg in special_test_suites:
647 638 # This is in-process
648 639 run_iptest()
649 640 else:
650 641 inc_slow = "--all" in sys.argv
651 642 if inc_slow:
652 643 sys.argv.remove("--all")
653 644
654 645 fast = "--fast" in sys.argv
655 646 if fast:
656 647 sys.argv.remove("--fast")
657 648 IPTester.buffer_output = True
658 649
659 650 # This starts subprocesses
660 651 run_iptestall(inc_slow=inc_slow, fast=fast)
661 652
662 653
663 654 if __name__ == '__main__':
664 655 main()
General Comments 0
You need to be logged in to leave comments. Login now