From f82dc4259361bb563029f9c0205b8a8bd468fd4c 2009-04-24 17:12:50 From: Brian Granger Date: 2009-04-24 17:12:50 Subject: [PATCH] Refactored iptest to include the iptestall capabilities. We not have a test suite that can be run with `iptest all`. Give it a shot! --- diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 6bdf251..ecad646 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -1,31 +1,39 @@ # -*- coding: utf-8 -*- """IPython Test Suite Runner. -This module provides a main entry point to a user script to test IPython itself -from the command line. The main() routine can be used in a similar manner to -the ``nosetests`` script, and it takes similar arguments, but if no arguments -are given it defaults to testing all of IPython. This should be preferred to -using plain ``nosetests`` because a number of nose plugins necessary to test -IPython correctly are automatically configured by this code. +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. """ #----------------------------------------------------------------------------- # Module imports #----------------------------------------------------------------------------- -# stdlib +import os +import os.path as path import sys +import subprocess +import time import warnings -# third-party import nose.plugins.builtin from nose.core import TestProgram -# Our own imports from IPython.testing.plugin.ipdoctest import IPythonDoctest #----------------------------------------------------------------------------- -# Constants and globals +# Globals and constants #----------------------------------------------------------------------------- # For the IPythonDoctest plugin, we need to exclude certain patterns that cause @@ -50,8 +58,12 @@ EXCLUDE = ['IPython/external/', # Functions and classes #----------------------------------------------------------------------------- -def main(): - """Run the IPython test suite. +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. """ warnings.filterwarnings('ignore', @@ -101,3 +113,132 @@ def main(): plugins.append(plug) TestProgram(argv=argv,plugins=plugins) + + +class IPTester(object): + """Call that calls iptest or trial in a subprocess. + """ + def __init__(self,runner='iptest',params=None): + """ """ + if runner == 'iptest': + self.runner = ['iptest','-v'] + else: + self.runner = ['trial'] + if params is None: + params = [] + if isinstance(params,str): + params = [params] + self.params = params + + # Assemble call + self.call_args = self.runner+self.params + + def run(self): + """Run the stored commands""" + return subprocess.call(self.call_args) + + +def make_runners(): + """Define the modules and packages that need to be tested. + """ + + # This omits additional top-level modules that should not be doctested. + # XXX: Shell.py is also ommited because of a bug in the skip_doctest + # decorator. See ticket https://bugs.launchpad.net/bugs/366209 + top_mod = \ + ['background_jobs.py', 'ColorANSI.py', 'completer.py', 'ConfigLoader.py', + 'CrashHandler.py', 'Debugger.py', 'deep_reload.py', 'demo.py', + 'DPyGetOpt.py', 'dtutils.py', 'excolors.py', 'FakeModule.py', + 'generics.py', 'genutils.py', 'history.py', 'hooks.py', 'ipapi.py', + 'iplib.py', 'ipmaker.py', 'ipstruct.py', 'irunner.py', 'Itpl.py', + 'Logger.py', 'macro.py', 'Magic.py', 'OInspect.py', + 'OutputTrap.py', 'platutils.py', 'prefilter.py', 'Prompts.py', + 'PyColorize.py', 'Release.py', 'rlineimpl.py', 'shadowns.py', + 'shellglobals.py', 'strdispatch.py', 'twshell.py', + 'ultraTB.py', 'upgrade_dir.py', 'usage.py', 'wildcard.py', + # See note above for why this is skipped + # 'Shell.py', + 'winconsole.py'] + + if os.name == 'posix': + top_mod.append('platutils_posix.py') + elif sys.platform == 'win32': + top_mod.append('platutils_win32.py') + else: + top_mod.append('platutils_dummy.py') + + top_pack = ['config','Extensions','frontend','gui','kernel', + 'testing','tests','tools','UserConfig'] + + modules = ['IPython.%s' % m[:-3] for m in top_mod ] + packages = ['IPython.%s' % m for m in top_pack ] + + # Make runners + runners = dict(zip(top_pack, [IPTester(params=v) for v in packages])) + + try: + import zope.interface + import twisted + import foolscap + except ImportError: + pass + else: + runners['trial'] = IPTester('trial',['IPython']) + + for m in modules: + runners[m] = IPTester(params=m) + + return runners + + +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. + """ + runners = make_runners() + # Run all test runners, tracking execution time + failed = {} + t_start = time.time() + for name,runner in runners.iteritems(): + print '*'*77 + print 'IPython test set:',name + res = runner.run() + if res: + failed[name] = res + t_end = time.time() + t_tests = t_end - t_start + nrunners = len(runners) + nfail = len(failed) + # summarize results + print + print '*'*77 + print 'Ran %s test sets in %.3fs' % (nrunners, t_tests) + 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 + print 'ERROR - %s out of %s test sets failed.' % (nfail, nrunners) + for name in failed: + failed_runner = runners[name] + 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(): + if sys.argv[1] == 'all': + run_iptestall() + else: + run_iptest() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/IPython/testing/iptestall.py b/IPython/testing/iptestall.py deleted file mode 100755 index 297007e..0000000 --- a/IPython/testing/iptestall.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python -"""Master test runner for IPython - EXPERIMENTAL CODE!!! - -This tries - -XXX - Big limitation right now: we don't summarize the total test counts. That -would require parsing the output of the subprocesses. -""" -import os.path as path -import subprocess as subp -import time - -class IPTester(object): - """Object to call iptest with specific parameters. - """ - def __init__(self,runner='iptest',params=None): - """ """ - if runner == 'iptest': - self.runner = ['iptest','-v'] - else: - self.runner = ['trial'] - if params is None: - params = [] - if isinstance(params,str): - params = [params] - self.params = params - - # Assemble call - self.call_args = self.runner+self.params - - def run(self): - """Run the stored commands""" - return subp.call(self.call_args) - - -def make_runners(): - top_mod = \ - ['background_jobs.py', 'ColorANSI.py', 'completer.py', 'ConfigLoader.py', - 'CrashHandler.py', 'Debugger.py', 'deep_reload.py', 'demo.py', - 'DPyGetOpt.py', 'dtutils.py', 'excolors.py', 'FakeModule.py', - 'generics.py', 'genutils.py', 'Gnuplot2.py', 'GnuplotInteractive.py', - 'GnuplotRuntime.py', 'history.py', 'hooks.py', 'ipapi.py', - 'iplib.py', 'ipmaker.py', 'ipstruct.py', 'irunner.py', 'Itpl.py', - 'Logger.py', 'macro.py', 'Magic.py', 'numutils.py', 'OInspect.py', - 'OutputTrap.py', 'platutils_dummy.py', 'platutils_posix.py', - 'platutils.py', 'platutils_win32.py', 'prefilter.py', 'Prompts.py', - 'PyColorize.py', 'Release.py', 'rlineimpl.py', 'shadowns.py', - 'shellglobals.py', 'Shell.py', 'strdispatch.py', 'twshell.py', - 'ultraTB.py', 'upgrade_dir.py', 'usage.py', 'wildcard.py', - 'winconsole.py'] - - top_pack = ['config','Extensions','frontend','gui','kernel', - 'testing','tests','tools','UserConfig'] - - modules = ['IPython.%s' % m for m in top_mod ] - packages = ['IPython.%s' % m for m in top_pack ] - - # Make runners - runners = dict(zip(top_pack, [IPTester(params=v) for v in packages])) - runners['trial'] = IPTester('trial',['IPython']) - - return runners - - -def main(): - runners = make_runners() - # Run all test runners, tracking execution time - failed = {} - t_start = time.time() - for name,runner in runners.iteritems(): - print '*'*77 - print 'IPython test set:',name - res = runner.run() - if res: - failed[name] = res - t_end = time.time() - t_tests = t_end - t_start - nrunners = len(runners) - nfail = len(failed) - # summarize results - print - print '*'*77 - print 'Ran %s test sets in %.3fs' % (nrunners, t_tests) - 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 - print 'ERROR - %s out of %s test sets failed.' % (nfail, nrunners) - for name in failed: - failed_runner = runners[name] - print '-'*40 - print 'Runner failed:',name - print 'You may wish to rerun this one individually, with:' - print ' '.join(failed_runner.call_args) - print - - -if __name__ == '__main__': - main()