2008-08-24 14:37:40 +08:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""IPython Test Suite Runner.
|
2009-03-11 13:49:08 +08:00
|
|
|
|
2009-04-25 01:12:50 +08:00
|
|
|
This module provides a main entry point to a user script to test IPython
|
|
|
|
itself from the command line. There are two ways of running this script:
|
|
|
|
|
|
|
|
1. With the syntax `iptest all`. This runs our entire test suite by
|
|
|
|
calling this script (with different arguments) or trial recursively. This
|
|
|
|
causes modules and package to be tested in different processes, using nose
|
|
|
|
or trial where appropriate.
|
|
|
|
2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
|
|
|
|
the script simply calls nose, but with special command line flags and
|
|
|
|
plugins loaded.
|
|
|
|
|
|
|
|
For now, this script requires that both nose and twisted are installed. This
|
|
|
|
will change in the future.
|
2008-08-24 14:37:40 +08:00
|
|
|
"""
|
|
|
|
|
2009-03-11 13:49:08 +08:00
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
# Module imports
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
2010-01-13 04:42:23 +08:00
|
|
|
# Stdlib
|
2009-04-25 01:12:50 +08:00
|
|
|
import os
|
|
|
|
import os.path as path
|
2010-01-08 08:47:46 +08:00
|
|
|
import signal
|
2008-08-24 14:37:40 +08:00
|
|
|
import sys
|
2009-04-25 01:12:50 +08:00
|
|
|
import subprocess
|
2009-08-02 08:08:32 +08:00
|
|
|
import tempfile
|
2009-04-25 01:12:50 +08:00
|
|
|
import time
|
2008-08-24 14:37:40 +08:00
|
|
|
import warnings
|
|
|
|
|
2010-01-15 18:00:11 +08:00
|
|
|
|
|
|
|
# Ugly, but necessary hack to ensure the test suite finds our version of
|
|
|
|
# IPython and not a possibly different one that may exist system-wide.
|
|
|
|
# Note that this must be done here, so the imports that come next work
|
|
|
|
# correctly even if IPython isn't installed yet.
|
|
|
|
p = os.path
|
|
|
|
ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
|
|
|
|
sys.path.insert(0, ippath)
|
|
|
|
#print 'ipp:', ippath # dbg
|
|
|
|
#import IPython; print 'IP file:', IPython.__file__ # dbg
|
|
|
|
|
2010-01-13 04:42:23 +08:00
|
|
|
# Note: monkeypatch!
|
|
|
|
# We need to monkeypatch a small problem in nose itself first, before importing
|
|
|
|
# it for actual use. This should get into nose upstream, but its release cycle
|
|
|
|
# is slow and we need it for our parametric tests to work correctly.
|
2010-01-15 17:06:34 +08:00
|
|
|
from IPython.testing import nosepatch
|
2010-01-13 04:42:23 +08:00
|
|
|
# Now, proceed to import nose itself
|
2008-08-24 14:37:40 +08:00
|
|
|
import nose.plugins.builtin
|
2009-03-11 13:49:08 +08:00
|
|
|
from nose.core import TestProgram
|
2008-08-24 14:37:40 +08:00
|
|
|
|
2010-01-13 04:42:23 +08:00
|
|
|
# Our own imports
|
2010-01-08 08:04:08 +08:00
|
|
|
from IPython.utils import genutils
|
|
|
|
from IPython.utils.platutils import find_cmd, FindCmdError
|
2010-01-15 17:06:34 +08:00
|
|
|
from IPython.testing import globalipapp
|
|
|
|
from IPython.testing import tools
|
|
|
|
from IPython.testing.plugin.ipdoctest import IPythonDoctest
|
2008-08-24 14:37:40 +08:00
|
|
|
|
2009-04-26 00:04:56 +08:00
|
|
|
pjoin = path.join
|
|
|
|
|
2010-01-08 08:04:08 +08:00
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
# Warnings control
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
# Twisted generates annoying warnings with Python 2.6, as will do other code
|
|
|
|
# that imports 'sets' as of today
|
|
|
|
warnings.filterwarnings('ignore', 'the sets module is deprecated',
|
|
|
|
DeprecationWarning )
|
|
|
|
|
2010-01-13 15:21:21 +08:00
|
|
|
# This one also comes from Twisted
|
|
|
|
warnings.filterwarnings('ignore', 'the sha module is deprecated',
|
|
|
|
DeprecationWarning)
|
|
|
|
|
2010-01-16 06:41:10 +08:00
|
|
|
# Wx on Fedora11 spits these out
|
|
|
|
warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
|
|
|
|
UserWarning)
|
|
|
|
|
2009-03-11 13:49:08 +08:00
|
|
|
#-----------------------------------------------------------------------------
|
2009-04-26 03:27:03 +08:00
|
|
|
# Logic for skipping doctests
|
2009-03-11 13:49:08 +08:00
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
2009-04-26 03:27:03 +08:00
|
|
|
def test_for(mod):
|
|
|
|
"""Test to see if mod is importable."""
|
|
|
|
try:
|
|
|
|
__import__(mod)
|
|
|
|
except ImportError:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
|
2010-01-13 09:39:42 +08:00
|
|
|
|
2009-04-26 03:27:03 +08:00
|
|
|
have_curses = test_for('_curses')
|
|
|
|
have_wx = test_for('wx')
|
2009-07-29 17:13:26 +08:00
|
|
|
have_wx_aui = test_for('wx.aui')
|
2009-04-26 03:27:03 +08:00
|
|
|
have_zi = test_for('zope.interface')
|
|
|
|
have_twisted = test_for('twisted')
|
|
|
|
have_foolscap = test_for('foolscap')
|
|
|
|
have_objc = test_for('objc')
|
|
|
|
have_pexpect = test_for('pexpect')
|
2009-07-28 06:52:00 +08:00
|
|
|
have_gtk = test_for('gtk')
|
|
|
|
have_gobject = test_for('gobject')
|
2009-04-26 03:27:03 +08:00
|
|
|
|
2009-04-26 01:05:09 +08:00
|
|
|
|
2009-07-28 06:38:27 +08:00
|
|
|
def make_exclude():
|
2010-01-13 09:36:00 +08:00
|
|
|
"""Make patterns of modules and packages to exclude from testing.
|
|
|
|
|
|
|
|
For the IPythonDoctest plugin, we need to exclude certain patterns that
|
|
|
|
cause testing problems. We should strive to minimize the number of
|
|
|
|
skipped modules, since this means untested code. As the testing
|
|
|
|
machinery solidifies, this list should eventually become empty.
|
|
|
|
These modules and packages will NOT get scanned by nose at all for tests.
|
|
|
|
"""
|
|
|
|
# Simple utility to make IPython paths more readably, we need a lot of
|
|
|
|
# these below
|
|
|
|
ipjoin = lambda *paths: pjoin('IPython', *paths)
|
|
|
|
|
|
|
|
exclusions = [ipjoin('external'),
|
|
|
|
ipjoin('frontend', 'process', 'winprocess.py'),
|
2010-01-15 18:00:11 +08:00
|
|
|
# Deprecated old Shell and iplib modules, skip to avoid
|
|
|
|
# warnings
|
|
|
|
ipjoin('Shell'),
|
|
|
|
ipjoin('iplib'),
|
2010-01-10 09:55:56 +08:00
|
|
|
pjoin('IPython_doctest_plugin'),
|
2010-01-13 09:36:00 +08:00
|
|
|
ipjoin('quarantine'),
|
|
|
|
ipjoin('deathrow'),
|
|
|
|
ipjoin('testing', 'attic'),
|
2010-01-13 15:21:21 +08:00
|
|
|
# This guy is probably attic material
|
2010-01-13 09:36:00 +08:00
|
|
|
ipjoin('testing', 'mkdoctests'),
|
2010-01-13 15:21:21 +08:00
|
|
|
# Testing inputhook will need a lot of thought, to figure out
|
|
|
|
# how to have tests that don't lock up with the gui event
|
|
|
|
# loops in the picture
|
2010-01-13 09:36:00 +08:00
|
|
|
ipjoin('lib', 'inputhook'),
|
2010-01-10 09:55:56 +08:00
|
|
|
# Config files aren't really importable stand-alone
|
2010-01-13 09:36:00 +08:00
|
|
|
ipjoin('config', 'default'),
|
|
|
|
ipjoin('config', 'profile'),
|
2010-01-10 09:55:56 +08:00
|
|
|
]
|
2009-07-28 06:38:27 +08:00
|
|
|
|
|
|
|
if not have_wx:
|
2010-01-13 09:36:00 +08:00
|
|
|
exclusions.append(ipjoin('gui'))
|
|
|
|
exclusions.append(ipjoin('frontend', 'wx'))
|
|
|
|
exclusions.append(ipjoin('lib', 'inputhookwx'))
|
2009-07-28 06:52:00 +08:00
|
|
|
|
|
|
|
if not have_gtk or not have_gobject:
|
2010-01-13 09:36:00 +08:00
|
|
|
exclusions.append(ipjoin('lib', 'inputhookgtk'))
|
2009-07-28 06:38:27 +08:00
|
|
|
|
2009-08-04 03:50:56 +08:00
|
|
|
if not have_wx_aui:
|
2010-01-13 09:36:00 +08:00
|
|
|
exclusions.append(ipjoin('gui', 'wx', 'wxIPython'))
|
2009-08-04 03:50:56 +08:00
|
|
|
|
2009-07-28 06:38:27 +08:00
|
|
|
if not have_objc:
|
2010-01-13 09:36:00 +08:00
|
|
|
exclusions.append(ipjoin('frontend', 'cocoa'))
|
2009-07-28 06:38:27 +08:00
|
|
|
|
|
|
|
if not sys.platform == 'win32':
|
2010-01-13 09:36:00 +08:00
|
|
|
exclusions.append(ipjoin('utils', 'platutils_win32'))
|
2009-07-28 06:38:27 +08:00
|
|
|
|
|
|
|
# These have to be skipped on win32 because the use echo, rm, cd, etc.
|
|
|
|
# See ticket https://bugs.launchpad.net/bugs/366982
|
|
|
|
if sys.platform == 'win32':
|
2010-01-13 09:36:00 +08:00
|
|
|
exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
|
|
|
|
exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
|
2009-07-28 06:38:27 +08:00
|
|
|
|
|
|
|
if not os.name == 'posix':
|
2010-01-13 09:36:00 +08:00
|
|
|
exclusions.append(ipjoin('utils', 'platutils_posix'))
|
2009-07-28 06:38:27 +08:00
|
|
|
|
|
|
|
if not have_pexpect:
|
2010-01-13 09:39:42 +08:00
|
|
|
exclusions.extend([ipjoin('scripts', 'irunner'),
|
|
|
|
ipjoin('lib', 'irunner')])
|
2009-07-28 06:38:27 +08:00
|
|
|
|
2009-08-05 00:50:23 +08:00
|
|
|
# This is scary. We still have things in frontend and testing that
|
|
|
|
# are being tested by nose that use twisted. We need to rethink
|
|
|
|
# how we are isolating dependencies in testing.
|
|
|
|
if not (have_twisted and have_zi and have_foolscap):
|
2010-01-13 09:36:00 +08:00
|
|
|
exclusions.extend(
|
|
|
|
[ipjoin('frontend', 'asyncfrontendbase'),
|
|
|
|
ipjoin('frontend', 'prefilterfrontend'),
|
|
|
|
ipjoin('frontend', 'frontendbase'),
|
|
|
|
ipjoin('frontend', 'linefrontendbase'),
|
|
|
|
ipjoin('frontend', 'tests', 'test_linefrontend'),
|
|
|
|
ipjoin('frontend', 'tests', 'test_frontendbase'),
|
|
|
|
ipjoin('frontend', 'tests', 'test_prefilterfrontend'),
|
|
|
|
ipjoin('frontend', 'tests', 'test_asyncfrontendbase'),
|
|
|
|
ipjoin('testing', 'parametric'),
|
|
|
|
ipjoin('testing', 'util'),
|
|
|
|
ipjoin('testing', 'tests', 'test_decorators_trial'),
|
|
|
|
] )
|
2009-08-05 00:50:23 +08:00
|
|
|
|
2009-07-28 06:38:27 +08:00
|
|
|
# This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
|
|
|
|
if sys.platform == 'win32':
|
2010-01-10 08:30:59 +08:00
|
|
|
exclusions = [s.replace('\\','\\\\') for s in exclusions]
|
2009-07-28 06:38:27 +08:00
|
|
|
|
2010-01-10 08:30:59 +08:00
|
|
|
return exclusions
|
2009-04-26 01:05:09 +08:00
|
|
|
|
|
|
|
|
2009-03-11 13:49:08 +08:00
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
# Functions and classes
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
2010-01-08 08:04:08 +08:00
|
|
|
class IPTester(object):
|
|
|
|
"""Call that calls iptest or trial in a subprocess.
|
|
|
|
"""
|
2010-01-08 08:47:46 +08:00
|
|
|
#: string, name of test runner that will be called
|
|
|
|
runner = None
|
|
|
|
#: list, parameters for test runner
|
|
|
|
params = None
|
|
|
|
#: list, arguments of system call to be made to call test runner
|
|
|
|
call_args = None
|
|
|
|
#: list, process ids of subprocesses we start (for cleanup)
|
|
|
|
pids = None
|
|
|
|
|
2010-01-15 17:06:34 +08:00
|
|
|
def __init__(self, runner='iptest', params=None):
|
2010-01-08 08:47:46 +08:00
|
|
|
"""Create new test runner."""
|
2010-01-08 08:04:08 +08:00
|
|
|
if runner == 'iptest':
|
2010-01-15 17:06:34 +08:00
|
|
|
# Find our own 'iptest' script OS-level entry point. Don't look
|
|
|
|
# system-wide, so we are sure we pick up *this one*. And pass
|
|
|
|
# through to subprocess call our own sys.argv
|
2010-01-15 18:00:11 +08:00
|
|
|
self.runner = tools.cmd2argv(os.path.abspath(__file__)) + \
|
|
|
|
sys.argv[1:]
|
2010-01-08 08:04:08 +08:00
|
|
|
else:
|
2010-01-13 15:21:21 +08:00
|
|
|
self.runner = tools.cmd2argv(os.path.abspath(find_cmd('trial')))
|
2010-01-08 08:04:08 +08:00
|
|
|
if params is None:
|
|
|
|
params = []
|
2010-01-15 17:06:34 +08:00
|
|
|
if isinstance(params, str):
|
2010-01-08 08:04:08 +08:00
|
|
|
params = [params]
|
|
|
|
self.params = params
|
|
|
|
|
|
|
|
# Assemble call
|
|
|
|
self.call_args = self.runner+self.params
|
|
|
|
|
2010-01-08 08:47:46 +08:00
|
|
|
# Store pids of anything we start to clean up on deletion, if possible
|
|
|
|
# (on posix only, since win32 has no os.kill)
|
|
|
|
self.pids = []
|
|
|
|
|
2010-01-08 08:04:08 +08:00
|
|
|
if sys.platform == 'win32':
|
|
|
|
def _run_cmd(self):
|
|
|
|
# On Windows, use os.system instead of subprocess.call, because I
|
|
|
|
# was having problems with subprocess and I just don't know enough
|
|
|
|
# about win32 to debug this reliably. Os.system may be the 'old
|
|
|
|
# fashioned' way to do it, but it works just fine. If someone
|
|
|
|
# later can clean this up that's fine, as long as the tests run
|
|
|
|
# reliably in win32.
|
|
|
|
return os.system(' '.join(self.call_args))
|
|
|
|
else:
|
|
|
|
def _run_cmd(self):
|
2010-01-08 08:47:46 +08:00
|
|
|
subp = subprocess.Popen(self.call_args)
|
|
|
|
self.pids.append(subp.pid)
|
|
|
|
# If this fails, the pid will be left in self.pids and cleaned up
|
|
|
|
# later, but if the wait call succeeds, then we can clear the
|
|
|
|
# stored pid.
|
|
|
|
retcode = subp.wait()
|
|
|
|
self.pids.pop()
|
|
|
|
return retcode
|
2010-01-08 08:04:08 +08:00
|
|
|
|
|
|
|
def run(self):
|
|
|
|
"""Run the stored commands"""
|
|
|
|
try:
|
|
|
|
return self._run_cmd()
|
|
|
|
except:
|
|
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
|
|
return 1 # signal failure
|
|
|
|
|
2010-01-08 08:47:46 +08:00
|
|
|
def __del__(self):
|
|
|
|
"""Cleanup on exit by killing any leftover processes."""
|
|
|
|
|
|
|
|
if not hasattr(os, 'kill'):
|
|
|
|
return
|
|
|
|
|
|
|
|
for pid in self.pids:
|
|
|
|
try:
|
|
|
|
print 'Cleaning stale PID:', pid
|
|
|
|
os.kill(pid, signal.SIGKILL)
|
|
|
|
except OSError:
|
|
|
|
# This is just a best effort, if we fail or the process was
|
|
|
|
# really gone, ignore it.
|
2010-01-08 09:39:24 +08:00
|
|
|
pass
|
|
|
|
|
2010-01-08 08:04:08 +08:00
|
|
|
|
|
|
|
def make_runners():
|
|
|
|
"""Define the top-level packages that need to be tested.
|
|
|
|
"""
|
|
|
|
|
2010-01-16 06:41:10 +08:00
|
|
|
# Packages to be tested via nose, that only depend on the stdlib
|
|
|
|
nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
|
|
|
|
'scripts', 'testing', 'utils' ]
|
2010-01-15 17:06:34 +08:00
|
|
|
# The machinery in kernel needs twisted for real testing
|
2010-01-16 06:41:10 +08:00
|
|
|
trial_pkg_names = []
|
2010-01-08 08:04:08 +08:00
|
|
|
|
|
|
|
if have_wx:
|
2010-01-16 06:41:10 +08:00
|
|
|
nose_pkg_names.append('gui')
|
2010-01-08 08:04:08 +08:00
|
|
|
|
|
|
|
# And add twisted ones if conditions are met
|
|
|
|
if have_zi and have_twisted and have_foolscap:
|
2010-01-16 06:41:10 +08:00
|
|
|
# Note that we list the kernel here, though the bulk of it is
|
|
|
|
# twisted-based, because nose picks up doctests that twisted doesn't.
|
|
|
|
nose_pkg_names.append('kernel')
|
|
|
|
trial_pkg_names.append('kernel')
|
|
|
|
|
|
|
|
# For debugging this code, only load quick stuff
|
|
|
|
#nose_pkg_names = ['config', 'utils'] # dbg
|
|
|
|
#trial_pkg_names = [] # dbg
|
|
|
|
|
|
|
|
# Make fully qualified package names prepending 'IPython.' to our name lists
|
|
|
|
nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
|
|
|
|
trial_packages = ['IPython.%s' % m for m in trial_pkg_names ]
|
|
|
|
|
|
|
|
# Make runners
|
|
|
|
runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
|
|
|
|
runners.extend([ (v, IPTester('trial', params=v)) for v in trial_packages ])
|
|
|
|
|
2010-01-08 08:04:08 +08:00
|
|
|
return runners
|
|
|
|
|
|
|
|
|
2009-04-25 01:12:50 +08:00
|
|
|
def run_iptest():
|
|
|
|
"""Run the IPython test suite using nose.
|
|
|
|
|
|
|
|
This function is called when this script is **not** called with the form
|
|
|
|
`iptest all`. It simply calls nose with appropriate command line flags
|
|
|
|
and accepts all of the standard nose arguments.
|
2008-08-24 14:37:40 +08:00
|
|
|
"""
|
|
|
|
|
|
|
|
warnings.filterwarnings('ignore',
|
|
|
|
'This will be removed soon. Use IPython.testing.util instead')
|
|
|
|
|
2010-01-10 08:30:59 +08:00
|
|
|
argv = sys.argv + [ '--detailed-errors',
|
|
|
|
# Loading ipdoctest causes problems with Twisted, but
|
|
|
|
# our test suite runner now separates things and runs
|
|
|
|
# all Twisted tests with trial.
|
|
|
|
'--with-ipdoctest',
|
|
|
|
'--ipdoctest-tests','--ipdoctest-extension=txt',
|
|
|
|
|
2008-11-09 13:54:34 +08:00
|
|
|
# We add --exe because of setuptools' imbecility (it
|
|
|
|
# blindly does chmod +x on ALL files). Nose does the
|
|
|
|
# right thing and it tries to avoid executables,
|
|
|
|
# setuptools unfortunately forces our hand here. This
|
|
|
|
# has been discussed on the distutils list and the
|
|
|
|
# setuptools devs refuse to fix this problem!
|
|
|
|
'--exe',
|
|
|
|
]
|
2008-08-24 14:37:40 +08:00
|
|
|
|
|
|
|
|
2010-01-15 17:06:34 +08:00
|
|
|
# Construct list of plugins, omitting the existing doctest plugin, which
|
|
|
|
# ours replaces (and extends).
|
2010-01-10 08:30:59 +08:00
|
|
|
plugins = [IPythonDoctest(make_exclude())]
|
2008-11-09 13:54:34 +08:00
|
|
|
for p in nose.plugins.builtin.plugins:
|
|
|
|
plug = p()
|
|
|
|
if plug.name == 'doctest':
|
|
|
|
continue
|
|
|
|
plugins.append(plug)
|
|
|
|
|
2010-01-10 08:30:59 +08:00
|
|
|
# We need a global ipython running in this process
|
|
|
|
globalipapp.start_ipython()
|
|
|
|
# Now nose can run
|
2010-01-15 17:06:34 +08:00
|
|
|
TestProgram(argv=argv, plugins=plugins)
|
2009-04-25 01:12:50 +08:00
|
|
|
|
|
|
|
|
|
|
|
def run_iptestall():
|
|
|
|
"""Run the entire IPython test suite by calling nose and trial.
|
|
|
|
|
|
|
|
This function constructs :class:`IPTester` instances for all IPython
|
|
|
|
modules and package and then runs each of them. This causes the modules
|
|
|
|
and packages of IPython to be tested each in their own subprocess using
|
|
|
|
nose or twisted.trial appropriately.
|
|
|
|
"""
|
2009-07-28 06:38:27 +08:00
|
|
|
|
2009-04-25 01:12:50 +08:00
|
|
|
runners = make_runners()
|
2009-07-28 06:38:27 +08:00
|
|
|
|
2010-01-08 08:04:08 +08:00
|
|
|
# Run the test runners in a temporary dir so we can nuke it when finished
|
|
|
|
# to clean up any junk files left over by accident. This also makes it
|
|
|
|
# robust against being run in non-writeable directories by mistake, as the
|
|
|
|
# temp dir will always be user-writeable.
|
|
|
|
curdir = os.getcwd()
|
|
|
|
testdir = tempfile.gettempdir()
|
|
|
|
os.chdir(testdir)
|
|
|
|
|
2009-04-25 01:12:50 +08:00
|
|
|
# Run all test runners, tracking execution time
|
2010-01-15 17:06:34 +08:00
|
|
|
failed = []
|
2009-04-25 01:12:50 +08:00
|
|
|
t_start = time.time()
|
2010-01-08 08:04:08 +08:00
|
|
|
try:
|
2010-01-15 17:06:34 +08:00
|
|
|
for (name, runner) in runners:
|
|
|
|
print '*'*70
|
2010-01-08 08:04:08 +08:00
|
|
|
print 'IPython test group:',name
|
|
|
|
res = runner.run()
|
|
|
|
if res:
|
2010-01-15 17:06:34 +08:00
|
|
|
failed.append( (name, runner) )
|
2010-01-08 08:04:08 +08:00
|
|
|
finally:
|
|
|
|
os.chdir(curdir)
|
2009-04-25 01:12:50 +08:00
|
|
|
t_end = time.time()
|
|
|
|
t_tests = t_end - t_start
|
|
|
|
nrunners = len(runners)
|
|
|
|
nfail = len(failed)
|
|
|
|
# summarize results
|
|
|
|
print
|
2010-01-15 17:06:34 +08:00
|
|
|
print '*'*70
|
2009-07-29 17:13:26 +08:00
|
|
|
print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
|
2009-04-25 01:12:50 +08:00
|
|
|
print
|
|
|
|
if not failed:
|
|
|
|
print 'OK'
|
|
|
|
else:
|
|
|
|
# If anything went wrong, point out what command to rerun manually to
|
|
|
|
# see the actual errors and individual summary
|
2009-07-29 17:13:26 +08:00
|
|
|
print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
|
2010-01-15 17:06:34 +08:00
|
|
|
for name, failed_runner in failed:
|
2009-04-25 01:12:50 +08:00
|
|
|
print '-'*40
|
|
|
|
print 'Runner failed:',name
|
|
|
|
print 'You may wish to rerun this one individually, with:'
|
|
|
|
print ' '.join(failed_runner.call_args)
|
|
|
|
print
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
2010-01-15 17:06:34 +08:00
|
|
|
for arg in sys.argv[1:]:
|
|
|
|
if arg.startswith('IPython'):
|
2010-01-15 18:00:11 +08:00
|
|
|
# This is in-process
|
2009-04-26 07:09:59 +08:00
|
|
|
run_iptest()
|
2010-01-15 17:06:34 +08:00
|
|
|
else:
|
2010-01-15 18:00:11 +08:00
|
|
|
# This starts subprocesses
|
2010-01-15 17:06:34 +08:00
|
|
|
run_iptestall()
|
2009-04-25 01:12:50 +08:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2009-07-29 17:13:26 +08:00
|
|
|
main()
|