diff --git a/IPython/Shell.py b/IPython/Shell.py index a8fe13a..9023fe6 100644 --- a/IPython/Shell.py +++ b/IPython/Shell.py @@ -40,11 +40,12 @@ except ImportError: # IPython imports import IPython from IPython import ultraTB, ipapi +from IPython.Magic import Magic from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no from IPython.iplib import InteractiveShell from IPython.ipmaker import make_IPython -from IPython.Magic import Magic from IPython.ipstruct import Struct +from IPython.testing import decorators as testdec # Globals # global flag to pass around information about Ctrl-C without exceptions @@ -607,7 +608,8 @@ class MatplotlibShellBase: # if a backend switch was performed, reverse it now if self.mpl_use._called: self.matplotlib.rcParams['backend'] = self.mpl_backend - + + @testdec.skip_doctest def magic_run(self,parameter_s=''): Magic.magic_run(self,parameter_s,runner=self.mplot_exec) diff --git a/IPython/frontend/tests/test_process.py b/IPython/frontend/tests/test_process.py index b275dff..d82c635 100644 --- a/IPython/frontend/tests/test_process.py +++ b/IPython/frontend/tests/test_process.py @@ -17,6 +17,7 @@ from time import sleep import sys from IPython.frontend._process import PipedProcess +from IPython.testing import decorators as testdec def test_capture_out(): """ A simple test to see if we can execute a process and get the output. @@ -25,9 +26,11 @@ def test_capture_out(): p = PipedProcess('echo 1', out_callback=s.write, ) p.start() p.join() - assert s.getvalue() == '1\n' - + result = s.getvalue().rstrip() + assert result == '1' +# FIXME +@testdec.skip("This doesn't work under Windows") def test_io(): """ Checks that we can send characters on stdin to the process. """ @@ -40,7 +43,8 @@ def test_io(): sleep(0.1) p.process.stdin.write(test_string) p.join() - assert s.getvalue() == test_string + result = s.getvalue() + assert result == test_string def test_kill(): diff --git a/IPython/kernel/core/tests/test_redirectors.py b/IPython/kernel/core/tests/test_redirectors.py index 68f3c58..f9e57f5 100644 --- a/IPython/kernel/core/tests/test_redirectors.py +++ b/IPython/kernel/core/tests/test_redirectors.py @@ -16,7 +16,10 @@ __docformat__ = "restructuredtext en" import os from cStringIO import StringIO +from IPython.testing import decorators as testdec +# FIXME +@testdec.skip("This doesn't work under Windows") def test_redirector(): """ Checks that the redirector can be used to do synchronous capture. """ @@ -33,9 +36,12 @@ def test_redirector(): r.stop() raise r.stop() - assert out.getvalue() == "".join("%ic\n%i\n" %(i, i) for i in range(10)) - + result1 = out.getvalue() + result2 = "".join("%ic\n%i\n" %(i, i) for i in range(10)) + assert result1 == result2 +# FIXME +@testdec.skip("This doesn't work under Windows") def test_redirector_output_trap(): """ This test check not only that the redirector_output_trap does trap the output, but also that it does it in a gready way, that @@ -54,8 +60,9 @@ def test_redirector_output_trap(): trap.unset() raise trap.unset() - assert out.getvalue() == "".join("%ic\n%ip\n%i\n" %(i, i, i) - for i in range(10)) + result1 = out.getvalue() + result2 = "".join("%ic\n%ip\n%i\n" %(i, i, i) for i in range(10)) + assert result1 == result2 diff --git a/IPython/testing/decorators.py b/IPython/testing/decorators.py index 1a07fe6..78b6840 100644 --- a/IPython/testing/decorators.py +++ b/IPython/testing/decorators.py @@ -120,16 +120,28 @@ skip_doctest = make_label_dec('skip_doctest', omit from testing, while preserving the docstring for introspection, help, etc.""") +def skip(msg=''): + """Decorator - mark a test function for skipping from test suite. -def skip(func): - """Decorator - mark a test function for skipping from test suite.""" + :Parameters: + + func : function + Test function to be skipped + + msg : string + Optional message to be added. + """ import nose - - def wrapper(*a,**k): - raise nose.SkipTest("Skipping test for function: %s" % - func.__name__) - - return apply_wrapper(wrapper,func) + def inner(func): + + def wrapper(*a,**k): + if msg: out = '\n'+msg + else: out = '' + raise nose.SkipTest("Skipping test for function: %s%s" % + (func.__name__,out)) + + return apply_wrapper(wrapper,func) + return inner diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py new file mode 100644 index 0000000..262ef28 --- /dev/null +++ b/IPython/testing/iptest.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""IPython Test Suite Runner. +""" + +import sys +import warnings + +from nose.core import TestProgram +import nose.plugins.builtin + +from IPython.testing.plugin.ipdoctest import IPythonDoctest + +def main(): + """Run the IPython test suite. + """ + + warnings.filterwarnings('ignore', + 'This will be removed soon. Use IPython.testing.util instead') + + + # construct list of plugins, omitting the existing doctest plugin + plugins = [IPythonDoctest()] + for p in nose.plugins.builtin.plugins: + plug = p() + if plug.name == 'doctest': + continue + + #print 'adding plugin:',plug.name # dbg + plugins.append(plug) + + argv = sys.argv + ['--doctest-tests','--doctest-extension=txt', + '--detailed-errors', + + # 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', + ] + + has_ip = False + for arg in sys.argv: + if 'IPython' in arg: + has_ip = True + break + + if not has_ip: + argv.append('IPython') + + TestProgram(argv=argv,plugins=plugins) diff --git a/IPython/testing/plugin/__init__.py b/IPython/testing/plugin/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/IPython/testing/plugin/__init__.py diff --git a/IPython/testing/plugin/ipdoctest.py b/IPython/testing/plugin/ipdoctest.py index 5273781..5971332 100644 --- a/IPython/testing/plugin/ipdoctest.py +++ b/IPython/testing/plugin/ipdoctest.py @@ -658,6 +658,24 @@ class ExtensionDoctest(doctests.Doctest): def options(self, parser, env=os.environ): Plugin.options(self, parser, env) + parser.add_option('--doctest-tests', action='store_true', + dest='doctest_tests', + default=env.get('NOSE_DOCTEST_TESTS',True), + help="Also look for doctests in test modules. " + "Note that classes, methods and functions should " + "have either doctests or non-doctest tests, " + "not both. [NOSE_DOCTEST_TESTS]") + parser.add_option('--doctest-extension', action="append", + dest="doctestExtension", + help="Also look for doctests in files with " + "this extension [NOSE_DOCTEST_EXTENSION]") + # Set the default as a list, if given in env; otherwise + # an additional value set on the command line will cause + # an error. + env_setting = env.get('NOSE_DOCTEST_EXTENSION') + if env_setting is not None: + parser.set_defaults(doctestExtension=tolist(env_setting)) + def configure(self, options, config): Plugin.configure(self, options, config) @@ -743,16 +761,19 @@ class ExtensionDoctest(doctests.Doctest): Modified version that accepts extension modules as valid containers for doctests. """ - #print 'Filename:',filename # dbg + print 'Filename:',filename # dbg # XXX - temporarily hardcoded list, will move to driver later exclude = ['IPython/external/', - 'IPython/Extensions/ipy_', 'IPython/platutils_win32', 'IPython/frontend/cocoa', 'IPython_doctest_plugin', 'IPython/Gnuplot', - 'IPython/Extensions/PhysicalQIn'] + 'IPython/Extensions/ipy_', + 'IPython/Extensions/PhysicalQIn', + 'IPython/Extensions/scitedirector', + 'IPython/testing/plugin', + ] for fex in exclude: if fex in filename: # substring @@ -782,3 +803,4 @@ class IPythonDoctest(ExtensionDoctest): self.checker = IPDoctestOutputChecker() self.globs = None self.extraglobs = None + diff --git a/IPython/testing/plugin/test_refs.py b/IPython/testing/plugin/test_refs.py index 2c6e88b..fc7e6f0 100644 --- a/IPython/testing/plugin/test_refs.py +++ b/IPython/testing/plugin/test_refs.py @@ -45,6 +45,11 @@ def test_deliberately_broken(): """A deliberately broken test - we want to skip this one.""" 1/0 +@dec.skip('foo') +def test_deliberately_broken2(): + """Another deliberately broken test - we want to skip this one.""" + 1/0 + # Verify that we can correctly skip the doctest for a function at will, but # that the docstring itself is NOT destroyed by the decorator. diff --git a/IPython/testing/tutils.py b/IPython/testing/tutils.py index 6a24639..43e7ba9 100644 --- a/IPython/testing/tutils.py +++ b/IPython/testing/tutils.py @@ -9,6 +9,7 @@ Utilities for testing code. # testing machinery from snakeoil that were good have already been merged into # the nose plugin, so this can be taken away soon. Leave a warning for now, # we'll remove it in a later release (around 0.10 or so). + from warnings import warn warn('This will be removed soon. Use IPython.testing.util instead', DeprecationWarning) diff --git a/IPython/ultraTB.py b/IPython/ultraTB.py index f6abbbd..f0f3cb9 100644 --- a/IPython/ultraTB.py +++ b/IPython/ultraTB.py @@ -445,7 +445,8 @@ class ListTB(TBTools): Also lifted nearly verbatim from traceback.py """ - + + have_filedata = False Colors = self.Colors list = [] try: diff --git a/docs/examples/core/extension.py b/docs/examples/core/extension.py deleted file mode 100644 index 61add1b..0000000 --- a/docs/examples/core/extension.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -import IPython.ipapi -ip = IPython.ipapi.get() - -def ${name}_f(self, arg): - r""" Short explanation - - Long explanation, examples - - """ - - # opts,args = self.parse_options(arg,'rx') - # if 'r' in opts: pass - - - -ip.expose_magic("${name}",${name}_f) - - diff --git a/docs/source/development/development.txt b/docs/source/development/development.txt index e4bc727..36ebacb 100644 --- a/docs/source/development/development.txt +++ b/docs/source/development/development.txt @@ -354,8 +354,8 @@ Installation and testing scenarios This section outlines the various scenarios that we need to test before we release an IPython version. These scenarios represent different ways of installing IPython and its dependencies. -Installation scenarios ----------------------- +Installation scenarios under Linux and OS X +------------------------------------------- 1. Install from tarball using `python setup.py install`. a. With only readline+nose dependencies installed. @@ -367,6 +367,12 @@ Installation scenarios ii. Optional dependency sets: `easy_install -f ipython-0.9.beta3-py2.5.egg IPython[kernel,doc,test,security]` b. With all dependencies already installed. +Installation scenarios under Win32 +---------------------------------- + + 1. Install everything from .exe installers + 2. easy_install? + Tests to run for these scenarios -------------------------------- diff --git a/scripts/iptest b/scripts/iptest new file mode 100755 index 0000000..ce230ce --- /dev/null +++ b/scripts/iptest @@ -0,0 +1,8 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""IPython Test Suite Runner. +""" + +from IPython.testing import iptest + +iptest.main() diff --git a/setup.py b/setup.py index 19e3187..59380f4 100755 --- a/setup.py +++ b/setup.py @@ -137,23 +137,22 @@ if 'setuptools' in sys.modules: 'ipcontroller = IPython.kernel.scripts.ipcontroller:main', 'ipengine = IPython.kernel.scripts.ipengine:main', 'ipcluster = IPython.kernel.scripts.ipcluster:main', - 'ipythonx = IPython.frontend.wx.ipythonx:main' + 'ipythonx = IPython.frontend.wx.ipythonx:main', + 'iptest = IPython.testing.iptest:main', ] } - setup_args["extras_require"] = dict( + setup_args['extras_require'] = dict( kernel = [ - "zope.interface>=3.4.1", - "Twisted>=8.0.1", - "foolscap>=0.2.6" + 'zope.interface>=3.4.1', + 'Twisted>=8.0.1', + 'foolscap>=0.2.6' ], - doc=['Sphinx>=0.3','pygments'], + doc='Sphinx>=0.3', test='nose>=0.10.1', - security=["pyOpenSSL>=0.6"] + security='pyOpenSSL>=0.6' ) # Allow setuptools to handle the scripts scripts = [] - # eggs will lack docs, examples - data_files = [] else: # package_data of setuptools was introduced to distutils in 2.4 cfgfiles = filter(isfile, glob('IPython/UserConfig/*')) diff --git a/setupbase.py b/setupbase.py index d3db0cd..228aceb 100644 --- a/setupbase.py +++ b/setupbase.py @@ -115,6 +115,7 @@ def find_packages(): add_package(packages, 'kernel', config=True, tests=True, scripts=True) add_package(packages, 'kernel.core', config=True, tests=True) add_package(packages, 'testing', tests=True) + add_package(packages, 'testing.plugin', tests=False) add_package(packages, 'tools', tests=True) add_package(packages, 'UserConfig') return packages @@ -220,11 +221,12 @@ def find_scripts(): """ scripts = ['IPython/kernel/scripts/ipengine', 'IPython/kernel/scripts/ipcontroller', - 'IPython/kernel/scripts/ipcluster', + 'IPython/kernel/scripts/ipcluster', 'scripts/ipython', 'scripts/ipythonx', 'scripts/pycolor', 'scripts/irunner', + 'scripts/iptest', ] # Script to be run by the windows binary installer after the default setup