aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/ipython/py2/IPython/testing
diff options
context:
space:
mode:
authorMikhail Borisov <borisov.mikhail@gmail.com>2022-02-10 16:45:39 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:39 +0300
commita6a92afe03e02795227d2641b49819b687f088f8 (patch)
treef6984a1d27d5a7ec88a6fdd6e20cd5b7693b6ece /contrib/python/ipython/py2/IPython/testing
parentc6dc8b8bd530985bc4cce0137e9a5de32f1087cb (diff)
downloadydb-a6a92afe03e02795227d2641b49819b687f088f8.tar.gz
Restoring authorship annotation for Mikhail Borisov <borisov.mikhail@gmail.com>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/ipython/py2/IPython/testing')
-rw-r--r--contrib/python/ipython/py2/IPython/testing/__init__.py76
-rw-r--r--contrib/python/ipython/py2/IPython/testing/__main__.py6
-rw-r--r--contrib/python/ipython/py2/IPython/testing/decorators.py740
-rw-r--r--contrib/python/ipython/py2/IPython/testing/globalipapp.py258
-rw-r--r--contrib/python/ipython/py2/IPython/testing/iptest.py856
-rw-r--r--contrib/python/ipython/py2/IPython/testing/iptestcontroller.py1064
-rw-r--r--contrib/python/ipython/py2/IPython/testing/ipunittest.py352
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/Makefile148
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/README.txt78
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/dtexample.py316
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/ipdoctest.py1522
-rwxr-xr-xcontrib/python/ipython/py2/IPython/testing/plugin/iptest.py38
-rwxr-xr-xcontrib/python/ipython/py2/IPython/testing/plugin/setup.py36
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/show_refs.py40
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/simple.py68
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/simplevars.py6
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/test_combo.txt72
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/test_example.txt48
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/test_exampleip.txt60
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/test_ipdoctest.py160
-rw-r--r--contrib/python/ipython/py2/IPython/testing/plugin/test_refs.py92
-rw-r--r--contrib/python/ipython/py2/IPython/testing/skipdoctest.py76
-rw-r--r--contrib/python/ipython/py2/IPython/testing/tools.py892
23 files changed, 3502 insertions, 3502 deletions
diff --git a/contrib/python/ipython/py2/IPython/testing/__init__.py b/contrib/python/ipython/py2/IPython/testing/__init__.py
index 165f503169..6011b39f77 100644
--- a/contrib/python/ipython/py2/IPython/testing/__init__.py
+++ b/contrib/python/ipython/py2/IPython/testing/__init__.py
@@ -1,38 +1,38 @@
-"""Testing support (tools to test IPython itself).
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (C) 2009-2011 The IPython Development Team
-#
-# Distributed under the terms of the BSD License. The full license is in
-# the file COPYING, distributed as part of this software.
-#-----------------------------------------------------------------------------
-
-#-----------------------------------------------------------------------------
-# Functions
-#-----------------------------------------------------------------------------
-
-# User-level entry point for testing
-def test(**kwargs):
- """Run the entire IPython test suite.
-
- Any of the options for run_iptestall() may be passed as keyword arguments.
-
- For example::
-
- IPython.test(testgroups=['lib', 'config', 'utils'], fast=2)
-
- will run those three sections of the test suite, using two processes.
- """
-
- # Do the import internally, so that this function doesn't increase total
- # import time
- from .iptestcontroller import run_iptestall, default_options
- options = default_options()
- for name, val in kwargs.items():
- setattr(options, name, val)
- run_iptestall(options)
-
-# So nose doesn't try to run this as a test itself and we end up with an
-# infinite test loop
-test.__test__ = False
+"""Testing support (tools to test IPython itself).
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2009-2011 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Functions
+#-----------------------------------------------------------------------------
+
+# User-level entry point for testing
+def test(**kwargs):
+ """Run the entire IPython test suite.
+
+ Any of the options for run_iptestall() may be passed as keyword arguments.
+
+ For example::
+
+ IPython.test(testgroups=['lib', 'config', 'utils'], fast=2)
+
+ will run those three sections of the test suite, using two processes.
+ """
+
+ # Do the import internally, so that this function doesn't increase total
+ # import time
+ from .iptestcontroller import run_iptestall, default_options
+ options = default_options()
+ for name, val in kwargs.items():
+ setattr(options, name, val)
+ run_iptestall(options)
+
+# So nose doesn't try to run this as a test itself and we end up with an
+# infinite test loop
+test.__test__ = False
diff --git a/contrib/python/ipython/py2/IPython/testing/__main__.py b/contrib/python/ipython/py2/IPython/testing/__main__.py
index 4b0bb8ba9c..179ec6f699 100644
--- a/contrib/python/ipython/py2/IPython/testing/__main__.py
+++ b/contrib/python/ipython/py2/IPython/testing/__main__.py
@@ -1,3 +1,3 @@
-if __name__ == '__main__':
- from IPython.testing import iptestcontroller
- iptestcontroller.main()
+if __name__ == '__main__':
+ from IPython.testing import iptestcontroller
+ iptestcontroller.main()
diff --git a/contrib/python/ipython/py2/IPython/testing/decorators.py b/contrib/python/ipython/py2/IPython/testing/decorators.py
index c9807ce70e..2fe72f6cae 100644
--- a/contrib/python/ipython/py2/IPython/testing/decorators.py
+++ b/contrib/python/ipython/py2/IPython/testing/decorators.py
@@ -1,384 +1,384 @@
-# -*- coding: utf-8 -*-
-"""Decorators for labeling test objects.
-
-Decorators that merely return a modified version of the original function
-object are straightforward. Decorators that return a new function object need
-to use nose.tools.make_decorator(original_function)(decorator) in returning the
-decorator, in order to preserve metadata such as function name, setup and
-teardown functions and so on - see nose.tools for more information.
-
-This module provides a set of useful decorators meant to be ready to use in
-your own tests. See the bottom of the file for the ready-made ones, and if you
-find yourself writing a new one that may be of generic use, add it here.
-
-Included decorators:
-
-
-Lightweight testing that remains unittest-compatible.
-
-- An @as_unittest decorator can be used to tag any normal parameter-less
- function as a unittest TestCase. Then, both nose and normal unittest will
- recognize it as such. This will make it easier to migrate away from Nose if
- we ever need/want to while maintaining very lightweight tests.
-
-NOTE: This file contains IPython-specific decorators. Using the machinery in
-IPython.external.decorators, we import either numpy.testing.decorators if numpy is
-available, OR use equivalent code in IPython.external._decorators, which
-we've copied verbatim from numpy.
-
-"""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-import sys
-import os
-import tempfile
-import unittest
-import warnings
-
-from decorator import decorator
-
-# Expose the unittest-driven decorators
-from .ipunittest import ipdoctest, ipdocstring
-
-# Grab the numpy-specific decorators which we keep in a file that we
-# occasionally update from upstream: decorators.py is a copy of
-# numpy.testing.decorators, we expose all of it here.
-from IPython.external.decorators import *
-
-# For onlyif_cmd_exists decorator
+# -*- coding: utf-8 -*-
+"""Decorators for labeling test objects.
+
+Decorators that merely return a modified version of the original function
+object are straightforward. Decorators that return a new function object need
+to use nose.tools.make_decorator(original_function)(decorator) in returning the
+decorator, in order to preserve metadata such as function name, setup and
+teardown functions and so on - see nose.tools for more information.
+
+This module provides a set of useful decorators meant to be ready to use in
+your own tests. See the bottom of the file for the ready-made ones, and if you
+find yourself writing a new one that may be of generic use, add it here.
+
+Included decorators:
+
+
+Lightweight testing that remains unittest-compatible.
+
+- An @as_unittest decorator can be used to tag any normal parameter-less
+ function as a unittest TestCase. Then, both nose and normal unittest will
+ recognize it as such. This will make it easier to migrate away from Nose if
+ we ever need/want to while maintaining very lightweight tests.
+
+NOTE: This file contains IPython-specific decorators. Using the machinery in
+IPython.external.decorators, we import either numpy.testing.decorators if numpy is
+available, OR use equivalent code in IPython.external._decorators, which
+we've copied verbatim from numpy.
+
+"""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+import sys
+import os
+import tempfile
+import unittest
+import warnings
+
+from decorator import decorator
+
+# Expose the unittest-driven decorators
+from .ipunittest import ipdoctest, ipdocstring
+
+# Grab the numpy-specific decorators which we keep in a file that we
+# occasionally update from upstream: decorators.py is a copy of
+# numpy.testing.decorators, we expose all of it here.
+from IPython.external.decorators import *
+
+# For onlyif_cmd_exists decorator
from IPython.utils.py3compat import string_types, which, PY2, PY3, PYPY
-
-#-----------------------------------------------------------------------------
-# Classes and functions
-#-----------------------------------------------------------------------------
-
-# Simple example of the basic idea
-def as_unittest(func):
- """Decorator to make a simple function into a normal test via unittest."""
- class Tester(unittest.TestCase):
- def test(self):
- func()
-
- Tester.__name__ = func.__name__
-
- return Tester
-
-# Utility functions
-
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+# Simple example of the basic idea
+def as_unittest(func):
+ """Decorator to make a simple function into a normal test via unittest."""
+ class Tester(unittest.TestCase):
+ def test(self):
+ func()
+
+ Tester.__name__ = func.__name__
+
+ return Tester
+
+# Utility functions
+
def apply_wrapper(wrapper, func):
- """Apply a wrapper to a function for decoration.
-
- This mixes Michele Simionato's decorator tool with nose's make_decorator,
- to apply a wrapper in a decorator so that all nose attributes, as well as
- function signature and other properties, survive the decoration cleanly.
- This will ensure that wrapped functions can still be well introspected via
- IPython, for example.
- """
+ """Apply a wrapper to a function for decoration.
+
+ This mixes Michele Simionato's decorator tool with nose's make_decorator,
+ to apply a wrapper in a decorator so that all nose attributes, as well as
+ function signature and other properties, survive the decoration cleanly.
+ This will ensure that wrapped functions can still be well introspected via
+ IPython, for example.
+ """
warnings.warn("The function `apply_wrapper` is deprecated since IPython 4.0",
DeprecationWarning, stacklevel=2)
- import nose.tools
-
- return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
-
-
+ import nose.tools
+
+ return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
+
+
def make_label_dec(label, ds=None):
- """Factory function to create a decorator that applies one or more labels.
-
- Parameters
- ----------
- label : string or sequence
- One or more labels that will be applied by the decorator to the functions
- it decorates. Labels are attributes of the decorated function with their
- value set to True.
-
- ds : string
- An optional docstring for the resulting decorator. If not given, a
- default docstring is auto-generated.
-
- Returns
- -------
- A decorator.
-
- Examples
- --------
-
- A simple labeling decorator:
-
- >>> slow = make_label_dec('slow')
- >>> slow.__doc__
- "Labels a test as 'slow'."
-
- And one that uses multiple labels and a custom docstring:
-
- >>> rare = make_label_dec(['slow','hard'],
- ... "Mix labels 'slow' and 'hard' for rare tests.")
- >>> rare.__doc__
- "Mix labels 'slow' and 'hard' for rare tests."
-
- Now, let's test using this one:
- >>> @rare
- ... def f(): pass
- ...
- >>>
- >>> f.slow
- True
- >>> f.hard
- True
- """
-
+ """Factory function to create a decorator that applies one or more labels.
+
+ Parameters
+ ----------
+ label : string or sequence
+ One or more labels that will be applied by the decorator to the functions
+ it decorates. Labels are attributes of the decorated function with their
+ value set to True.
+
+ ds : string
+ An optional docstring for the resulting decorator. If not given, a
+ default docstring is auto-generated.
+
+ Returns
+ -------
+ A decorator.
+
+ Examples
+ --------
+
+ A simple labeling decorator:
+
+ >>> slow = make_label_dec('slow')
+ >>> slow.__doc__
+ "Labels a test as 'slow'."
+
+ And one that uses multiple labels and a custom docstring:
+
+ >>> rare = make_label_dec(['slow','hard'],
+ ... "Mix labels 'slow' and 'hard' for rare tests.")
+ >>> rare.__doc__
+ "Mix labels 'slow' and 'hard' for rare tests."
+
+ Now, let's test using this one:
+ >>> @rare
+ ... def f(): pass
+ ...
+ >>>
+ >>> f.slow
+ True
+ >>> f.hard
+ True
+ """
+
warnings.warn("The function `make_label_dec` is deprecated since IPython 4.0",
DeprecationWarning, stacklevel=2)
- if isinstance(label, string_types):
- labels = [label]
- else:
- labels = label
-
- # Validate that the given label(s) are OK for use in setattr() by doing a
- # dry run on a dummy function.
- tmp = lambda : None
- for label in labels:
- setattr(tmp,label,True)
-
- # This is the actual decorator we'll return
- def decor(f):
- for label in labels:
- setattr(f,label,True)
- return f
-
- # Apply the user's docstring, or autogenerate a basic one
- if ds is None:
- ds = "Labels a test as %r." % label
- decor.__doc__ = ds
-
- return decor
-
-
-# Inspired by numpy's skipif, but uses the full apply_wrapper utility to
-# preserve function metadata better and allows the skip condition to be a
-# callable.
-def skipif(skip_condition, msg=None):
- ''' Make function raise SkipTest exception if skip_condition is true
-
- Parameters
- ----------
-
- skip_condition : bool or callable
- Flag to determine whether to skip test. If the condition is a
- callable, it is used at runtime to dynamically make the decision. This
- is useful for tests that may require costly imports, to delay the cost
- until the test suite is actually executed.
- msg : string
- Message to give on raising a SkipTest exception.
-
- Returns
- -------
- decorator : function
- Decorator, which, when applied to a function, causes SkipTest
- to be raised when the skip_condition was True, and the function
- to be called normally otherwise.
-
- Notes
- -----
- You will see from the code that we had to further decorate the
- decorator with the nose.tools.make_decorator function in order to
- transmit function name, and various other metadata.
- '''
-
- def skip_decorator(f):
- # Local import to avoid a hard nose dependency and only incur the
- # import time overhead at actual test-time.
- import nose
-
- # Allow for both boolean or callable skip conditions.
- if callable(skip_condition):
- skip_val = skip_condition
- else:
- skip_val = lambda : skip_condition
-
- def get_msg(func,msg=None):
- """Skip message with information about function being skipped."""
- if msg is None: out = 'Test skipped due to test condition.'
- else: out = msg
- return "Skipping test: %s. %s" % (func.__name__,out)
-
- # We need to define *two* skippers because Python doesn't allow both
- # return with value and yield inside the same function.
- def skipper_func(*args, **kwargs):
- """Skipper for normal test functions."""
- if skip_val():
- raise nose.SkipTest(get_msg(f,msg))
- else:
- return f(*args, **kwargs)
-
- def skipper_gen(*args, **kwargs):
- """Skipper for test generators."""
- if skip_val():
- raise nose.SkipTest(get_msg(f,msg))
- else:
- for x in f(*args, **kwargs):
- yield x
-
- # Choose the right skipper to use when building the actual generator.
- if nose.util.isgenerator(f):
- skipper = skipper_gen
- else:
- skipper = skipper_func
-
- return nose.tools.make_decorator(f)(skipper)
-
- return skip_decorator
-
-# A version with the condition set to true, common case just to attach a message
-# to a skip decorator
-def skip(msg=None):
- """Decorator factory - mark a test function for skipping from test suite.
-
- Parameters
- ----------
- msg : string
- Optional message to be added.
-
- Returns
- -------
- decorator : function
- Decorator, which, when applied to a function, causes SkipTest
- to be raised, with the optional message added.
- """
-
- return skipif(True,msg)
-
-
-def onlyif(condition, msg):
- """The reverse from skipif, see skipif for details."""
-
- if callable(condition):
- skip_condition = lambda : not condition()
- else:
- skip_condition = lambda : not condition
-
- return skipif(skip_condition, msg)
-
-#-----------------------------------------------------------------------------
-# Utility functions for decorators
-def module_not_available(module):
- """Can module be imported? Returns true if module does NOT import.
-
- This is used to make a decorator to skip tests that require module to be
- available, but delay the 'import numpy' to test execution time.
- """
- try:
- mod = __import__(module)
- mod_not_avail = False
- except ImportError:
- mod_not_avail = True
-
- return mod_not_avail
-
-
-def decorated_dummy(dec, name):
- """Return a dummy function decorated with dec, with the given name.
-
- Examples
- --------
- import IPython.testing.decorators as dec
- setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
- """
+ if isinstance(label, string_types):
+ labels = [label]
+ else:
+ labels = label
+
+ # Validate that the given label(s) are OK for use in setattr() by doing a
+ # dry run on a dummy function.
+ tmp = lambda : None
+ for label in labels:
+ setattr(tmp,label,True)
+
+ # This is the actual decorator we'll return
+ def decor(f):
+ for label in labels:
+ setattr(f,label,True)
+ return f
+
+ # Apply the user's docstring, or autogenerate a basic one
+ if ds is None:
+ ds = "Labels a test as %r." % label
+ decor.__doc__ = ds
+
+ return decor
+
+
+# Inspired by numpy's skipif, but uses the full apply_wrapper utility to
+# preserve function metadata better and allows the skip condition to be a
+# callable.
+def skipif(skip_condition, msg=None):
+ ''' Make function raise SkipTest exception if skip_condition is true
+
+ Parameters
+ ----------
+
+ skip_condition : bool or callable
+ Flag to determine whether to skip test. If the condition is a
+ callable, it is used at runtime to dynamically make the decision. This
+ is useful for tests that may require costly imports, to delay the cost
+ until the test suite is actually executed.
+ msg : string
+ Message to give on raising a SkipTest exception.
+
+ Returns
+ -------
+ decorator : function
+ Decorator, which, when applied to a function, causes SkipTest
+ to be raised when the skip_condition was True, and the function
+ to be called normally otherwise.
+
+ Notes
+ -----
+ You will see from the code that we had to further decorate the
+ decorator with the nose.tools.make_decorator function in order to
+ transmit function name, and various other metadata.
+ '''
+
+ def skip_decorator(f):
+ # Local import to avoid a hard nose dependency and only incur the
+ # import time overhead at actual test-time.
+ import nose
+
+ # Allow for both boolean or callable skip conditions.
+ if callable(skip_condition):
+ skip_val = skip_condition
+ else:
+ skip_val = lambda : skip_condition
+
+ def get_msg(func,msg=None):
+ """Skip message with information about function being skipped."""
+ if msg is None: out = 'Test skipped due to test condition.'
+ else: out = msg
+ return "Skipping test: %s. %s" % (func.__name__,out)
+
+ # We need to define *two* skippers because Python doesn't allow both
+ # return with value and yield inside the same function.
+ def skipper_func(*args, **kwargs):
+ """Skipper for normal test functions."""
+ if skip_val():
+ raise nose.SkipTest(get_msg(f,msg))
+ else:
+ return f(*args, **kwargs)
+
+ def skipper_gen(*args, **kwargs):
+ """Skipper for test generators."""
+ if skip_val():
+ raise nose.SkipTest(get_msg(f,msg))
+ else:
+ for x in f(*args, **kwargs):
+ yield x
+
+ # Choose the right skipper to use when building the actual generator.
+ if nose.util.isgenerator(f):
+ skipper = skipper_gen
+ else:
+ skipper = skipper_func
+
+ return nose.tools.make_decorator(f)(skipper)
+
+ return skip_decorator
+
+# A version with the condition set to true, common case just to attach a message
+# to a skip decorator
+def skip(msg=None):
+ """Decorator factory - mark a test function for skipping from test suite.
+
+ Parameters
+ ----------
+ msg : string
+ Optional message to be added.
+
+ Returns
+ -------
+ decorator : function
+ Decorator, which, when applied to a function, causes SkipTest
+ to be raised, with the optional message added.
+ """
+
+ return skipif(True,msg)
+
+
+def onlyif(condition, msg):
+ """The reverse from skipif, see skipif for details."""
+
+ if callable(condition):
+ skip_condition = lambda : not condition()
+ else:
+ skip_condition = lambda : not condition
+
+ return skipif(skip_condition, msg)
+
+#-----------------------------------------------------------------------------
+# Utility functions for decorators
+def module_not_available(module):
+ """Can module be imported? Returns true if module does NOT import.
+
+ This is used to make a decorator to skip tests that require module to be
+ available, but delay the 'import numpy' to test execution time.
+ """
+ try:
+ mod = __import__(module)
+ mod_not_avail = False
+ except ImportError:
+ mod_not_avail = True
+
+ return mod_not_avail
+
+
+def decorated_dummy(dec, name):
+ """Return a dummy function decorated with dec, with the given name.
+
+ Examples
+ --------
+ import IPython.testing.decorators as dec
+ setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
+ """
warnings.warn("The function `decorated_dummy` is deprecated since IPython 4.0",
DeprecationWarning, stacklevel=2)
- dummy = lambda: None
- dummy.__name__ = name
- return dec(dummy)
-
-#-----------------------------------------------------------------------------
-# Decorators for public use
-
-# Decorators to skip certain tests on specific platforms.
-skip_win32 = skipif(sys.platform == 'win32',
- "This test does not run under Windows")
-skip_linux = skipif(sys.platform.startswith('linux'),
- "This test does not run under Linux")
-skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
-
-
-# Decorators to skip tests if not on specific platforms.
-skip_if_not_win32 = skipif(sys.platform != 'win32',
- "This test only runs under Windows")
-skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
- "This test only runs under Linux")
-skip_if_not_osx = skipif(sys.platform != 'darwin',
- "This test only runs under OSX")
-
-
-_x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
- os.environ.get('DISPLAY', '') == '')
-_x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
-
-skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
-
-# not a decorator itself, returns a dummy function to be used as setup
-def skip_file_no_x11(name):
+ dummy = lambda: None
+ dummy.__name__ = name
+ return dec(dummy)
+
+#-----------------------------------------------------------------------------
+# Decorators for public use
+
+# Decorators to skip certain tests on specific platforms.
+skip_win32 = skipif(sys.platform == 'win32',
+ "This test does not run under Windows")
+skip_linux = skipif(sys.platform.startswith('linux'),
+ "This test does not run under Linux")
+skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
+
+
+# Decorators to skip tests if not on specific platforms.
+skip_if_not_win32 = skipif(sys.platform != 'win32',
+ "This test only runs under Windows")
+skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
+ "This test only runs under Linux")
+skip_if_not_osx = skipif(sys.platform != 'darwin',
+ "This test only runs under OSX")
+
+
+_x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
+ os.environ.get('DISPLAY', '') == '')
+_x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
+
+skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
+
+# not a decorator itself, returns a dummy function to be used as setup
+def skip_file_no_x11(name):
warnings.warn("The function `skip_file_no_x11` is deprecated since IPython 4.0",
DeprecationWarning, stacklevel=2)
- return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
-
-# Other skip decorators
-
-# generic skip without module
-skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
-
-skipif_not_numpy = skip_without('numpy')
-
-skipif_not_matplotlib = skip_without('matplotlib')
-
-skipif_not_sympy = skip_without('sympy')
-
-skip_known_failure = knownfailureif(True,'This test is known to fail')
-
-known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
- 'This test is known to fail on Python 3.')
-
+ return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
+
+# Other skip decorators
+
+# generic skip without module
+skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
+
+skipif_not_numpy = skip_without('numpy')
+
+skipif_not_matplotlib = skip_without('matplotlib')
+
+skipif_not_sympy = skip_without('sympy')
+
+skip_known_failure = knownfailureif(True,'This test is known to fail')
+
+known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
+ 'This test is known to fail on Python 3.')
+
cpython2_only = skipif(PY3 or PYPY, "This test only runs on CPython 2.")
-py2_only = skipif(PY3, "This test only runs on Python 2.")
-py3_only = skipif(PY2, "This test only runs on Python 3.")
-
-# A null 'decorator', useful to make more readable code that needs to pick
-# between different decorators based on OS or other conditions
-null_deco = lambda f: f
-
-# Some tests only run where we can use unicode paths. Note that we can't just
-# check os.path.supports_unicode_filenames, which is always False on Linux.
-try:
- f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
-except UnicodeEncodeError:
- unicode_paths = False
-else:
- unicode_paths = True
- f.close()
-
-onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
- "where we can use unicode in filenames."))
-
-
-def onlyif_cmds_exist(*commands):
- """
- Decorator to skip test when at least one of `commands` is not found.
- """
- for cmd in commands:
- if not which(cmd):
- return skip("This test runs only if command '{0}' "
- "is installed".format(cmd))
- return null_deco
-
-def onlyif_any_cmd_exists(*commands):
- """
- Decorator to skip test unless at least one of `commands` is found.
- """
+py2_only = skipif(PY3, "This test only runs on Python 2.")
+py3_only = skipif(PY2, "This test only runs on Python 3.")
+
+# A null 'decorator', useful to make more readable code that needs to pick
+# between different decorators based on OS or other conditions
+null_deco = lambda f: f
+
+# Some tests only run where we can use unicode paths. Note that we can't just
+# check os.path.supports_unicode_filenames, which is always False on Linux.
+try:
+ f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
+except UnicodeEncodeError:
+ unicode_paths = False
+else:
+ unicode_paths = True
+ f.close()
+
+onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
+ "where we can use unicode in filenames."))
+
+
+def onlyif_cmds_exist(*commands):
+ """
+ Decorator to skip test when at least one of `commands` is not found.
+ """
+ for cmd in commands:
+ if not which(cmd):
+ return skip("This test runs only if command '{0}' "
+ "is installed".format(cmd))
+ return null_deco
+
+def onlyif_any_cmd_exists(*commands):
+ """
+ Decorator to skip test unless at least one of `commands` is found.
+ """
warnings.warn("The function `onlyif_any_cmd_exists` is deprecated since IPython 4.0",
DeprecationWarning, stacklevel=2)
- for cmd in commands:
- if which(cmd):
- return null_deco
- return skip("This test runs only if one of the commands {0} "
- "is installed".format(commands))
+ for cmd in commands:
+ if which(cmd):
+ return null_deco
+ return skip("This test runs only if one of the commands {0} "
+ "is installed".format(commands))
diff --git a/contrib/python/ipython/py2/IPython/testing/globalipapp.py b/contrib/python/ipython/py2/IPython/testing/globalipapp.py
index 3983393112..a40702cc67 100644
--- a/contrib/python/ipython/py2/IPython/testing/globalipapp.py
+++ b/contrib/python/ipython/py2/IPython/testing/globalipapp.py
@@ -1,138 +1,138 @@
-"""Global IPython app to support test running.
-
-We must start our own ipython object and heavily muck with it so that all the
-modifications IPython makes to system behavior don't send the doctest machinery
-into a fit. This code should be considered a gross hack, but it gets the job
-done.
-"""
-from __future__ import absolute_import
-from __future__ import print_function
-
+"""Global IPython app to support test running.
+
+We must start our own ipython object and heavily muck with it so that all the
+modifications IPython makes to system behavior don't send the doctest machinery
+into a fit. This code should be considered a gross hack, but it gets the job
+done.
+"""
+from __future__ import absolute_import
+from __future__ import print_function
+
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
-
-import sys
+
+import sys
import warnings
-
-from . import tools
-
-from IPython.core import page
-from IPython.utils import io
-from IPython.utils import py3compat
-from IPython.utils.py3compat import builtin_mod
-from IPython.terminal.interactiveshell import TerminalInteractiveShell
-
-
-class StreamProxy(io.IOStream):
- """Proxy for sys.stdout/err. This will request the stream *at call time*
- allowing for nose's Capture plugin's redirection of sys.stdout/err.
-
- Parameters
- ----------
- name : str
- The name of the stream. This will be requested anew at every call
- """
-
- def __init__(self, name):
+
+from . import tools
+
+from IPython.core import page
+from IPython.utils import io
+from IPython.utils import py3compat
+from IPython.utils.py3compat import builtin_mod
+from IPython.terminal.interactiveshell import TerminalInteractiveShell
+
+
+class StreamProxy(io.IOStream):
+ """Proxy for sys.stdout/err. This will request the stream *at call time*
+ allowing for nose's Capture plugin's redirection of sys.stdout/err.
+
+ Parameters
+ ----------
+ name : str
+ The name of the stream. This will be requested anew at every call
+ """
+
+ def __init__(self, name):
warnings.warn("StreamProxy is deprecated and unused as of IPython 5", DeprecationWarning,
stacklevel=2,
)
- self.name=name
-
- @property
- def stream(self):
- return getattr(sys, self.name)
-
- def flush(self):
- self.stream.flush()
-
-
-def get_ipython():
- # This will get replaced by the real thing once we start IPython below
- return start_ipython()
-
-
-# A couple of methods to override those in the running IPython to interact
-# better with doctest (doctest captures on raw stdout, so we need to direct
-# various types of output there otherwise it will miss them).
-
-def xsys(self, cmd):
- """Replace the default system call with a capturing one for doctest.
- """
- # We use getoutput, but we need to strip it because pexpect captures
- # the trailing newline differently from commands.getoutput
- print(self.getoutput(cmd, split=False, depth=1).rstrip(), end='', file=sys.stdout)
- sys.stdout.flush()
-
-
-def _showtraceback(self, etype, evalue, stb):
- """Print the traceback purely on stdout for doctest to capture it.
- """
- print(self.InteractiveTB.stb2text(stb), file=sys.stdout)
-
-
-def start_ipython():
- """Start a global IPython shell, which we need for IPython-specific syntax.
- """
- global get_ipython
-
- # This function should only ever run once!
- if hasattr(start_ipython, 'already_called'):
- return
- start_ipython.already_called = True
-
- # Store certain global objects that IPython modifies
- _displayhook = sys.displayhook
- _excepthook = sys.excepthook
- _main = sys.modules.get('__main__')
-
- # Create custom argv and namespaces for our IPython to be test-friendly
- config = tools.default_config()
+ self.name=name
+
+ @property
+ def stream(self):
+ return getattr(sys, self.name)
+
+ def flush(self):
+ self.stream.flush()
+
+
+def get_ipython():
+ # This will get replaced by the real thing once we start IPython below
+ return start_ipython()
+
+
+# A couple of methods to override those in the running IPython to interact
+# better with doctest (doctest captures on raw stdout, so we need to direct
+# various types of output there otherwise it will miss them).
+
+def xsys(self, cmd):
+ """Replace the default system call with a capturing one for doctest.
+ """
+ # We use getoutput, but we need to strip it because pexpect captures
+ # the trailing newline differently from commands.getoutput
+ print(self.getoutput(cmd, split=False, depth=1).rstrip(), end='', file=sys.stdout)
+ sys.stdout.flush()
+
+
+def _showtraceback(self, etype, evalue, stb):
+ """Print the traceback purely on stdout for doctest to capture it.
+ """
+ print(self.InteractiveTB.stb2text(stb), file=sys.stdout)
+
+
+def start_ipython():
+ """Start a global IPython shell, which we need for IPython-specific syntax.
+ """
+ global get_ipython
+
+ # This function should only ever run once!
+ if hasattr(start_ipython, 'already_called'):
+ return
+ start_ipython.already_called = True
+
+ # Store certain global objects that IPython modifies
+ _displayhook = sys.displayhook
+ _excepthook = sys.excepthook
+ _main = sys.modules.get('__main__')
+
+ # Create custom argv and namespaces for our IPython to be test-friendly
+ config = tools.default_config()
config.TerminalInteractiveShell.simple_prompt = True
-
- # Create and initialize our test-friendly IPython instance.
- shell = TerminalInteractiveShell.instance(config=config,
- )
-
- # A few more tweaks needed for playing nicely with doctests...
-
- # remove history file
- shell.tempfiles.append(config.HistoryManager.hist_file)
-
- # These traps are normally only active for interactive use, set them
- # permanently since we'll be mocking interactive sessions.
- shell.builtin_trap.activate()
-
- # Modify the IPython system call with one that uses getoutput, so that we
- # can capture subcommands and print them to Python's stdout, otherwise the
- # doctest machinery would miss them.
- shell.system = py3compat.MethodType(xsys, shell)
-
- shell._showtraceback = py3compat.MethodType(_showtraceback, shell)
-
- # IPython is ready, now clean up some global state...
-
- # Deactivate the various python system hooks added by ipython for
- # interactive convenience so we don't confuse the doctest system
- sys.modules['__main__'] = _main
- sys.displayhook = _displayhook
- sys.excepthook = _excepthook
-
- # So that ipython magics and aliases can be doctested (they work by making
- # a call into a global _ip object). Also make the top-level get_ipython
- # now return this without recursively calling here again.
- _ip = shell
- get_ipython = _ip.get_ipython
- builtin_mod._ip = _ip
- builtin_mod.get_ipython = get_ipython
-
- # Override paging, so we don't require user interaction during the tests.
- def nopage(strng, start=0, screen_lines=0, pager_cmd=None):
+
+ # Create and initialize our test-friendly IPython instance.
+ shell = TerminalInteractiveShell.instance(config=config,
+ )
+
+ # A few more tweaks needed for playing nicely with doctests...
+
+ # remove history file
+ shell.tempfiles.append(config.HistoryManager.hist_file)
+
+ # These traps are normally only active for interactive use, set them
+ # permanently since we'll be mocking interactive sessions.
+ shell.builtin_trap.activate()
+
+ # Modify the IPython system call with one that uses getoutput, so that we
+ # can capture subcommands and print them to Python's stdout, otherwise the
+ # doctest machinery would miss them.
+ shell.system = py3compat.MethodType(xsys, shell)
+
+ shell._showtraceback = py3compat.MethodType(_showtraceback, shell)
+
+ # IPython is ready, now clean up some global state...
+
+ # Deactivate the various python system hooks added by ipython for
+ # interactive convenience so we don't confuse the doctest system
+ sys.modules['__main__'] = _main
+ sys.displayhook = _displayhook
+ sys.excepthook = _excepthook
+
+ # So that ipython magics and aliases can be doctested (they work by making
+ # a call into a global _ip object). Also make the top-level get_ipython
+ # now return this without recursively calling here again.
+ _ip = shell
+ get_ipython = _ip.get_ipython
+ builtin_mod._ip = _ip
+ builtin_mod.get_ipython = get_ipython
+
+ # Override paging, so we don't require user interaction during the tests.
+ def nopage(strng, start=0, screen_lines=0, pager_cmd=None):
if isinstance(strng, dict):
strng = strng.get('text/plain', '')
- print(strng)
-
- page.orig_page = page.pager_page
- page.pager_page = nopage
-
- return _ip
+ print(strng)
+
+ page.orig_page = page.pager_page
+ page.pager_page = nopage
+
+ return _ip
diff --git a/contrib/python/ipython/py2/IPython/testing/iptest.py b/contrib/python/ipython/py2/IPython/testing/iptest.py
index 4018264125..9a5a3d6f58 100644
--- a/contrib/python/ipython/py2/IPython/testing/iptest.py
+++ b/contrib/python/ipython/py2/IPython/testing/iptest.py
@@ -1,55 +1,55 @@
-# -*- 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. 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) 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.
-
-"""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-from __future__ import print_function
-
-import glob
-from io import BytesIO
-import os
-import os.path as path
-import sys
-from threading import Thread, Lock, Event
-import warnings
-
-import nose.plugins.builtin
-from nose.plugins.xunit import Xunit
-from nose import SkipTest
-from nose.core import TestProgram
-from nose.plugins import Plugin
-from nose.util import safe_str
-
-from IPython import version_info
-from IPython.utils.py3compat import bytes_to_str
-from IPython.utils.importstring import import_item
-from IPython.testing.plugin.ipdoctest import IPythonDoctest
-from IPython.external.decorators import KnownFailure, knownfailureif
-
-pjoin = path.join
-
-
-# Enable printing all warnings raise by IPython's modules
+# -*- 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. 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) 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.
+
+"""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+from __future__ import print_function
+
+import glob
+from io import BytesIO
+import os
+import os.path as path
+import sys
+from threading import Thread, Lock, Event
+import warnings
+
+import nose.plugins.builtin
+from nose.plugins.xunit import Xunit
+from nose import SkipTest
+from nose.core import TestProgram
+from nose.plugins import Plugin
+from nose.util import safe_str
+
+from IPython import version_info
+from IPython.utils.py3compat import bytes_to_str
+from IPython.utils.importstring import import_item
+from IPython.testing.plugin.ipdoctest import IPythonDoctest
+from IPython.external.decorators import KnownFailure, knownfailureif
+
+pjoin = path.join
+
+
+# Enable printing all warnings raise by IPython's modules
warnings.filterwarnings('ignore', message='.*Matplotlib is building the font cache.*', category=UserWarning, module='.*')
if sys.version_info > (3,0):
warnings.filterwarnings('error', message='.*', category=ResourceWarning, module='.*')
warnings.filterwarnings('error', message=".*{'config': True}.*", category=DeprecationWarning, module='IPy.*')
-warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*')
-
+warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*')
+
warnings.filterwarnings('error', message='.*apply_wrapper.*', category=DeprecationWarning, module='.*')
warnings.filterwarnings('error', message='.*make_label_dec', category=DeprecationWarning, module='.*')
warnings.filterwarnings('error', message='.*decorated_dummy.*', category=DeprecationWarning, module='.*')
@@ -60,384 +60,384 @@ warnings.filterwarnings('error', message='.*disable_gui.*', category=Deprecation
warnings.filterwarnings('error', message='.*ExceptionColors global is deprecated.*', category=DeprecationWarning, module='.*')
-if version_info < (6,):
- # nose.tools renames all things from `camelCase` to `snake_case` which raise an
- # warning with the runner they also import from standard import library. (as of Dec 2015)
- # Ignore, let's revisit that in a couple of years for IPython 6.
- warnings.filterwarnings('ignore', message='.*Please use assertEqual instead', category=Warning, module='IPython.*')
-
-
-# ------------------------------------------------------------------------------
-# Monkeypatch Xunit to count known failures as skipped.
-# ------------------------------------------------------------------------------
-def monkeypatch_xunit():
- try:
- knownfailureif(True)(lambda: None)()
- except Exception as e:
- KnownFailureTest = type(e)
-
- def addError(self, test, err, capt=None):
- if issubclass(err[0], KnownFailureTest):
- err = (SkipTest,) + err[1:]
- return self.orig_addError(test, err, capt)
-
- Xunit.orig_addError = Xunit.addError
- Xunit.addError = addError
-
-#-----------------------------------------------------------------------------
-# Check which dependencies are installed and greater than minimum version.
-#-----------------------------------------------------------------------------
-def extract_version(mod):
- return mod.__version__
-
-def test_for(item, min_version=None, callback=extract_version):
- """Test to see if item is importable, and optionally check against a minimum
- version.
-
- If min_version is given, the default behavior is to check against the
- `__version__` attribute of the item, but specifying `callback` allows you to
- extract the value you are interested in. e.g::
-
- In [1]: import sys
-
- In [2]: from IPython.testing.iptest import test_for
-
- In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
- Out[3]: True
-
- """
- try:
- check = import_item(item)
- except (ImportError, RuntimeError):
- # GTK reports Runtime error if it can't be initialized even if it's
- # importable.
- return False
- else:
- if min_version:
- if callback:
- # extra processing step to get version to compare
- check = callback(check)
-
- return check >= min_version
- else:
- return True
-
-# Global dict where we can store information on what we have and what we don't
-# have available at test run time
-have = {'matplotlib': test_for('matplotlib'),
- 'pygments': test_for('pygments'),
- 'sqlite3': test_for('sqlite3')}
-
-#-----------------------------------------------------------------------------
-# Test suite definitions
-#-----------------------------------------------------------------------------
-
-test_group_names = ['core',
- 'extensions', 'lib', 'terminal', 'testing', 'utils',
- ]
-
-class TestSection(object):
- def __init__(self, name, includes):
- self.name = name
- self.includes = includes
- self.excludes = []
- self.dependencies = []
- self.enabled = True
-
- def exclude(self, module):
- if not module.startswith('IPython'):
- module = self.includes[0] + "." + module
- self.excludes.append(module.replace('.', os.sep))
-
- def requires(self, *packages):
- self.dependencies.extend(packages)
-
- @property
- def will_run(self):
- return self.enabled and all(have[p] for p in self.dependencies)
-
-# Name -> (include, exclude, dependencies_met)
-test_sections = {n:TestSection(n, ['IPython.%s' % n]) for n in test_group_names}
-
-
-# Exclusions and dependencies
-# ---------------------------
-
-# core:
-sec = test_sections['core']
-if not have['sqlite3']:
- sec.exclude('tests.test_history')
- sec.exclude('history')
-if not have['matplotlib']:
- sec.exclude('pylabtools'),
- sec.exclude('tests.test_pylabtools')
-
-# lib:
-sec = test_sections['lib']
-sec.exclude('kernel')
-if not have['pygments']:
- sec.exclude('tests.test_lexers')
-# We do this unconditionally, so that the test suite doesn't import
-# gtk, changing the default encoding and masking some unicode bugs.
-sec.exclude('inputhookgtk')
-# We also do this unconditionally, because wx can interfere with Unix signals.
-# There are currently no tests for it anyway.
-sec.exclude('inputhookwx')
-# 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
-sec.exclude('inputhook')
-
-# testing:
-sec = test_sections['testing']
-# These have to be skipped on win32 because they use echo, rm, cd, etc.
-# See ticket https://github.com/ipython/ipython/issues/87
-if sys.platform == 'win32':
- sec.exclude('plugin.test_exampleip')
- sec.exclude('plugin.dtexample')
-
-# don't run jupyter_console tests found via shim
-test_sections['terminal'].exclude('console')
-
-# extensions:
-sec = test_sections['extensions']
-# This is deprecated in favour of rpy2
-sec.exclude('rmagic')
-# autoreload does some strange stuff, so move it to its own test section
-sec.exclude('autoreload')
-sec.exclude('tests.test_autoreload')
-test_sections['autoreload'] = TestSection('autoreload',
- ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
-test_group_names.append('autoreload')
-
-
-#-----------------------------------------------------------------------------
-# Functions and classes
-#-----------------------------------------------------------------------------
-
-def check_exclusions_exist():
- from IPython.paths import get_ipython_package_dir
+if version_info < (6,):
+ # nose.tools renames all things from `camelCase` to `snake_case` which raise an
+ # warning with the runner they also import from standard import library. (as of Dec 2015)
+ # Ignore, let's revisit that in a couple of years for IPython 6.
+ warnings.filterwarnings('ignore', message='.*Please use assertEqual instead', category=Warning, module='IPython.*')
+
+
+# ------------------------------------------------------------------------------
+# Monkeypatch Xunit to count known failures as skipped.
+# ------------------------------------------------------------------------------
+def monkeypatch_xunit():
+ try:
+ knownfailureif(True)(lambda: None)()
+ except Exception as e:
+ KnownFailureTest = type(e)
+
+ def addError(self, test, err, capt=None):
+ if issubclass(err[0], KnownFailureTest):
+ err = (SkipTest,) + err[1:]
+ return self.orig_addError(test, err, capt)
+
+ Xunit.orig_addError = Xunit.addError
+ Xunit.addError = addError
+
+#-----------------------------------------------------------------------------
+# Check which dependencies are installed and greater than minimum version.
+#-----------------------------------------------------------------------------
+def extract_version(mod):
+ return mod.__version__
+
+def test_for(item, min_version=None, callback=extract_version):
+ """Test to see if item is importable, and optionally check against a minimum
+ version.
+
+ If min_version is given, the default behavior is to check against the
+ `__version__` attribute of the item, but specifying `callback` allows you to
+ extract the value you are interested in. e.g::
+
+ In [1]: import sys
+
+ In [2]: from IPython.testing.iptest import test_for
+
+ In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
+ Out[3]: True
+
+ """
+ try:
+ check = import_item(item)
+ except (ImportError, RuntimeError):
+ # GTK reports Runtime error if it can't be initialized even if it's
+ # importable.
+ return False
+ else:
+ if min_version:
+ if callback:
+ # extra processing step to get version to compare
+ check = callback(check)
+
+ return check >= min_version
+ else:
+ return True
+
+# Global dict where we can store information on what we have and what we don't
+# have available at test run time
+have = {'matplotlib': test_for('matplotlib'),
+ 'pygments': test_for('pygments'),
+ 'sqlite3': test_for('sqlite3')}
+
+#-----------------------------------------------------------------------------
+# Test suite definitions
+#-----------------------------------------------------------------------------
+
+test_group_names = ['core',
+ 'extensions', 'lib', 'terminal', 'testing', 'utils',
+ ]
+
+class TestSection(object):
+ def __init__(self, name, includes):
+ self.name = name
+ self.includes = includes
+ self.excludes = []
+ self.dependencies = []
+ self.enabled = True
+
+ def exclude(self, module):
+ if not module.startswith('IPython'):
+ module = self.includes[0] + "." + module
+ self.excludes.append(module.replace('.', os.sep))
+
+ def requires(self, *packages):
+ self.dependencies.extend(packages)
+
+ @property
+ def will_run(self):
+ return self.enabled and all(have[p] for p in self.dependencies)
+
+# Name -> (include, exclude, dependencies_met)
+test_sections = {n:TestSection(n, ['IPython.%s' % n]) for n in test_group_names}
+
+
+# Exclusions and dependencies
+# ---------------------------
+
+# core:
+sec = test_sections['core']
+if not have['sqlite3']:
+ sec.exclude('tests.test_history')
+ sec.exclude('history')
+if not have['matplotlib']:
+ sec.exclude('pylabtools'),
+ sec.exclude('tests.test_pylabtools')
+
+# lib:
+sec = test_sections['lib']
+sec.exclude('kernel')
+if not have['pygments']:
+ sec.exclude('tests.test_lexers')
+# We do this unconditionally, so that the test suite doesn't import
+# gtk, changing the default encoding and masking some unicode bugs.
+sec.exclude('inputhookgtk')
+# We also do this unconditionally, because wx can interfere with Unix signals.
+# There are currently no tests for it anyway.
+sec.exclude('inputhookwx')
+# 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
+sec.exclude('inputhook')
+
+# testing:
+sec = test_sections['testing']
+# These have to be skipped on win32 because they use echo, rm, cd, etc.
+# See ticket https://github.com/ipython/ipython/issues/87
+if sys.platform == 'win32':
+ sec.exclude('plugin.test_exampleip')
+ sec.exclude('plugin.dtexample')
+
+# don't run jupyter_console tests found via shim
+test_sections['terminal'].exclude('console')
+
+# extensions:
+sec = test_sections['extensions']
+# This is deprecated in favour of rpy2
+sec.exclude('rmagic')
+# autoreload does some strange stuff, so move it to its own test section
+sec.exclude('autoreload')
+sec.exclude('tests.test_autoreload')
+test_sections['autoreload'] = TestSection('autoreload',
+ ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
+test_group_names.append('autoreload')
+
+
+#-----------------------------------------------------------------------------
+# Functions and classes
+#-----------------------------------------------------------------------------
+
+def check_exclusions_exist():
+ from IPython.paths import get_ipython_package_dir
from warnings import warn
- parent = os.path.dirname(get_ipython_package_dir())
- for sec in test_sections:
- for pattern in sec.exclusions:
- fullpath = pjoin(parent, pattern)
- if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
- warn("Excluding nonexistent file: %r" % pattern)
-
-
-class ExclusionPlugin(Plugin):
- """A nose plugin to effect our exclusions of files and directories.
- """
- name = 'exclusions'
- score = 3000 # Should come before any other plugins
-
- def __init__(self, exclude_patterns=None):
- """
- Parameters
- ----------
-
- exclude_patterns : sequence of strings, optional
- Filenames containing these patterns (as raw strings, not as regular
- expressions) are excluded from the tests.
- """
- self.exclude_patterns = exclude_patterns or []
- super(ExclusionPlugin, self).__init__()
-
- def options(self, parser, env=os.environ):
- Plugin.options(self, parser, env)
-
- def configure(self, options, config):
- Plugin.configure(self, options, config)
- # Override nose trying to disable plugin.
- self.enabled = True
-
- def wantFile(self, filename):
- """Return whether the given filename should be scanned for tests.
- """
- if any(pat in filename for pat in self.exclude_patterns):
- return False
- return None
-
- def wantDirectory(self, directory):
- """Return whether the given directory should be scanned for tests.
- """
- if any(pat in directory for pat in self.exclude_patterns):
- return False
- return None
-
-
-class StreamCapturer(Thread):
- daemon = True # Don't hang if main thread crashes
- started = False
- def __init__(self, echo=False):
- super(StreamCapturer, self).__init__()
- self.echo = echo
- self.streams = []
- self.buffer = BytesIO()
- self.readfd, self.writefd = os.pipe()
- self.buffer_lock = Lock()
- self.stop = Event()
-
- def run(self):
- self.started = True
-
- while not self.stop.is_set():
- chunk = os.read(self.readfd, 1024)
-
- with self.buffer_lock:
- self.buffer.write(chunk)
- if self.echo:
- sys.stdout.write(bytes_to_str(chunk))
-
- os.close(self.readfd)
- os.close(self.writefd)
-
- def reset_buffer(self):
- with self.buffer_lock:
- self.buffer.truncate(0)
- self.buffer.seek(0)
-
- def get_buffer(self):
- with self.buffer_lock:
- return self.buffer.getvalue()
-
- def ensure_started(self):
- if not self.started:
- self.start()
-
- def halt(self):
- """Safely stop the thread."""
- if not self.started:
- return
-
- self.stop.set()
- os.write(self.writefd, b'\0') # Ensure we're not locked in a read()
- self.join()
-
-class SubprocessStreamCapturePlugin(Plugin):
- name='subprocstreams'
- def __init__(self):
- Plugin.__init__(self)
- self.stream_capturer = StreamCapturer()
- self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
- # This is ugly, but distant parts of the test machinery need to be able
- # to redirect streams, so we make the object globally accessible.
- nose.iptest_stdstreams_fileno = self.get_write_fileno
-
- def get_write_fileno(self):
- if self.destination == 'capture':
- self.stream_capturer.ensure_started()
- return self.stream_capturer.writefd
- elif self.destination == 'discard':
- return os.open(os.devnull, os.O_WRONLY)
- else:
- return sys.__stdout__.fileno()
-
- def configure(self, options, config):
- Plugin.configure(self, options, config)
- # Override nose trying to disable plugin.
- if self.destination == 'capture':
- self.enabled = True
-
- def startTest(self, test):
- # Reset log capture
- self.stream_capturer.reset_buffer()
-
- def formatFailure(self, test, err):
- # Show output
- ec, ev, tb = err
- captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
- if captured.strip():
- ev = safe_str(ev)
- out = [ev, '>> begin captured subprocess output <<',
- captured,
- '>> end captured subprocess output <<']
- return ec, '\n'.join(out), tb
-
- return err
-
- formatError = formatFailure
-
- def finalize(self, result):
- self.stream_capturer.halt()
-
-
-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.
- """
- # Apply our monkeypatch to Xunit
- if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
- monkeypatch_xunit()
-
- arg1 = sys.argv[1]
- if arg1 in test_sections:
- section = test_sections[arg1]
- sys.argv[1:2] = section.includes
- elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
- section = test_sections[arg1[8:]]
- sys.argv[1:2] = section.includes
- else:
- section = TestSection(arg1, includes=[arg1])
-
-
- argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
- # 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',
- ]
- if '-a' not in argv and '-A' not in argv:
- argv = argv + ['-a', '!crash']
-
- if nose.__version__ >= '0.11':
- # I don't fully understand why we need this one, but depending on what
- # directory the test suite is run from, if we don't give it, 0 tests
- # get run. Specifically, if the test suite is run from the source dir
- # with an argument (like 'iptest.py IPython.core', 0 tests are run,
- # even if the same call done in this directory works fine). It appears
- # that if the requested package is in the current dir, nose bails early
- # by default. Since it's otherwise harmless, leave it in by default
- # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
- argv.append('--traverse-namespace')
-
- plugins = [ ExclusionPlugin(section.excludes), KnownFailure(),
- SubprocessStreamCapturePlugin() ]
-
- # we still have some vestigial doctests in core
- if (section.name.startswith(('core', 'IPython.core'))):
- plugins.append(IPythonDoctest())
- argv.extend([
- '--with-ipdoctest',
- '--ipdoctest-tests',
- '--ipdoctest-extension=txt',
- ])
-
-
- # Use working directory set by parent process (see iptestcontroller)
- if 'IPTEST_WORKING_DIR' in os.environ:
- os.chdir(os.environ['IPTEST_WORKING_DIR'])
-
- # We need a global ipython running in this process, but the special
- # in-process group spawns its own IPython kernels, so for *that* group we
- # must avoid also opening the global one (otherwise there's a conflict of
- # singletons). Ultimately the solution to this problem is to refactor our
- # assumptions about what needs to be a singleton and what doesn't (app
- # objects should, individual shells shouldn't). But for now, this
- # workaround allows the test suite for the inprocess module to complete.
- if 'kernel.inprocess' not in section.name:
- from IPython.testing import globalipapp
- globalipapp.start_ipython()
-
- # Now nose can run
- TestProgram(argv=argv, addplugins=plugins)
-
-if __name__ == '__main__':
- run_iptest()
+ parent = os.path.dirname(get_ipython_package_dir())
+ for sec in test_sections:
+ for pattern in sec.exclusions:
+ fullpath = pjoin(parent, pattern)
+ if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
+ warn("Excluding nonexistent file: %r" % pattern)
+
+
+class ExclusionPlugin(Plugin):
+ """A nose plugin to effect our exclusions of files and directories.
+ """
+ name = 'exclusions'
+ score = 3000 # Should come before any other plugins
+
+ def __init__(self, exclude_patterns=None):
+ """
+ Parameters
+ ----------
+
+ exclude_patterns : sequence of strings, optional
+ Filenames containing these patterns (as raw strings, not as regular
+ expressions) are excluded from the tests.
+ """
+ self.exclude_patterns = exclude_patterns or []
+ super(ExclusionPlugin, self).__init__()
+
+ def options(self, parser, env=os.environ):
+ Plugin.options(self, parser, env)
+
+ def configure(self, options, config):
+ Plugin.configure(self, options, config)
+ # Override nose trying to disable plugin.
+ self.enabled = True
+
+ def wantFile(self, filename):
+ """Return whether the given filename should be scanned for tests.
+ """
+ if any(pat in filename for pat in self.exclude_patterns):
+ return False
+ return None
+
+ def wantDirectory(self, directory):
+ """Return whether the given directory should be scanned for tests.
+ """
+ if any(pat in directory for pat in self.exclude_patterns):
+ return False
+ return None
+
+
+class StreamCapturer(Thread):
+ daemon = True # Don't hang if main thread crashes
+ started = False
+ def __init__(self, echo=False):
+ super(StreamCapturer, self).__init__()
+ self.echo = echo
+ self.streams = []
+ self.buffer = BytesIO()
+ self.readfd, self.writefd = os.pipe()
+ self.buffer_lock = Lock()
+ self.stop = Event()
+
+ def run(self):
+ self.started = True
+
+ while not self.stop.is_set():
+ chunk = os.read(self.readfd, 1024)
+
+ with self.buffer_lock:
+ self.buffer.write(chunk)
+ if self.echo:
+ sys.stdout.write(bytes_to_str(chunk))
+
+ os.close(self.readfd)
+ os.close(self.writefd)
+
+ def reset_buffer(self):
+ with self.buffer_lock:
+ self.buffer.truncate(0)
+ self.buffer.seek(0)
+
+ def get_buffer(self):
+ with self.buffer_lock:
+ return self.buffer.getvalue()
+
+ def ensure_started(self):
+ if not self.started:
+ self.start()
+
+ def halt(self):
+ """Safely stop the thread."""
+ if not self.started:
+ return
+
+ self.stop.set()
+ os.write(self.writefd, b'\0') # Ensure we're not locked in a read()
+ self.join()
+
+class SubprocessStreamCapturePlugin(Plugin):
+ name='subprocstreams'
+ def __init__(self):
+ Plugin.__init__(self)
+ self.stream_capturer = StreamCapturer()
+ self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
+ # This is ugly, but distant parts of the test machinery need to be able
+ # to redirect streams, so we make the object globally accessible.
+ nose.iptest_stdstreams_fileno = self.get_write_fileno
+
+ def get_write_fileno(self):
+ if self.destination == 'capture':
+ self.stream_capturer.ensure_started()
+ return self.stream_capturer.writefd
+ elif self.destination == 'discard':
+ return os.open(os.devnull, os.O_WRONLY)
+ else:
+ return sys.__stdout__.fileno()
+
+ def configure(self, options, config):
+ Plugin.configure(self, options, config)
+ # Override nose trying to disable plugin.
+ if self.destination == 'capture':
+ self.enabled = True
+
+ def startTest(self, test):
+ # Reset log capture
+ self.stream_capturer.reset_buffer()
+
+ def formatFailure(self, test, err):
+ # Show output
+ ec, ev, tb = err
+ captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
+ if captured.strip():
+ ev = safe_str(ev)
+ out = [ev, '>> begin captured subprocess output <<',
+ captured,
+ '>> end captured subprocess output <<']
+ return ec, '\n'.join(out), tb
+
+ return err
+
+ formatError = formatFailure
+
+ def finalize(self, result):
+ self.stream_capturer.halt()
+
+
+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.
+ """
+ # Apply our monkeypatch to Xunit
+ if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
+ monkeypatch_xunit()
+
+ arg1 = sys.argv[1]
+ if arg1 in test_sections:
+ section = test_sections[arg1]
+ sys.argv[1:2] = section.includes
+ elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
+ section = test_sections[arg1[8:]]
+ sys.argv[1:2] = section.includes
+ else:
+ section = TestSection(arg1, includes=[arg1])
+
+
+ argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
+ # 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',
+ ]
+ if '-a' not in argv and '-A' not in argv:
+ argv = argv + ['-a', '!crash']
+
+ if nose.__version__ >= '0.11':
+ # I don't fully understand why we need this one, but depending on what
+ # directory the test suite is run from, if we don't give it, 0 tests
+ # get run. Specifically, if the test suite is run from the source dir
+ # with an argument (like 'iptest.py IPython.core', 0 tests are run,
+ # even if the same call done in this directory works fine). It appears
+ # that if the requested package is in the current dir, nose bails early
+ # by default. Since it's otherwise harmless, leave it in by default
+ # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
+ argv.append('--traverse-namespace')
+
+ plugins = [ ExclusionPlugin(section.excludes), KnownFailure(),
+ SubprocessStreamCapturePlugin() ]
+
+ # we still have some vestigial doctests in core
+ if (section.name.startswith(('core', 'IPython.core'))):
+ plugins.append(IPythonDoctest())
+ argv.extend([
+ '--with-ipdoctest',
+ '--ipdoctest-tests',
+ '--ipdoctest-extension=txt',
+ ])
+
+
+ # Use working directory set by parent process (see iptestcontroller)
+ if 'IPTEST_WORKING_DIR' in os.environ:
+ os.chdir(os.environ['IPTEST_WORKING_DIR'])
+
+ # We need a global ipython running in this process, but the special
+ # in-process group spawns its own IPython kernels, so for *that* group we
+ # must avoid also opening the global one (otherwise there's a conflict of
+ # singletons). Ultimately the solution to this problem is to refactor our
+ # assumptions about what needs to be a singleton and what doesn't (app
+ # objects should, individual shells shouldn't). But for now, this
+ # workaround allows the test suite for the inprocess module to complete.
+ if 'kernel.inprocess' not in section.name:
+ from IPython.testing import globalipapp
+ globalipapp.start_ipython()
+
+ # Now nose can run
+ TestProgram(argv=argv, addplugins=plugins)
+
+if __name__ == '__main__':
+ run_iptest()
diff --git a/contrib/python/ipython/py2/IPython/testing/iptestcontroller.py b/contrib/python/ipython/py2/IPython/testing/iptestcontroller.py
index 95aa06e4a4..6d8834f193 100644
--- a/contrib/python/ipython/py2/IPython/testing/iptestcontroller.py
+++ b/contrib/python/ipython/py2/IPython/testing/iptestcontroller.py
@@ -1,532 +1,532 @@
-# -*- coding: utf-8 -*-
-"""IPython Test Process Controller
-
-This module runs one or more subprocesses which will actually run the IPython
-test suite.
-
-"""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-from __future__ import print_function
-
-import argparse
-import json
-import multiprocessing.pool
-import os
-import stat
-import re
-import requests
-import shutil
-import signal
-import sys
-import subprocess
-import time
-
-from .iptest import (
- have, test_group_names as py_test_group_names, test_sections, StreamCapturer,
- test_for,
-)
-from IPython.utils.path import compress_user
-from IPython.utils.py3compat import bytes_to_str
-from IPython.utils.sysinfo import get_sys_info
-from IPython.utils.tempdir import TemporaryDirectory
-from IPython.utils.text import strip_ansi
-
-try:
- # Python >= 3.3
- from subprocess import TimeoutExpired
- def popen_wait(p, timeout):
- return p.wait(timeout)
-except ImportError:
- class TimeoutExpired(Exception):
- pass
- def popen_wait(p, timeout):
- """backport of Popen.wait from Python 3"""
- for i in range(int(10 * timeout)):
- if p.poll() is not None:
- return
- time.sleep(0.1)
- if p.poll() is None:
- raise TimeoutExpired
-
-NOTEBOOK_SHUTDOWN_TIMEOUT = 10
-
-class TestController(object):
- """Run tests in a subprocess
- """
- #: str, IPython test suite to be executed.
- section = None
- #: list, command line arguments to be executed
- cmd = None
- #: dict, extra environment variables to set for the subprocess
- env = None
- #: list, TemporaryDirectory instances to clear up when the process finishes
- dirs = None
- #: subprocess.Popen instance
- process = None
- #: str, process stdout+stderr
- stdout = None
-
- def __init__(self):
- self.cmd = []
- self.env = {}
- self.dirs = []
-
- def setup(self):
- """Create temporary directories etc.
-
- This is only called when we know the test group will be run. Things
- created here may be cleaned up by self.cleanup().
- """
- pass
-
- def launch(self, buffer_output=False, capture_output=False):
- # print('*** ENV:', self.env) # dbg
- # print('*** CMD:', self.cmd) # dbg
- env = os.environ.copy()
- env.update(self.env)
- if buffer_output:
- capture_output = True
- self.stdout_capturer = c = StreamCapturer(echo=not buffer_output)
- c.start()
- stdout = c.writefd if capture_output else None
- stderr = subprocess.STDOUT if capture_output else None
- self.process = subprocess.Popen(self.cmd, stdout=stdout,
- stderr=stderr, env=env)
-
- def wait(self):
- self.process.wait()
- self.stdout_capturer.halt()
- self.stdout = self.stdout_capturer.get_buffer()
- return self.process.returncode
-
- def print_extra_info(self):
- """Print extra information about this test run.
-
- If we're running in parallel and showing the concise view, this is only
- called if the test group fails. Otherwise, it's called before the test
- group is started.
-
- The base implementation does nothing, but it can be overridden by
- subclasses.
- """
- return
-
- def cleanup_process(self):
- """Cleanup on exit by killing any leftover processes."""
- subp = self.process
- if subp is None or (subp.poll() is not None):
- return # Process doesn't exist, or is already dead.
-
- try:
- print('Cleaning up stale PID: %d' % subp.pid)
- subp.kill()
- except: # (OSError, WindowsError) ?
- # This is just a best effort, if we fail or the process was
- # really gone, ignore it.
- pass
- else:
- for i in range(10):
- if subp.poll() is None:
- time.sleep(0.1)
- else:
- break
-
- if subp.poll() is None:
- # The process did not die...
- print('... failed. Manual cleanup may be required.')
-
- def cleanup(self):
- "Kill process if it's still alive, and clean up temporary directories"
- self.cleanup_process()
- for td in self.dirs:
- td.cleanup()
-
- __del__ = cleanup
-
-
-class PyTestController(TestController):
- """Run Python tests using IPython.testing.iptest"""
- #: str, Python command to execute in subprocess
- pycmd = None
-
- def __init__(self, section, options):
- """Create new test runner."""
- TestController.__init__(self)
- self.section = section
- # pycmd is put into cmd[2] in PyTestController.launch()
- self.cmd = [sys.executable, '-c', None, section]
- self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()"
- self.options = options
-
- def setup(self):
- ipydir = TemporaryDirectory()
- self.dirs.append(ipydir)
- self.env['IPYTHONDIR'] = ipydir.name
- self.workingdir = workingdir = TemporaryDirectory()
- self.dirs.append(workingdir)
- self.env['IPTEST_WORKING_DIR'] = workingdir.name
- # This means we won't get odd effects from our own matplotlib config
- self.env['MPLCONFIGDIR'] = workingdir.name
- # For security reasons (http://bugs.python.org/issue16202), use
- # a temporary directory to which other users have no access.
- self.env['TMPDIR'] = workingdir.name
-
- # Add a non-accessible directory to PATH (see gh-7053)
- noaccess = os.path.join(self.workingdir.name, "_no_access_")
- self.noaccess = noaccess
- os.mkdir(noaccess, 0)
-
- PATH = os.environ.get('PATH', '')
- if PATH:
- PATH = noaccess + os.pathsep + PATH
- else:
- PATH = noaccess
- self.env['PATH'] = PATH
-
- # From options:
- if self.options.xunit:
- self.add_xunit()
- if self.options.coverage:
- self.add_coverage()
- self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams
- self.cmd.extend(self.options.extra_args)
-
- def cleanup(self):
- """
- Make the non-accessible directory created in setup() accessible
- again, otherwise deleting the workingdir will fail.
- """
- os.chmod(self.noaccess, stat.S_IRWXU)
- TestController.cleanup(self)
-
- @property
- def will_run(self):
- try:
- return test_sections[self.section].will_run
- except KeyError:
- return True
-
- def add_xunit(self):
- xunit_file = os.path.abspath(self.section + '.xunit.xml')
- self.cmd.extend(['--with-xunit', '--xunit-file', xunit_file])
-
- def add_coverage(self):
- try:
- sources = test_sections[self.section].includes
- except KeyError:
- sources = ['IPython']
-
- coverage_rc = ("[run]\n"
- "data_file = {data_file}\n"
- "source =\n"
- " {source}\n"
- ).format(data_file=os.path.abspath('.coverage.'+self.section),
- source="\n ".join(sources))
- config_file = os.path.join(self.workingdir.name, '.coveragerc')
- with open(config_file, 'w') as f:
- f.write(coverage_rc)
-
- self.env['COVERAGE_PROCESS_START'] = config_file
- self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
-
- def launch(self, buffer_output=False):
- self.cmd[2] = self.pycmd
- super(PyTestController, self).launch(buffer_output=buffer_output)
-
-
-def prepare_controllers(options):
- """Returns two lists of TestController instances, those to run, and those
- not to run."""
- testgroups = options.testgroups
- if not testgroups:
- testgroups = py_test_group_names
-
- controllers = [PyTestController(name, options) for name in testgroups]
-
- to_run = [c for c in controllers if c.will_run]
- not_run = [c for c in controllers if not c.will_run]
- return to_run, not_run
-
-def do_run(controller, buffer_output=True):
- """Setup and run a test controller.
-
- If buffer_output is True, no output is displayed, to avoid it appearing
- interleaved. In this case, the caller is responsible for displaying test
- output on failure.
-
- Returns
- -------
- controller : TestController
- The same controller as passed in, as a convenience for using map() type
- APIs.
- exitcode : int
- The exit code of the test subprocess. Non-zero indicates failure.
- """
- try:
- try:
- controller.setup()
- if not buffer_output:
- controller.print_extra_info()
- controller.launch(buffer_output=buffer_output)
- except Exception:
- import traceback
- traceback.print_exc()
- return controller, 1 # signal failure
-
- exitcode = controller.wait()
- return controller, exitcode
-
- except KeyboardInterrupt:
- return controller, -signal.SIGINT
- finally:
- controller.cleanup()
-
-def report():
- """Return a string with a summary report of test-related variables."""
- inf = get_sys_info()
- out = []
- def _add(name, value):
- out.append((name, value))
-
- _add('IPython version', inf['ipython_version'])
- _add('IPython commit', "{} ({})".format(inf['commit_hash'], inf['commit_source']))
- _add('IPython package', compress_user(inf['ipython_path']))
- _add('Python version', inf['sys_version'].replace('\n',''))
- _add('sys.executable', compress_user(inf['sys_executable']))
- _add('Platform', inf['platform'])
-
- width = max(len(n) for (n,v) in out)
- out = ["{:<{width}}: {}\n".format(n, v, width=width) for (n,v) in out]
-
- avail = []
- not_avail = []
-
- for k, is_avail in have.items():
- if is_avail:
- avail.append(k)
- else:
- not_avail.append(k)
-
- if avail:
- out.append('\nTools and libraries available at test time:\n')
- avail.sort()
- out.append(' ' + ' '.join(avail)+'\n')
-
- if not_avail:
- out.append('\nTools and libraries NOT available at test time:\n')
- not_avail.sort()
- out.append(' ' + ' '.join(not_avail)+'\n')
-
- return ''.join(out)
-
-def run_iptestall(options):
- """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.
-
- Parameters
- ----------
-
- All parameters are passed as attributes of the options object.
-
- testgroups : list of str
- Run only these sections of the test suite. If empty, run all the available
- sections.
-
- fast : int or None
- Run the test suite in parallel, using n simultaneous processes. If None
- is passed, one process is used per CPU core. Default 1 (i.e. sequential)
-
- inc_slow : bool
- Include slow tests. By default, these tests aren't run.
-
- url : unicode
- Address:port to use when running the JS tests.
-
- xunit : bool
- Produce Xunit XML output. This is written to multiple foo.xunit.xml files.
-
- coverage : bool or str
- Measure code coverage from tests. True will store the raw coverage data,
- or pass 'html' or 'xml' to get reports.
-
- extra_args : list
- Extra arguments to pass to the test subprocesses, e.g. '-v'
- """
- to_run, not_run = prepare_controllers(options)
-
- def justify(ltext, rtext, width=70, fill='-'):
- ltext += ' '
- rtext = (' ' + rtext).rjust(width - len(ltext), fill)
- return ltext + rtext
-
- # Run all test runners, tracking execution time
- failed = []
- t_start = time.time()
-
- print()
- if options.fast == 1:
- # This actually means sequential, i.e. with 1 job
- for controller in to_run:
- print('Test group:', controller.section)
- sys.stdout.flush() # Show in correct order when output is piped
- controller, res = do_run(controller, buffer_output=False)
- if res:
- failed.append(controller)
- if res == -signal.SIGINT:
- print("Interrupted")
- break
- print()
-
- else:
- # Run tests concurrently
- try:
- pool = multiprocessing.pool.ThreadPool(options.fast)
- for (controller, res) in pool.imap_unordered(do_run, to_run):
- res_string = 'OK' if res == 0 else 'FAILED'
- print(justify('Test group: ' + controller.section, res_string))
- if res:
- controller.print_extra_info()
- print(bytes_to_str(controller.stdout))
- failed.append(controller)
- if res == -signal.SIGINT:
- print("Interrupted")
- break
- except KeyboardInterrupt:
- return
-
- for controller in not_run:
- print(justify('Test group: ' + controller.section, 'NOT RUN'))
-
- t_end = time.time()
- t_tests = t_end - t_start
- nrunners = len(to_run)
- nfail = len(failed)
- # summarize results
- print('_'*70)
- print('Test suite completed for system with the following information:')
- print(report())
- took = "Took %.3fs." % t_tests
- print('Status: ', end='')
- if not failed:
- print('OK (%d test groups).' % nrunners, took)
- else:
- # If anything went wrong, point out what command to rerun manually to
- # see the actual errors and individual summary
- failed_sections = [c.section for c in failed]
- print('ERROR - {} out of {} test groups failed ({}).'.format(nfail,
- nrunners, ', '.join(failed_sections)), took)
- print()
- print('You may wish to rerun these, with:')
- print(' iptest', *failed_sections)
- print()
-
- if options.coverage:
- from coverage import coverage, CoverageException
- cov = coverage(data_file='.coverage')
- cov.combine()
- cov.save()
-
- # Coverage HTML report
- if options.coverage == 'html':
- html_dir = 'ipy_htmlcov'
- shutil.rmtree(html_dir, ignore_errors=True)
- print("Writing HTML coverage report to %s/ ... " % html_dir, end="")
- sys.stdout.flush()
-
- # Custom HTML reporter to clean up module names.
- from coverage.html import HtmlReporter
- class CustomHtmlReporter(HtmlReporter):
- def find_code_units(self, morfs):
- super(CustomHtmlReporter, self).find_code_units(morfs)
- for cu in self.code_units:
- nameparts = cu.name.split(os.sep)
- if 'IPython' not in nameparts:
- continue
- ix = nameparts.index('IPython')
- cu.name = '.'.join(nameparts[ix:])
-
- # Reimplement the html_report method with our custom reporter
- cov.get_data()
- cov.config.from_args(omit='*{0}tests{0}*'.format(os.sep), html_dir=html_dir,
- html_title='IPython test coverage',
- )
- reporter = CustomHtmlReporter(cov, cov.config)
- reporter.report(None)
- print('done.')
-
- # Coverage XML report
- elif options.coverage == 'xml':
- try:
- cov.xml_report(outfile='ipy_coverage.xml')
- except CoverageException as e:
- print('Generating coverage report failed. Are you running javascript tests only?')
- import traceback
- traceback.print_exc()
-
- if failed:
- # Ensure that our exit code indicates failure
- sys.exit(1)
-
-argparser = argparse.ArgumentParser(description='Run IPython test suite')
-argparser.add_argument('testgroups', nargs='*',
- help='Run specified groups of tests. If omitted, run '
- 'all tests.')
-argparser.add_argument('--all', action='store_true',
- help='Include slow tests not run by default.')
-argparser.add_argument('--url', help="URL to use for the JS tests.")
-argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int,
- help='Run test sections in parallel. This starts as many '
- 'processes as you have cores, or you can specify a number.')
-argparser.add_argument('--xunit', action='store_true',
- help='Produce Xunit XML results')
-argparser.add_argument('--coverage', nargs='?', const=True, default=False,
- help="Measure test coverage. Specify 'html' or "
- "'xml' to get reports.")
-argparser.add_argument('--subproc-streams', default='capture',
- help="What to do with stdout/stderr from subprocesses. "
- "'capture' (default), 'show' and 'discard' are the options.")
-
-def default_options():
- """Get an argparse Namespace object with the default arguments, to pass to
- :func:`run_iptestall`.
- """
- options = argparser.parse_args([])
- options.extra_args = []
- return options
-
-def main():
- # iptest doesn't work correctly if the working directory is the
- # root of the IPython source tree. Tell the user to avoid
- # frustration.
- if os.path.exists(os.path.join(os.getcwd(),
- 'IPython', 'testing', '__main__.py')):
- print("Don't run iptest from the IPython source directory",
- file=sys.stderr)
- sys.exit(1)
- # Arguments after -- should be passed through to nose. Argparse treats
- # everything after -- as regular positional arguments, so we separate them
- # first.
- try:
- ix = sys.argv.index('--')
- except ValueError:
- to_parse = sys.argv[1:]
- extra_args = []
- else:
- to_parse = sys.argv[1:ix]
- extra_args = sys.argv[ix+1:]
-
- options = argparser.parse_args(to_parse)
- options.extra_args = extra_args
-
- run_iptestall(options)
-
-
-if __name__ == '__main__':
- main()
+# -*- coding: utf-8 -*-
+"""IPython Test Process Controller
+
+This module runs one or more subprocesses which will actually run the IPython
+test suite.
+
+"""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+from __future__ import print_function
+
+import argparse
+import json
+import multiprocessing.pool
+import os
+import stat
+import re
+import requests
+import shutil
+import signal
+import sys
+import subprocess
+import time
+
+from .iptest import (
+ have, test_group_names as py_test_group_names, test_sections, StreamCapturer,
+ test_for,
+)
+from IPython.utils.path import compress_user
+from IPython.utils.py3compat import bytes_to_str
+from IPython.utils.sysinfo import get_sys_info
+from IPython.utils.tempdir import TemporaryDirectory
+from IPython.utils.text import strip_ansi
+
+try:
+ # Python >= 3.3
+ from subprocess import TimeoutExpired
+ def popen_wait(p, timeout):
+ return p.wait(timeout)
+except ImportError:
+ class TimeoutExpired(Exception):
+ pass
+ def popen_wait(p, timeout):
+ """backport of Popen.wait from Python 3"""
+ for i in range(int(10 * timeout)):
+ if p.poll() is not None:
+ return
+ time.sleep(0.1)
+ if p.poll() is None:
+ raise TimeoutExpired
+
+NOTEBOOK_SHUTDOWN_TIMEOUT = 10
+
+class TestController(object):
+ """Run tests in a subprocess
+ """
+ #: str, IPython test suite to be executed.
+ section = None
+ #: list, command line arguments to be executed
+ cmd = None
+ #: dict, extra environment variables to set for the subprocess
+ env = None
+ #: list, TemporaryDirectory instances to clear up when the process finishes
+ dirs = None
+ #: subprocess.Popen instance
+ process = None
+ #: str, process stdout+stderr
+ stdout = None
+
+ def __init__(self):
+ self.cmd = []
+ self.env = {}
+ self.dirs = []
+
+ def setup(self):
+ """Create temporary directories etc.
+
+ This is only called when we know the test group will be run. Things
+ created here may be cleaned up by self.cleanup().
+ """
+ pass
+
+ def launch(self, buffer_output=False, capture_output=False):
+ # print('*** ENV:', self.env) # dbg
+ # print('*** CMD:', self.cmd) # dbg
+ env = os.environ.copy()
+ env.update(self.env)
+ if buffer_output:
+ capture_output = True
+ self.stdout_capturer = c = StreamCapturer(echo=not buffer_output)
+ c.start()
+ stdout = c.writefd if capture_output else None
+ stderr = subprocess.STDOUT if capture_output else None
+ self.process = subprocess.Popen(self.cmd, stdout=stdout,
+ stderr=stderr, env=env)
+
+ def wait(self):
+ self.process.wait()
+ self.stdout_capturer.halt()
+ self.stdout = self.stdout_capturer.get_buffer()
+ return self.process.returncode
+
+ def print_extra_info(self):
+ """Print extra information about this test run.
+
+ If we're running in parallel and showing the concise view, this is only
+ called if the test group fails. Otherwise, it's called before the test
+ group is started.
+
+ The base implementation does nothing, but it can be overridden by
+ subclasses.
+ """
+ return
+
+ def cleanup_process(self):
+ """Cleanup on exit by killing any leftover processes."""
+ subp = self.process
+ if subp is None or (subp.poll() is not None):
+ return # Process doesn't exist, or is already dead.
+
+ try:
+ print('Cleaning up stale PID: %d' % subp.pid)
+ subp.kill()
+ except: # (OSError, WindowsError) ?
+ # This is just a best effort, if we fail or the process was
+ # really gone, ignore it.
+ pass
+ else:
+ for i in range(10):
+ if subp.poll() is None:
+ time.sleep(0.1)
+ else:
+ break
+
+ if subp.poll() is None:
+ # The process did not die...
+ print('... failed. Manual cleanup may be required.')
+
+ def cleanup(self):
+ "Kill process if it's still alive, and clean up temporary directories"
+ self.cleanup_process()
+ for td in self.dirs:
+ td.cleanup()
+
+ __del__ = cleanup
+
+
+class PyTestController(TestController):
+ """Run Python tests using IPython.testing.iptest"""
+ #: str, Python command to execute in subprocess
+ pycmd = None
+
+ def __init__(self, section, options):
+ """Create new test runner."""
+ TestController.__init__(self)
+ self.section = section
+ # pycmd is put into cmd[2] in PyTestController.launch()
+ self.cmd = [sys.executable, '-c', None, section]
+ self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()"
+ self.options = options
+
+ def setup(self):
+ ipydir = TemporaryDirectory()
+ self.dirs.append(ipydir)
+ self.env['IPYTHONDIR'] = ipydir.name
+ self.workingdir = workingdir = TemporaryDirectory()
+ self.dirs.append(workingdir)
+ self.env['IPTEST_WORKING_DIR'] = workingdir.name
+ # This means we won't get odd effects from our own matplotlib config
+ self.env['MPLCONFIGDIR'] = workingdir.name
+ # For security reasons (http://bugs.python.org/issue16202), use
+ # a temporary directory to which other users have no access.
+ self.env['TMPDIR'] = workingdir.name
+
+ # Add a non-accessible directory to PATH (see gh-7053)
+ noaccess = os.path.join(self.workingdir.name, "_no_access_")
+ self.noaccess = noaccess
+ os.mkdir(noaccess, 0)
+
+ PATH = os.environ.get('PATH', '')
+ if PATH:
+ PATH = noaccess + os.pathsep + PATH
+ else:
+ PATH = noaccess
+ self.env['PATH'] = PATH
+
+ # From options:
+ if self.options.xunit:
+ self.add_xunit()
+ if self.options.coverage:
+ self.add_coverage()
+ self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams
+ self.cmd.extend(self.options.extra_args)
+
+ def cleanup(self):
+ """
+ Make the non-accessible directory created in setup() accessible
+ again, otherwise deleting the workingdir will fail.
+ """
+ os.chmod(self.noaccess, stat.S_IRWXU)
+ TestController.cleanup(self)
+
+ @property
+ def will_run(self):
+ try:
+ return test_sections[self.section].will_run
+ except KeyError:
+ return True
+
+ def add_xunit(self):
+ xunit_file = os.path.abspath(self.section + '.xunit.xml')
+ self.cmd.extend(['--with-xunit', '--xunit-file', xunit_file])
+
+ def add_coverage(self):
+ try:
+ sources = test_sections[self.section].includes
+ except KeyError:
+ sources = ['IPython']
+
+ coverage_rc = ("[run]\n"
+ "data_file = {data_file}\n"
+ "source =\n"
+ " {source}\n"
+ ).format(data_file=os.path.abspath('.coverage.'+self.section),
+ source="\n ".join(sources))
+ config_file = os.path.join(self.workingdir.name, '.coveragerc')
+ with open(config_file, 'w') as f:
+ f.write(coverage_rc)
+
+ self.env['COVERAGE_PROCESS_START'] = config_file
+ self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
+
+ def launch(self, buffer_output=False):
+ self.cmd[2] = self.pycmd
+ super(PyTestController, self).launch(buffer_output=buffer_output)
+
+
+def prepare_controllers(options):
+ """Returns two lists of TestController instances, those to run, and those
+ not to run."""
+ testgroups = options.testgroups
+ if not testgroups:
+ testgroups = py_test_group_names
+
+ controllers = [PyTestController(name, options) for name in testgroups]
+
+ to_run = [c for c in controllers if c.will_run]
+ not_run = [c for c in controllers if not c.will_run]
+ return to_run, not_run
+
+def do_run(controller, buffer_output=True):
+ """Setup and run a test controller.
+
+ If buffer_output is True, no output is displayed, to avoid it appearing
+ interleaved. In this case, the caller is responsible for displaying test
+ output on failure.
+
+ Returns
+ -------
+ controller : TestController
+ The same controller as passed in, as a convenience for using map() type
+ APIs.
+ exitcode : int
+ The exit code of the test subprocess. Non-zero indicates failure.
+ """
+ try:
+ try:
+ controller.setup()
+ if not buffer_output:
+ controller.print_extra_info()
+ controller.launch(buffer_output=buffer_output)
+ except Exception:
+ import traceback
+ traceback.print_exc()
+ return controller, 1 # signal failure
+
+ exitcode = controller.wait()
+ return controller, exitcode
+
+ except KeyboardInterrupt:
+ return controller, -signal.SIGINT
+ finally:
+ controller.cleanup()
+
+def report():
+ """Return a string with a summary report of test-related variables."""
+ inf = get_sys_info()
+ out = []
+ def _add(name, value):
+ out.append((name, value))
+
+ _add('IPython version', inf['ipython_version'])
+ _add('IPython commit', "{} ({})".format(inf['commit_hash'], inf['commit_source']))
+ _add('IPython package', compress_user(inf['ipython_path']))
+ _add('Python version', inf['sys_version'].replace('\n',''))
+ _add('sys.executable', compress_user(inf['sys_executable']))
+ _add('Platform', inf['platform'])
+
+ width = max(len(n) for (n,v) in out)
+ out = ["{:<{width}}: {}\n".format(n, v, width=width) for (n,v) in out]
+
+ avail = []
+ not_avail = []
+
+ for k, is_avail in have.items():
+ if is_avail:
+ avail.append(k)
+ else:
+ not_avail.append(k)
+
+ if avail:
+ out.append('\nTools and libraries available at test time:\n')
+ avail.sort()
+ out.append(' ' + ' '.join(avail)+'\n')
+
+ if not_avail:
+ out.append('\nTools and libraries NOT available at test time:\n')
+ not_avail.sort()
+ out.append(' ' + ' '.join(not_avail)+'\n')
+
+ return ''.join(out)
+
+def run_iptestall(options):
+ """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.
+
+ Parameters
+ ----------
+
+ All parameters are passed as attributes of the options object.
+
+ testgroups : list of str
+ Run only these sections of the test suite. If empty, run all the available
+ sections.
+
+ fast : int or None
+ Run the test suite in parallel, using n simultaneous processes. If None
+ is passed, one process is used per CPU core. Default 1 (i.e. sequential)
+
+ inc_slow : bool
+ Include slow tests. By default, these tests aren't run.
+
+ url : unicode
+ Address:port to use when running the JS tests.
+
+ xunit : bool
+ Produce Xunit XML output. This is written to multiple foo.xunit.xml files.
+
+ coverage : bool or str
+ Measure code coverage from tests. True will store the raw coverage data,
+ or pass 'html' or 'xml' to get reports.
+
+ extra_args : list
+ Extra arguments to pass to the test subprocesses, e.g. '-v'
+ """
+ to_run, not_run = prepare_controllers(options)
+
+ def justify(ltext, rtext, width=70, fill='-'):
+ ltext += ' '
+ rtext = (' ' + rtext).rjust(width - len(ltext), fill)
+ return ltext + rtext
+
+ # Run all test runners, tracking execution time
+ failed = []
+ t_start = time.time()
+
+ print()
+ if options.fast == 1:
+ # This actually means sequential, i.e. with 1 job
+ for controller in to_run:
+ print('Test group:', controller.section)
+ sys.stdout.flush() # Show in correct order when output is piped
+ controller, res = do_run(controller, buffer_output=False)
+ if res:
+ failed.append(controller)
+ if res == -signal.SIGINT:
+ print("Interrupted")
+ break
+ print()
+
+ else:
+ # Run tests concurrently
+ try:
+ pool = multiprocessing.pool.ThreadPool(options.fast)
+ for (controller, res) in pool.imap_unordered(do_run, to_run):
+ res_string = 'OK' if res == 0 else 'FAILED'
+ print(justify('Test group: ' + controller.section, res_string))
+ if res:
+ controller.print_extra_info()
+ print(bytes_to_str(controller.stdout))
+ failed.append(controller)
+ if res == -signal.SIGINT:
+ print("Interrupted")
+ break
+ except KeyboardInterrupt:
+ return
+
+ for controller in not_run:
+ print(justify('Test group: ' + controller.section, 'NOT RUN'))
+
+ t_end = time.time()
+ t_tests = t_end - t_start
+ nrunners = len(to_run)
+ nfail = len(failed)
+ # summarize results
+ print('_'*70)
+ print('Test suite completed for system with the following information:')
+ print(report())
+ took = "Took %.3fs." % t_tests
+ print('Status: ', end='')
+ if not failed:
+ print('OK (%d test groups).' % nrunners, took)
+ else:
+ # If anything went wrong, point out what command to rerun manually to
+ # see the actual errors and individual summary
+ failed_sections = [c.section for c in failed]
+ print('ERROR - {} out of {} test groups failed ({}).'.format(nfail,
+ nrunners, ', '.join(failed_sections)), took)
+ print()
+ print('You may wish to rerun these, with:')
+ print(' iptest', *failed_sections)
+ print()
+
+ if options.coverage:
+ from coverage import coverage, CoverageException
+ cov = coverage(data_file='.coverage')
+ cov.combine()
+ cov.save()
+
+ # Coverage HTML report
+ if options.coverage == 'html':
+ html_dir = 'ipy_htmlcov'
+ shutil.rmtree(html_dir, ignore_errors=True)
+ print("Writing HTML coverage report to %s/ ... " % html_dir, end="")
+ sys.stdout.flush()
+
+ # Custom HTML reporter to clean up module names.
+ from coverage.html import HtmlReporter
+ class CustomHtmlReporter(HtmlReporter):
+ def find_code_units(self, morfs):
+ super(CustomHtmlReporter, self).find_code_units(morfs)
+ for cu in self.code_units:
+ nameparts = cu.name.split(os.sep)
+ if 'IPython' not in nameparts:
+ continue
+ ix = nameparts.index('IPython')
+ cu.name = '.'.join(nameparts[ix:])
+
+ # Reimplement the html_report method with our custom reporter
+ cov.get_data()
+ cov.config.from_args(omit='*{0}tests{0}*'.format(os.sep), html_dir=html_dir,
+ html_title='IPython test coverage',
+ )
+ reporter = CustomHtmlReporter(cov, cov.config)
+ reporter.report(None)
+ print('done.')
+
+ # Coverage XML report
+ elif options.coverage == 'xml':
+ try:
+ cov.xml_report(outfile='ipy_coverage.xml')
+ except CoverageException as e:
+ print('Generating coverage report failed. Are you running javascript tests only?')
+ import traceback
+ traceback.print_exc()
+
+ if failed:
+ # Ensure that our exit code indicates failure
+ sys.exit(1)
+
+argparser = argparse.ArgumentParser(description='Run IPython test suite')
+argparser.add_argument('testgroups', nargs='*',
+ help='Run specified groups of tests. If omitted, run '
+ 'all tests.')
+argparser.add_argument('--all', action='store_true',
+ help='Include slow tests not run by default.')
+argparser.add_argument('--url', help="URL to use for the JS tests.")
+argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int,
+ help='Run test sections in parallel. This starts as many '
+ 'processes as you have cores, or you can specify a number.')
+argparser.add_argument('--xunit', action='store_true',
+ help='Produce Xunit XML results')
+argparser.add_argument('--coverage', nargs='?', const=True, default=False,
+ help="Measure test coverage. Specify 'html' or "
+ "'xml' to get reports.")
+argparser.add_argument('--subproc-streams', default='capture',
+ help="What to do with stdout/stderr from subprocesses. "
+ "'capture' (default), 'show' and 'discard' are the options.")
+
+def default_options():
+ """Get an argparse Namespace object with the default arguments, to pass to
+ :func:`run_iptestall`.
+ """
+ options = argparser.parse_args([])
+ options.extra_args = []
+ return options
+
+def main():
+ # iptest doesn't work correctly if the working directory is the
+ # root of the IPython source tree. Tell the user to avoid
+ # frustration.
+ if os.path.exists(os.path.join(os.getcwd(),
+ 'IPython', 'testing', '__main__.py')):
+ print("Don't run iptest from the IPython source directory",
+ file=sys.stderr)
+ sys.exit(1)
+ # Arguments after -- should be passed through to nose. Argparse treats
+ # everything after -- as regular positional arguments, so we separate them
+ # first.
+ try:
+ ix = sys.argv.index('--')
+ except ValueError:
+ to_parse = sys.argv[1:]
+ extra_args = []
+ else:
+ to_parse = sys.argv[1:ix]
+ extra_args = sys.argv[ix+1:]
+
+ options = argparser.parse_args(to_parse)
+ options.extra_args = extra_args
+
+ run_iptestall(options)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/python/ipython/py2/IPython/testing/ipunittest.py b/contrib/python/ipython/py2/IPython/testing/ipunittest.py
index da059816e2..04ea8320fb 100644
--- a/contrib/python/ipython/py2/IPython/testing/ipunittest.py
+++ b/contrib/python/ipython/py2/IPython/testing/ipunittest.py
@@ -1,178 +1,178 @@
-"""Experimental code for cleaner support of IPython syntax with unittest.
-
-In IPython up until 0.10, we've used very hacked up nose machinery for running
-tests with IPython special syntax, and this has proved to be extremely slow.
-This module provides decorators to try a different approach, stemming from a
-conversation Brian and I (FP) had about this problem Sept/09.
-
-The goal is to be able to easily write simple functions that can be seen by
-unittest as tests, and ultimately for these to support doctests with full
-IPython syntax. Nose already offers this based on naming conventions and our
-hackish plugins, but we are seeking to move away from nose dependencies if
-possible.
-
-This module follows a different approach, based on decorators.
-
-- A decorator called @ipdoctest can mark any function as having a docstring
- that should be viewed as a doctest, but after syntax conversion.
-
-Authors
--------
-
-- Fernando Perez <Fernando.Perez@berkeley.edu>
-"""
-
-from __future__ import absolute_import
-
-#-----------------------------------------------------------------------------
-# Copyright (C) 2009-2011 The IPython Development Team
-#
-# Distributed under the terms of the BSD License. The full license is in
-# the file COPYING, distributed as part of this software.
-#-----------------------------------------------------------------------------
-
-#-----------------------------------------------------------------------------
-# Imports
-#-----------------------------------------------------------------------------
-
-# Stdlib
-import re
-import unittest
-from doctest import DocTestFinder, DocTestRunner, TestResults
-
-#-----------------------------------------------------------------------------
-# Classes and functions
-#-----------------------------------------------------------------------------
-
-def count_failures(runner):
- """Count number of failures in a doctest runner.
-
- Code modeled after the summarize() method in doctest.
- """
- return [TestResults(f, t) for f, t in runner._name2ft.values() if f > 0 ]
-
-
-class IPython2PythonConverter(object):
- """Convert IPython 'syntax' to valid Python.
-
- Eventually this code may grow to be the full IPython syntax conversion
- implementation, but for now it only does prompt convertion."""
-
- def __init__(self):
- self.rps1 = re.compile(r'In\ \[\d+\]: ')
- self.rps2 = re.compile(r'\ \ \ \.\.\.+: ')
- self.rout = re.compile(r'Out\[\d+\]: \s*?\n?')
- self.pyps1 = '>>> '
- self.pyps2 = '... '
- self.rpyps1 = re.compile ('(\s*%s)(.*)$' % self.pyps1)
- self.rpyps2 = re.compile ('(\s*%s)(.*)$' % self.pyps2)
-
- def __call__(self, ds):
- """Convert IPython prompts to python ones in a string."""
- from . import globalipapp
-
- pyps1 = '>>> '
- pyps2 = '... '
- pyout = ''
-
- dnew = ds
- dnew = self.rps1.sub(pyps1, dnew)
- dnew = self.rps2.sub(pyps2, dnew)
- dnew = self.rout.sub(pyout, dnew)
- ip = globalipapp.get_ipython()
-
- # Convert input IPython source into valid Python.
- out = []
- newline = out.append
- for line in dnew.splitlines():
-
- mps1 = self.rpyps1.match(line)
- if mps1 is not None:
- prompt, text = mps1.groups()
- newline(prompt+ip.prefilter(text, False))
- continue
-
- mps2 = self.rpyps2.match(line)
- if mps2 is not None:
- prompt, text = mps2.groups()
- newline(prompt+ip.prefilter(text, True))
- continue
-
- newline(line)
- newline('') # ensure a closing newline, needed by doctest
- #print "PYSRC:", '\n'.join(out) # dbg
- return '\n'.join(out)
-
- #return dnew
-
-
-class Doc2UnitTester(object):
- """Class whose instances act as a decorator for docstring testing.
-
- In practice we're only likely to need one instance ever, made below (though
- no attempt is made at turning it into a singleton, there is no need for
- that).
- """
- def __init__(self, verbose=False):
- """New decorator.
-
- Parameters
- ----------
-
- verbose : boolean, optional (False)
- Passed to the doctest finder and runner to control verbosity.
- """
- self.verbose = verbose
- # We can reuse the same finder for all instances
- self.finder = DocTestFinder(verbose=verbose, recurse=False)
-
- def __call__(self, func):
- """Use as a decorator: doctest a function's docstring as a unittest.
-
- This version runs normal doctests, but the idea is to make it later run
- ipython syntax instead."""
-
- # Capture the enclosing instance with a different name, so the new
- # class below can see it without confusion regarding its own 'self'
- # that will point to the test instance at runtime
- d2u = self
-
- # Rewrite the function's docstring to have python syntax
- if func.__doc__ is not None:
- func.__doc__ = ip2py(func.__doc__)
-
- # Now, create a tester object that is a real unittest instance, so
- # normal unittest machinery (or Nose, or Trial) can find it.
- class Tester(unittest.TestCase):
- def test(self):
- # Make a new runner per function to be tested
- runner = DocTestRunner(verbose=d2u.verbose)
+"""Experimental code for cleaner support of IPython syntax with unittest.
+
+In IPython up until 0.10, we've used very hacked up nose machinery for running
+tests with IPython special syntax, and this has proved to be extremely slow.
+This module provides decorators to try a different approach, stemming from a
+conversation Brian and I (FP) had about this problem Sept/09.
+
+The goal is to be able to easily write simple functions that can be seen by
+unittest as tests, and ultimately for these to support doctests with full
+IPython syntax. Nose already offers this based on naming conventions and our
+hackish plugins, but we are seeking to move away from nose dependencies if
+possible.
+
+This module follows a different approach, based on decorators.
+
+- A decorator called @ipdoctest can mark any function as having a docstring
+ that should be viewed as a doctest, but after syntax conversion.
+
+Authors
+-------
+
+- Fernando Perez <Fernando.Perez@berkeley.edu>
+"""
+
+from __future__ import absolute_import
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2009-2011 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Stdlib
+import re
+import unittest
+from doctest import DocTestFinder, DocTestRunner, TestResults
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+def count_failures(runner):
+ """Count number of failures in a doctest runner.
+
+ Code modeled after the summarize() method in doctest.
+ """
+ return [TestResults(f, t) for f, t in runner._name2ft.values() if f > 0 ]
+
+
+class IPython2PythonConverter(object):
+ """Convert IPython 'syntax' to valid Python.
+
+ Eventually this code may grow to be the full IPython syntax conversion
+ implementation, but for now it only does prompt convertion."""
+
+ def __init__(self):
+ self.rps1 = re.compile(r'In\ \[\d+\]: ')
+ self.rps2 = re.compile(r'\ \ \ \.\.\.+: ')
+ self.rout = re.compile(r'Out\[\d+\]: \s*?\n?')
+ self.pyps1 = '>>> '
+ self.pyps2 = '... '
+ self.rpyps1 = re.compile ('(\s*%s)(.*)$' % self.pyps1)
+ self.rpyps2 = re.compile ('(\s*%s)(.*)$' % self.pyps2)
+
+ def __call__(self, ds):
+ """Convert IPython prompts to python ones in a string."""
+ from . import globalipapp
+
+ pyps1 = '>>> '
+ pyps2 = '... '
+ pyout = ''
+
+ dnew = ds
+ dnew = self.rps1.sub(pyps1, dnew)
+ dnew = self.rps2.sub(pyps2, dnew)
+ dnew = self.rout.sub(pyout, dnew)
+ ip = globalipapp.get_ipython()
+
+ # Convert input IPython source into valid Python.
+ out = []
+ newline = out.append
+ for line in dnew.splitlines():
+
+ mps1 = self.rpyps1.match(line)
+ if mps1 is not None:
+ prompt, text = mps1.groups()
+ newline(prompt+ip.prefilter(text, False))
+ continue
+
+ mps2 = self.rpyps2.match(line)
+ if mps2 is not None:
+ prompt, text = mps2.groups()
+ newline(prompt+ip.prefilter(text, True))
+ continue
+
+ newline(line)
+ newline('') # ensure a closing newline, needed by doctest
+ #print "PYSRC:", '\n'.join(out) # dbg
+ return '\n'.join(out)
+
+ #return dnew
+
+
+class Doc2UnitTester(object):
+ """Class whose instances act as a decorator for docstring testing.
+
+ In practice we're only likely to need one instance ever, made below (though
+ no attempt is made at turning it into a singleton, there is no need for
+ that).
+ """
+ def __init__(self, verbose=False):
+ """New decorator.
+
+ Parameters
+ ----------
+
+ verbose : boolean, optional (False)
+ Passed to the doctest finder and runner to control verbosity.
+ """
+ self.verbose = verbose
+ # We can reuse the same finder for all instances
+ self.finder = DocTestFinder(verbose=verbose, recurse=False)
+
+ def __call__(self, func):
+ """Use as a decorator: doctest a function's docstring as a unittest.
+
+ This version runs normal doctests, but the idea is to make it later run
+ ipython syntax instead."""
+
+ # Capture the enclosing instance with a different name, so the new
+ # class below can see it without confusion regarding its own 'self'
+ # that will point to the test instance at runtime
+ d2u = self
+
+ # Rewrite the function's docstring to have python syntax
+ if func.__doc__ is not None:
+ func.__doc__ = ip2py(func.__doc__)
+
+ # Now, create a tester object that is a real unittest instance, so
+ # normal unittest machinery (or Nose, or Trial) can find it.
+ class Tester(unittest.TestCase):
+ def test(self):
+ # Make a new runner per function to be tested
+ runner = DocTestRunner(verbose=d2u.verbose)
for the_test in d2u.finder.find(func, func.__name__):
runner.run(the_test)
- failed = count_failures(runner)
- if failed:
- # Since we only looked at a single function's docstring,
- # failed should contain at most one item. More than that
- # is a case we can't handle and should error out on
- if len(failed) > 1:
- err = "Invalid number of test results:" % failed
- raise ValueError(err)
- # Report a normal failure.
- self.fail('failed doctests: %s' % str(failed[0]))
-
- # Rename it so test reports have the original signature.
- Tester.__name__ = func.__name__
- return Tester
-
-
-def ipdocstring(func):
- """Change the function docstring via ip2py.
- """
- if func.__doc__ is not None:
- func.__doc__ = ip2py(func.__doc__)
- return func
-
-
-# Make an instance of the classes for public use
-ipdoctest = Doc2UnitTester()
-ip2py = IPython2PythonConverter()
+ failed = count_failures(runner)
+ if failed:
+ # Since we only looked at a single function's docstring,
+ # failed should contain at most one item. More than that
+ # is a case we can't handle and should error out on
+ if len(failed) > 1:
+ err = "Invalid number of test results:" % failed
+ raise ValueError(err)
+ # Report a normal failure.
+ self.fail('failed doctests: %s' % str(failed[0]))
+
+ # Rename it so test reports have the original signature.
+ Tester.__name__ = func.__name__
+ return Tester
+
+
+def ipdocstring(func):
+ """Change the function docstring via ip2py.
+ """
+ if func.__doc__ is not None:
+ func.__doc__ = ip2py(func.__doc__)
+ return func
+
+
+# Make an instance of the classes for public use
+ipdoctest = Doc2UnitTester()
+ip2py = IPython2PythonConverter()
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/Makefile b/contrib/python/ipython/py2/IPython/testing/plugin/Makefile
index 6f999a38fd..d57d198f15 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/Makefile
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/Makefile
@@ -1,74 +1,74 @@
-# Set this prefix to where you want to install the plugin
-PREFIX=/usr/local
-
-NOSE0=nosetests -vs --with-doctest --doctest-tests --detailed-errors
-NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt \
---detailed-errors
-
-SRC=ipdoctest.py setup.py ../decorators.py
-
-# Default target for clean 'make'
-default: interactiveshell
-
-# The actual plugin installation
-plugin: IPython_doctest_plugin.egg-info
-
-# Simple targets that test one thing
-simple: plugin simple.py
- $(NOSE) simple.py
-
-dtest: plugin dtexample.py
- $(NOSE) dtexample.py
-
-rtest: plugin test_refs.py
- $(NOSE) test_refs.py
-
-test: plugin dtexample.py
- $(NOSE) dtexample.py test*.py test*.txt
-
-deb: plugin dtexample.py
- $(NOSE) test_combo.txt
-
-# IPython tests
-deco:
- $(NOSE0) IPython.testing.decorators
-
-magic: plugin
- $(NOSE) IPython.core.magic
-
-excolors: plugin
- $(NOSE) IPython.core.excolors
-
-interactiveshell: plugin
- $(NOSE) IPython.core.interactiveshell
-
-strd: plugin
- $(NOSE) IPython.core.strdispatch
-
-engine: plugin
- $(NOSE) IPython.kernel
-
-tf: plugin
- $(NOSE) IPython.config.traitlets
-
-# All of ipython itself
-ipython: plugin
- $(NOSE) IPython
-
-
-# Combined targets
-sr: rtest strd
-
-base: dtest rtest test strd deco
-
-quick: base interactiveshell ipipe
-
-all: base ipython
-
-# Main plugin and cleanup
-IPython_doctest_plugin.egg-info: $(SRC)
- python setup.py install --prefix=$(PREFIX)
- touch $@
-
-clean:
- rm -rf IPython_doctest_plugin.egg-info *~ *pyc build/ dist/
+# Set this prefix to where you want to install the plugin
+PREFIX=/usr/local
+
+NOSE0=nosetests -vs --with-doctest --doctest-tests --detailed-errors
+NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt \
+--detailed-errors
+
+SRC=ipdoctest.py setup.py ../decorators.py
+
+# Default target for clean 'make'
+default: interactiveshell
+
+# The actual plugin installation
+plugin: IPython_doctest_plugin.egg-info
+
+# Simple targets that test one thing
+simple: plugin simple.py
+ $(NOSE) simple.py
+
+dtest: plugin dtexample.py
+ $(NOSE) dtexample.py
+
+rtest: plugin test_refs.py
+ $(NOSE) test_refs.py
+
+test: plugin dtexample.py
+ $(NOSE) dtexample.py test*.py test*.txt
+
+deb: plugin dtexample.py
+ $(NOSE) test_combo.txt
+
+# IPython tests
+deco:
+ $(NOSE0) IPython.testing.decorators
+
+magic: plugin
+ $(NOSE) IPython.core.magic
+
+excolors: plugin
+ $(NOSE) IPython.core.excolors
+
+interactiveshell: plugin
+ $(NOSE) IPython.core.interactiveshell
+
+strd: plugin
+ $(NOSE) IPython.core.strdispatch
+
+engine: plugin
+ $(NOSE) IPython.kernel
+
+tf: plugin
+ $(NOSE) IPython.config.traitlets
+
+# All of ipython itself
+ipython: plugin
+ $(NOSE) IPython
+
+
+# Combined targets
+sr: rtest strd
+
+base: dtest rtest test strd deco
+
+quick: base interactiveshell ipipe
+
+all: base ipython
+
+# Main plugin and cleanup
+IPython_doctest_plugin.egg-info: $(SRC)
+ python setup.py install --prefix=$(PREFIX)
+ touch $@
+
+clean:
+ rm -rf IPython_doctest_plugin.egg-info *~ *pyc build/ dist/
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/README.txt b/contrib/python/ipython/py2/IPython/testing/plugin/README.txt
index 6b34f9e5e1..e08380d9de 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/README.txt
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/README.txt
@@ -1,39 +1,39 @@
-=======================================================
- Nose plugin with IPython and extension module support
-=======================================================
-
-This directory provides the key functionality for test support that IPython
-needs as a nose plugin, which can be installed for use in projects other than
-IPython.
-
-The presence of a Makefile here is mostly for development and debugging
-purposes as it only provides a few shorthand commands. You can manually
-install the plugin by using standard Python procedures (``setup.py install``
-with appropriate arguments).
-
-To install the plugin using the Makefile, edit its first line to reflect where
-you'd like the installation. If you want it system-wide, you may want to edit
-the install line in the plugin target to use sudo and no prefix::
-
- sudo python setup.py install
-
-instead of the code using `--prefix` that's in there.
-
-Once you've set the prefix, simply build/install the plugin with::
-
- make
-
-and run the tests with::
-
- make test
-
-You should see output similar to::
-
- maqroll[plugin]> make test
- nosetests -s --with-ipdoctest --doctest-tests dtexample.py
- ..
- ----------------------------------------------------------------------
- Ran 2 tests in 0.016s
-
- OK
-
+=======================================================
+ Nose plugin with IPython and extension module support
+=======================================================
+
+This directory provides the key functionality for test support that IPython
+needs as a nose plugin, which can be installed for use in projects other than
+IPython.
+
+The presence of a Makefile here is mostly for development and debugging
+purposes as it only provides a few shorthand commands. You can manually
+install the plugin by using standard Python procedures (``setup.py install``
+with appropriate arguments).
+
+To install the plugin using the Makefile, edit its first line to reflect where
+you'd like the installation. If you want it system-wide, you may want to edit
+the install line in the plugin target to use sudo and no prefix::
+
+ sudo python setup.py install
+
+instead of the code using `--prefix` that's in there.
+
+Once you've set the prefix, simply build/install the plugin with::
+
+ make
+
+and run the tests with::
+
+ make test
+
+You should see output similar to::
+
+ maqroll[plugin]> make test
+ nosetests -s --with-ipdoctest --doctest-tests dtexample.py
+ ..
+ ----------------------------------------------------------------------
+ Ran 2 tests in 0.016s
+
+ OK
+
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/dtexample.py b/contrib/python/ipython/py2/IPython/testing/plugin/dtexample.py
index 5e02629bf7..081bf35571 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/dtexample.py
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/dtexample.py
@@ -1,158 +1,158 @@
-"""Simple example using doctests.
-
-This file just contains doctests both using plain python and IPython prompts.
-All tests should be loaded by nose.
-"""
-from __future__ import print_function
-
-def pyfunc():
- """Some pure python tests...
-
- >>> pyfunc()
- 'pyfunc'
-
- >>> import os
-
- >>> 2+3
- 5
-
- >>> for i in range(3):
- ... print(i, end=' ')
- ... print(i+1, end=' ')
- ...
- 0 1 1 2 2 3
- """
- return 'pyfunc'
-
-def ipfunc():
- """Some ipython tests...
-
- In [1]: import os
-
- In [3]: 2+3
- Out[3]: 5
-
- In [26]: for i in range(3):
- ....: print(i, end=' ')
- ....: print(i+1, end=' ')
- ....:
- 0 1 1 2 2 3
-
-
- Examples that access the operating system work:
-
- In [1]: !echo hello
- hello
-
- In [2]: !echo hello > /tmp/foo_iptest
-
- In [3]: !cat /tmp/foo_iptest
- hello
-
- In [4]: rm -f /tmp/foo_iptest
-
- It's OK to use '_' for the last result, but do NOT try to use IPython's
- numbered history of _NN outputs, since those won't exist under the
- doctest environment:
-
- In [7]: 'hi'
- Out[7]: 'hi'
-
- In [8]: print(repr(_))
- 'hi'
-
- In [7]: 3+4
- Out[7]: 7
-
- In [8]: _+3
- Out[8]: 10
-
- In [9]: ipfunc()
- Out[9]: 'ipfunc'
- """
- return 'ipfunc'
-
-
-def ranfunc():
- """A function with some random output.
-
- Normal examples are verified as usual:
- >>> 1+3
- 4
-
- But if you put '# random' in the output, it is ignored:
- >>> 1+3
- junk goes here... # random
-
- >>> 1+2
- again, anything goes #random
- if multiline, the random mark is only needed once.
-
- >>> 1+2
- You can also put the random marker at the end:
- # random
-
- >>> 1+2
- # random
- .. or at the beginning.
-
- More correct input is properly verified:
- >>> ranfunc()
- 'ranfunc'
- """
- return 'ranfunc'
-
-
-def random_all():
- """A function where we ignore the output of ALL examples.
-
- Examples:
-
- # all-random
-
- This mark tells the testing machinery that all subsequent examples should
- be treated as random (ignoring their output). They are still executed,
- so if a they raise an error, it will be detected as such, but their
- output is completely ignored.
-
- >>> 1+3
- junk goes here...
-
- >>> 1+3
- klasdfj;
-
- >>> 1+2
- again, anything goes
- blah...
- """
- pass
-
-def iprand():
- """Some ipython tests with random output.
-
- In [7]: 3+4
- Out[7]: 7
-
- In [8]: print('hello')
- world # random
-
- In [9]: iprand()
- Out[9]: 'iprand'
- """
- return 'iprand'
-
-def iprand_all():
- """Some ipython tests with fully random output.
-
- # all-random
-
- In [7]: 1
- Out[7]: 99
-
- In [8]: print('hello')
- world
-
- In [9]: iprand_all()
- Out[9]: 'junk'
- """
- return 'iprand_all'
+"""Simple example using doctests.
+
+This file just contains doctests both using plain python and IPython prompts.
+All tests should be loaded by nose.
+"""
+from __future__ import print_function
+
+def pyfunc():
+ """Some pure python tests...
+
+ >>> pyfunc()
+ 'pyfunc'
+
+ >>> import os
+
+ >>> 2+3
+ 5
+
+ >>> for i in range(3):
+ ... print(i, end=' ')
+ ... print(i+1, end=' ')
+ ...
+ 0 1 1 2 2 3
+ """
+ return 'pyfunc'
+
+def ipfunc():
+ """Some ipython tests...
+
+ In [1]: import os
+
+ In [3]: 2+3
+ Out[3]: 5
+
+ In [26]: for i in range(3):
+ ....: print(i, end=' ')
+ ....: print(i+1, end=' ')
+ ....:
+ 0 1 1 2 2 3
+
+
+ Examples that access the operating system work:
+
+ In [1]: !echo hello
+ hello
+
+ In [2]: !echo hello > /tmp/foo_iptest
+
+ In [3]: !cat /tmp/foo_iptest
+ hello
+
+ In [4]: rm -f /tmp/foo_iptest
+
+ It's OK to use '_' for the last result, but do NOT try to use IPython's
+ numbered history of _NN outputs, since those won't exist under the
+ doctest environment:
+
+ In [7]: 'hi'
+ Out[7]: 'hi'
+
+ In [8]: print(repr(_))
+ 'hi'
+
+ In [7]: 3+4
+ Out[7]: 7
+
+ In [8]: _+3
+ Out[8]: 10
+
+ In [9]: ipfunc()
+ Out[9]: 'ipfunc'
+ """
+ return 'ipfunc'
+
+
+def ranfunc():
+ """A function with some random output.
+
+ Normal examples are verified as usual:
+ >>> 1+3
+ 4
+
+ But if you put '# random' in the output, it is ignored:
+ >>> 1+3
+ junk goes here... # random
+
+ >>> 1+2
+ again, anything goes #random
+ if multiline, the random mark is only needed once.
+
+ >>> 1+2
+ You can also put the random marker at the end:
+ # random
+
+ >>> 1+2
+ # random
+ .. or at the beginning.
+
+ More correct input is properly verified:
+ >>> ranfunc()
+ 'ranfunc'
+ """
+ return 'ranfunc'
+
+
+def random_all():
+ """A function where we ignore the output of ALL examples.
+
+ Examples:
+
+ # all-random
+
+ This mark tells the testing machinery that all subsequent examples should
+ be treated as random (ignoring their output). They are still executed,
+ so if a they raise an error, it will be detected as such, but their
+ output is completely ignored.
+
+ >>> 1+3
+ junk goes here...
+
+ >>> 1+3
+ klasdfj;
+
+ >>> 1+2
+ again, anything goes
+ blah...
+ """
+ pass
+
+def iprand():
+ """Some ipython tests with random output.
+
+ In [7]: 3+4
+ Out[7]: 7
+
+ In [8]: print('hello')
+ world # random
+
+ In [9]: iprand()
+ Out[9]: 'iprand'
+ """
+ return 'iprand'
+
+def iprand_all():
+ """Some ipython tests with fully random output.
+
+ # all-random
+
+ In [7]: 1
+ Out[7]: 99
+
+ In [8]: print('hello')
+ world
+
+ In [9]: iprand_all()
+ Out[9]: 'junk'
+ """
+ return 'iprand_all'
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/ipdoctest.py b/contrib/python/ipython/py2/IPython/testing/plugin/ipdoctest.py
index bc750e0efd..64e7e536f8 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/ipdoctest.py
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/ipdoctest.py
@@ -1,769 +1,769 @@
-"""Nose Plugin that supports IPython doctests.
-
-Limitations:
-
-- When generating examples for use as doctests, make sure that you have
- pretty-printing OFF. This can be done either by setting the
- ``PlainTextFormatter.pprint`` option in your configuration file to False, or
- by interactively disabling it with %Pprint. This is required so that IPython
- output matches that of normal Python, which is used by doctest for internal
- execution.
-
-- Do not rely on specific prompt numbers for results (such as using
- '_34==True', for example). For IPython tests run via an external process the
- prompt numbers may be different, and IPython tests run as normal python code
- won't even have these special _NN variables set at all.
-"""
-
-#-----------------------------------------------------------------------------
-# Module imports
-
-# From the standard library
-import doctest
-import inspect
-import logging
-import os
-import re
-import sys
-
+"""Nose Plugin that supports IPython doctests.
+
+Limitations:
+
+- When generating examples for use as doctests, make sure that you have
+ pretty-printing OFF. This can be done either by setting the
+ ``PlainTextFormatter.pprint`` option in your configuration file to False, or
+ by interactively disabling it with %Pprint. This is required so that IPython
+ output matches that of normal Python, which is used by doctest for internal
+ execution.
+
+- Do not rely on specific prompt numbers for results (such as using
+ '_34==True', for example). For IPython tests run via an external process the
+ prompt numbers may be different, and IPython tests run as normal python code
+ won't even have these special _NN variables set at all.
+"""
+
+#-----------------------------------------------------------------------------
+# Module imports
+
+# From the standard library
+import doctest
+import inspect
+import logging
+import os
+import re
+import sys
+
from testpath import modified_env
-from inspect import getmodule
-
-# We are overriding the default doctest runner, so we need to import a few
-# things from doctest directly
-from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
- _unittest_reportflags, DocTestRunner,
- _extract_future_flags, pdb, _OutputRedirectingPdb,
- _exception_traceback,
- linecache)
-
-# Third-party modules
-
-from nose.plugins import doctests, Plugin
+from inspect import getmodule
+
+# We are overriding the default doctest runner, so we need to import a few
+# things from doctest directly
+from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
+ _unittest_reportflags, DocTestRunner,
+ _extract_future_flags, pdb, _OutputRedirectingPdb,
+ _exception_traceback,
+ linecache)
+
+# Third-party modules
+
+from nose.plugins import doctests, Plugin
from nose.util import anyp, tolist
-
-# Our own imports
-from IPython.utils.py3compat import builtin_mod, PY3, getcwd
-
-if PY3:
- from io import StringIO
-else:
- from StringIO import StringIO
-
-#-----------------------------------------------------------------------------
-# Module globals and other constants
-#-----------------------------------------------------------------------------
-
-log = logging.getLogger(__name__)
-
-
-#-----------------------------------------------------------------------------
-# Classes and functions
-#-----------------------------------------------------------------------------
-
-def is_extension_module(filename):
- """Return whether the given filename is an extension module.
-
- This simply checks that the extension is either .so or .pyd.
- """
- return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
-
-
-class DocTestSkip(object):
- """Object wrapper for doctests to be skipped."""
-
- ds_skip = """Doctest to skip.
- >>> 1 #doctest: +SKIP
- """
-
- def __init__(self,obj):
- self.obj = obj
-
- def __getattribute__(self,key):
- if key == '__doc__':
- return DocTestSkip.ds_skip
- else:
- return getattr(object.__getattribute__(self,'obj'),key)
-
-# Modified version of the one in the stdlib, that fixes a python bug (doctests
-# not found in extension modules, http://bugs.python.org/issue3158)
-class DocTestFinder(doctest.DocTestFinder):
-
- def _from_module(self, module, object):
- """
- Return true if the given object is defined in the given
- module.
- """
- if module is None:
- return True
- elif inspect.isfunction(object):
- return module.__dict__ is object.__globals__
- elif inspect.isbuiltin(object):
- return module.__name__ == object.__module__
- elif inspect.isclass(object):
- return module.__name__ == object.__module__
- elif inspect.ismethod(object):
- # This one may be a bug in cython that fails to correctly set the
- # __module__ attribute of methods, but since the same error is easy
- # to make by extension code writers, having this safety in place
- # isn't such a bad idea
- return module.__name__ == object.__self__.__class__.__module__
- elif inspect.getmodule(object) is not None:
- return module is inspect.getmodule(object)
- elif hasattr(object, '__module__'):
- return module.__name__ == object.__module__
- elif isinstance(object, property):
- return True # [XX] no way not be sure.
- elif inspect.ismethoddescriptor(object):
- # Unbound PyQt signals reach this point in Python 3.4b3, and we want
- # to avoid throwing an error. See also http://bugs.python.org/issue3158
- return False
- else:
- raise ValueError("object must be a class or function, got %r" % object)
-
- def _find(self, tests, obj, name, module, source_lines, globs, seen):
- """
- Find tests for the given object and any contained objects, and
- add them to `tests`.
- """
- print('_find for:', obj, name, module) # dbg
- if hasattr(obj,"skip_doctest"):
- #print 'SKIPPING DOCTEST FOR:',obj # dbg
- obj = DocTestSkip(obj)
-
- doctest.DocTestFinder._find(self,tests, obj, name, module,
- source_lines, globs, seen)
-
- # Below we re-run pieces of the above method with manual modifications,
- # because the original code is buggy and fails to correctly identify
- # doctests in extension modules.
-
- # Local shorthands
+
+# Our own imports
+from IPython.utils.py3compat import builtin_mod, PY3, getcwd
+
+if PY3:
+ from io import StringIO
+else:
+ from StringIO import StringIO
+
+#-----------------------------------------------------------------------------
+# Module globals and other constants
+#-----------------------------------------------------------------------------
+
+log = logging.getLogger(__name__)
+
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+def is_extension_module(filename):
+ """Return whether the given filename is an extension module.
+
+ This simply checks that the extension is either .so or .pyd.
+ """
+ return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
+
+
+class DocTestSkip(object):
+ """Object wrapper for doctests to be skipped."""
+
+ ds_skip = """Doctest to skip.
+ >>> 1 #doctest: +SKIP
+ """
+
+ def __init__(self,obj):
+ self.obj = obj
+
+ def __getattribute__(self,key):
+ if key == '__doc__':
+ return DocTestSkip.ds_skip
+ else:
+ return getattr(object.__getattribute__(self,'obj'),key)
+
+# Modified version of the one in the stdlib, that fixes a python bug (doctests
+# not found in extension modules, http://bugs.python.org/issue3158)
+class DocTestFinder(doctest.DocTestFinder):
+
+ def _from_module(self, module, object):
+ """
+ Return true if the given object is defined in the given
+ module.
+ """
+ if module is None:
+ return True
+ elif inspect.isfunction(object):
+ return module.__dict__ is object.__globals__
+ elif inspect.isbuiltin(object):
+ return module.__name__ == object.__module__
+ elif inspect.isclass(object):
+ return module.__name__ == object.__module__
+ elif inspect.ismethod(object):
+ # This one may be a bug in cython that fails to correctly set the
+ # __module__ attribute of methods, but since the same error is easy
+ # to make by extension code writers, having this safety in place
+ # isn't such a bad idea
+ return module.__name__ == object.__self__.__class__.__module__
+ elif inspect.getmodule(object) is not None:
+ return module is inspect.getmodule(object)
+ elif hasattr(object, '__module__'):
+ return module.__name__ == object.__module__
+ elif isinstance(object, property):
+ return True # [XX] no way not be sure.
+ elif inspect.ismethoddescriptor(object):
+ # Unbound PyQt signals reach this point in Python 3.4b3, and we want
+ # to avoid throwing an error. See also http://bugs.python.org/issue3158
+ return False
+ else:
+ raise ValueError("object must be a class or function, got %r" % object)
+
+ def _find(self, tests, obj, name, module, source_lines, globs, seen):
+ """
+ Find tests for the given object and any contained objects, and
+ add them to `tests`.
+ """
+ print('_find for:', obj, name, module) # dbg
+ if hasattr(obj,"skip_doctest"):
+ #print 'SKIPPING DOCTEST FOR:',obj # dbg
+ obj = DocTestSkip(obj)
+
+ doctest.DocTestFinder._find(self,tests, obj, name, module,
+ source_lines, globs, seen)
+
+ # Below we re-run pieces of the above method with manual modifications,
+ # because the original code is buggy and fails to correctly identify
+ # doctests in extension modules.
+
+ # Local shorthands
from inspect import isroutine, isclass
-
- # Look for tests in a module's contained objects.
- if inspect.ismodule(obj) and self._recurse:
- for valname, val in obj.__dict__.items():
- valname1 = '%s.%s' % (name, valname)
- if ( (isroutine(val) or isclass(val))
- and self._from_module(module, val) ):
-
- self._find(tests, val, valname1, module, source_lines,
- globs, seen)
-
- # Look for tests in a class's contained objects.
- if inspect.isclass(obj) and self._recurse:
- #print 'RECURSE into class:',obj # dbg
- for valname, val in obj.__dict__.items():
- # Special handling for staticmethod/classmethod.
- if isinstance(val, staticmethod):
- val = getattr(obj, valname)
- if isinstance(val, classmethod):
- val = getattr(obj, valname).__func__
-
- # Recurse to methods, properties, and nested classes.
- if ((inspect.isfunction(val) or inspect.isclass(val) or
- inspect.ismethod(val) or
- isinstance(val, property)) and
- self._from_module(module, val)):
- valname = '%s.%s' % (name, valname)
- self._find(tests, val, valname, module, source_lines,
- globs, seen)
-
-
-class IPDoctestOutputChecker(doctest.OutputChecker):
- """Second-chance checker with support for random tests.
-
- If the default comparison doesn't pass, this checker looks in the expected
- output string for flags that tell us to ignore the output.
- """
-
- random_re = re.compile(r'#\s*random\s+')
-
- def check_output(self, want, got, optionflags):
- """Check output, accepting special markers embedded in the output.
-
- If the output didn't pass the default validation but the special string
- '#random' is included, we accept it."""
-
- # Let the original tester verify first, in case people have valid tests
- # that happen to have a comment saying '#random' embedded in.
- ret = doctest.OutputChecker.check_output(self, want, got,
- optionflags)
- if not ret and self.random_re.search(want):
- #print >> sys.stderr, 'RANDOM OK:',want # dbg
- return True
-
- return ret
-
-
-class DocTestCase(doctests.DocTestCase):
- """Proxy for DocTestCase: provides an address() method that
- returns the correct address for the doctest case. Otherwise
- acts as a proxy to the test case. To provide hints for address(),
- an obj may also be passed -- this will be used as the test object
- for purposes of determining the test address, if it is provided.
- """
-
- # Note: this method was taken from numpy's nosetester module.
-
- # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
- # its constructor that blocks non-default arguments from being passed
- # down into doctest.DocTestCase
-
- def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
- checker=None, obj=None, result_var='_'):
- self._result_var = result_var
- doctests.DocTestCase.__init__(self, test,
- optionflags=optionflags,
- setUp=setUp, tearDown=tearDown,
- checker=checker)
- # Now we must actually copy the original constructor from the stdlib
- # doctest class, because we can't call it directly and a bug in nose
- # means it never gets passed the right arguments.
-
- self._dt_optionflags = optionflags
- self._dt_checker = checker
- self._dt_test = test
- self._dt_test_globs_ori = test.globs
- self._dt_setUp = setUp
- self._dt_tearDown = tearDown
-
- # XXX - store this runner once in the object!
- runner = IPDocTestRunner(optionflags=optionflags,
- checker=checker, verbose=False)
- self._dt_runner = runner
-
-
- # Each doctest should remember the directory it was loaded from, so
- # things like %run work without too many contortions
- self._ori_dir = os.path.dirname(test.filename)
-
- # Modified runTest from the default stdlib
- def runTest(self):
- test = self._dt_test
- runner = self._dt_runner
-
- old = sys.stdout
- new = StringIO()
- optionflags = self._dt_optionflags
-
- if not (optionflags & REPORTING_FLAGS):
- # The option flags don't include any reporting flags,
- # so add the default reporting flags
- optionflags |= _unittest_reportflags
-
- try:
- # Save our current directory and switch out to the one where the
- # test was originally created, in case another doctest did a
- # directory change. We'll restore this in the finally clause.
- curdir = getcwd()
- #print 'runTest in dir:', self._ori_dir # dbg
- os.chdir(self._ori_dir)
-
- runner.DIVIDER = "-"*70
- failures, tries = runner.run(test,out=new.write,
- clear_globs=False)
- finally:
- sys.stdout = old
- os.chdir(curdir)
-
- if failures:
- raise self.failureException(self.format_failure(new.getvalue()))
-
- def setUp(self):
- """Modified test setup that syncs with ipython namespace"""
- #print "setUp test", self._dt_test.examples # dbg
- if isinstance(self._dt_test.examples[0], IPExample):
- # for IPython examples *only*, we swap the globals with the ipython
- # namespace, after updating it with the globals (which doctest
- # fills with the necessary info from the module being tested).
- self.user_ns_orig = {}
- self.user_ns_orig.update(_ip.user_ns)
- _ip.user_ns.update(self._dt_test.globs)
- # We must remove the _ key in the namespace, so that Python's
- # doctest code sets it naturally
- _ip.user_ns.pop('_', None)
- _ip.user_ns['__builtins__'] = builtin_mod
- self._dt_test.globs = _ip.user_ns
-
- super(DocTestCase, self).setUp()
-
- def tearDown(self):
-
- # Undo the test.globs reassignment we made, so that the parent class
- # teardown doesn't destroy the ipython namespace
- if isinstance(self._dt_test.examples[0], IPExample):
- self._dt_test.globs = self._dt_test_globs_ori
- _ip.user_ns.clear()
- _ip.user_ns.update(self.user_ns_orig)
-
- # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
- # it does look like one to me: its tearDown method tries to run
- #
- # delattr(builtin_mod, self._result_var)
- #
- # without checking that the attribute really is there; it implicitly
- # assumes it should have been set via displayhook. But if the
- # displayhook was never called, this doesn't necessarily happen. I
- # haven't been able to find a little self-contained example outside of
- # ipython that would show the problem so I can report it to the nose
- # team, but it does happen a lot in our code.
- #
- # So here, we just protect as narrowly as possible by trapping an
- # attribute error whose message would be the name of self._result_var,
- # and letting any other error propagate.
- try:
- super(DocTestCase, self).tearDown()
- except AttributeError as exc:
- if exc.args[0] != self._result_var:
- raise
-
-
-# A simple subclassing of the original with a different class name, so we can
-# distinguish and treat differently IPython examples from pure python ones.
-class IPExample(doctest.Example): pass
-
-
-class IPExternalExample(doctest.Example):
- """Doctest examples to be run in an external process."""
-
- def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
- options=None):
- # Parent constructor
- doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
-
- # An EXTRA newline is needed to prevent pexpect hangs
- self.source += '\n'
-
-
-class IPDocTestParser(doctest.DocTestParser):
- """
- A class used to parse strings containing doctest examples.
-
- Note: This is a version modified to properly recognize IPython input and
- convert any IPython examples into valid Python ones.
- """
- # This regular expression is used to find doctest examples in a
- # string. It defines three groups: `source` is the source code
- # (including leading indentation and prompts); `indent` is the
- # indentation of the first (PS1) line of the source code; and
- # `want` is the expected output (including leading indentation).
-
- # Classic Python prompts or default IPython ones
- _PS1_PY = r'>>>'
- _PS2_PY = r'\.\.\.'
-
- _PS1_IP = r'In\ \[\d+\]:'
- _PS2_IP = r'\ \ \ \.\.\.+:'
-
- _RE_TPL = r'''
- # Source consists of a PS1 line followed by zero or more PS2 lines.
- (?P<source>
- (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
- (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
- \n? # a newline
- # Want consists of any non-blank lines that do not start with PS1.
- (?P<want> (?:(?![ ]*$) # Not a blank line
- (?![ ]*%s) # Not a line starting with PS1
- (?![ ]*%s) # Not a line starting with PS2
- .*$\n? # But any other line
- )*)
- '''
-
- _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
- re.MULTILINE | re.VERBOSE)
-
- _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
- re.MULTILINE | re.VERBOSE)
-
- # Mark a test as being fully random. In this case, we simply append the
- # random marker ('#random') to each individual example's output. This way
- # we don't need to modify any other code.
- _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
-
- # Mark tests to be executed in an external process - currently unsupported.
- _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
-
- def ip2py(self,source):
- """Convert input IPython source into valid Python."""
- block = _ip.input_transformer_manager.transform_cell(source)
- if len(block.splitlines()) == 1:
- return _ip.prefilter(block)
- else:
- return block
-
- def parse(self, string, name='<string>'):
- """
- Divide the given string into examples and intervening text,
- and return them as a list of alternating Examples and strings.
- Line numbers for the Examples are 0-based. The optional
- argument `name` is a name identifying this string, and is only
- used for error messages.
- """
-
- #print 'Parse string:\n',string # dbg
-
- string = string.expandtabs()
- # If all lines begin with the same indentation, then strip it.
- min_indent = self._min_indent(string)
- if min_indent > 0:
- string = '\n'.join([l[min_indent:] for l in string.split('\n')])
-
- output = []
- charno, lineno = 0, 0
-
- # We make 'all random' tests by adding the '# random' mark to every
- # block of output in the test.
- if self._RANDOM_TEST.search(string):
- random_marker = '\n# random'
- else:
- random_marker = ''
-
- # Whether to convert the input from ipython to python syntax
- ip2py = False
- # Find all doctest examples in the string. First, try them as Python
- # examples, then as IPython ones
- terms = list(self._EXAMPLE_RE_PY.finditer(string))
- if terms:
- # Normal Python example
- #print '-'*70 # dbg
- #print 'PyExample, Source:\n',string # dbg
- #print '-'*70 # dbg
- Example = doctest.Example
- else:
- # It's an ipython example. Note that IPExamples are run
- # in-process, so their syntax must be turned into valid python.
- # IPExternalExamples are run out-of-process (via pexpect) so they
- # don't need any filtering (a real ipython will be executing them).
- terms = list(self._EXAMPLE_RE_IP.finditer(string))
- if self._EXTERNAL_IP.search(string):
- #print '-'*70 # dbg
- #print 'IPExternalExample, Source:\n',string # dbg
- #print '-'*70 # dbg
- Example = IPExternalExample
- else:
- #print '-'*70 # dbg
- #print 'IPExample, Source:\n',string # dbg
- #print '-'*70 # dbg
- Example = IPExample
- ip2py = True
-
- for m in terms:
- # Add the pre-example text to `output`.
- output.append(string[charno:m.start()])
- # Update lineno (lines before this example)
- lineno += string.count('\n', charno, m.start())
- # Extract info from the regexp match.
- (source, options, want, exc_msg) = \
- self._parse_example(m, name, lineno,ip2py)
-
- # Append the random-output marker (it defaults to empty in most
- # cases, it's only non-empty for 'all-random' tests):
- want += random_marker
-
- if Example is IPExternalExample:
- options[doctest.NORMALIZE_WHITESPACE] = True
- want += '\n'
-
- # Create an Example, and add it to the list.
- if not self._IS_BLANK_OR_COMMENT(source):
- output.append(Example(source, want, exc_msg,
- lineno=lineno,
- indent=min_indent+len(m.group('indent')),
- options=options))
- # Update lineno (lines inside this example)
- lineno += string.count('\n', m.start(), m.end())
- # Update charno.
- charno = m.end()
- # Add any remaining post-example text to `output`.
- output.append(string[charno:])
- return output
-
- def _parse_example(self, m, name, lineno,ip2py=False):
- """
- Given a regular expression match from `_EXAMPLE_RE` (`m`),
- return a pair `(source, want)`, where `source` is the matched
- example's source code (with prompts and indentation stripped);
- and `want` is the example's expected output (with indentation
- stripped).
-
- `name` is the string's name, and `lineno` is the line number
- where the example starts; both are used for error messages.
-
- Optional:
- `ip2py`: if true, filter the input via IPython to convert the syntax
- into valid python.
- """
-
- # Get the example's indentation level.
- indent = len(m.group('indent'))
-
- # Divide source into lines; check that they're properly
- # indented; and then strip their indentation & prompts.
- source_lines = m.group('source').split('\n')
-
- # We're using variable-length input prompts
- ps1 = m.group('ps1')
- ps2 = m.group('ps2')
- ps1_len = len(ps1)
-
- self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
- if ps2:
- self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
-
- source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
-
- if ip2py:
- # Convert source input from IPython into valid Python syntax
- source = self.ip2py(source)
-
- # Divide want into lines; check that it's properly indented; and
- # then strip the indentation. Spaces before the last newline should
- # be preserved, so plain rstrip() isn't good enough.
- want = m.group('want')
- want_lines = want.split('\n')
- if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
- del want_lines[-1] # forget final newline & spaces after it
- self._check_prefix(want_lines, ' '*indent, name,
- lineno + len(source_lines))
-
- # Remove ipython output prompt that might be present in the first line
- want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
-
- want = '\n'.join([wl[indent:] for wl in want_lines])
-
- # If `want` contains a traceback message, then extract it.
- m = self._EXCEPTION_RE.match(want)
- if m:
- exc_msg = m.group('msg')
- else:
- exc_msg = None
-
- # Extract options from the source.
- options = self._find_options(source, name, lineno)
-
- return source, options, want, exc_msg
-
- def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
- """
- Given the lines of a source string (including prompts and
- leading indentation), check to make sure that every prompt is
- followed by a space character. If any line is not followed by
- a space character, then raise ValueError.
-
- Note: IPython-modified version which takes the input prompt length as a
- parameter, so that prompts of variable length can be dealt with.
- """
- space_idx = indent+ps1_len
- min_len = space_idx+1
- for i, line in enumerate(lines):
- if len(line) >= min_len and line[space_idx] != ' ':
- raise ValueError('line %r of the docstring for %s '
- 'lacks blank after %s: %r' %
- (lineno+i+1, name,
- line[indent:space_idx], line))
-
-
-SKIP = doctest.register_optionflag('SKIP')
-
-
-class IPDocTestRunner(doctest.DocTestRunner,object):
- """Test runner that synchronizes the IPython namespace with test globals.
- """
-
- def run(self, test, compileflags=None, out=None, clear_globs=True):
-
- # Hack: ipython needs access to the execution context of the example,
- # so that it can propagate user variables loaded by %run into
- # test.globs. We put them here into our modified %run as a function
- # attribute. Our new %run will then only make the namespace update
- # when called (rather than unconconditionally updating test.globs here
- # for all examples, most of which won't be calling %run anyway).
- #_ip._ipdoctest_test_globs = test.globs
- #_ip._ipdoctest_test_filename = test.filename
-
- test.globs.update(_ip.user_ns)
-
+
+ # Look for tests in a module's contained objects.
+ if inspect.ismodule(obj) and self._recurse:
+ for valname, val in obj.__dict__.items():
+ valname1 = '%s.%s' % (name, valname)
+ if ( (isroutine(val) or isclass(val))
+ and self._from_module(module, val) ):
+
+ self._find(tests, val, valname1, module, source_lines,
+ globs, seen)
+
+ # Look for tests in a class's contained objects.
+ if inspect.isclass(obj) and self._recurse:
+ #print 'RECURSE into class:',obj # dbg
+ for valname, val in obj.__dict__.items():
+ # Special handling for staticmethod/classmethod.
+ if isinstance(val, staticmethod):
+ val = getattr(obj, valname)
+ if isinstance(val, classmethod):
+ val = getattr(obj, valname).__func__
+
+ # Recurse to methods, properties, and nested classes.
+ if ((inspect.isfunction(val) or inspect.isclass(val) or
+ inspect.ismethod(val) or
+ isinstance(val, property)) and
+ self._from_module(module, val)):
+ valname = '%s.%s' % (name, valname)
+ self._find(tests, val, valname, module, source_lines,
+ globs, seen)
+
+
+class IPDoctestOutputChecker(doctest.OutputChecker):
+ """Second-chance checker with support for random tests.
+
+ If the default comparison doesn't pass, this checker looks in the expected
+ output string for flags that tell us to ignore the output.
+ """
+
+ random_re = re.compile(r'#\s*random\s+')
+
+ def check_output(self, want, got, optionflags):
+ """Check output, accepting special markers embedded in the output.
+
+ If the output didn't pass the default validation but the special string
+ '#random' is included, we accept it."""
+
+ # Let the original tester verify first, in case people have valid tests
+ # that happen to have a comment saying '#random' embedded in.
+ ret = doctest.OutputChecker.check_output(self, want, got,
+ optionflags)
+ if not ret and self.random_re.search(want):
+ #print >> sys.stderr, 'RANDOM OK:',want # dbg
+ return True
+
+ return ret
+
+
+class DocTestCase(doctests.DocTestCase):
+ """Proxy for DocTestCase: provides an address() method that
+ returns the correct address for the doctest case. Otherwise
+ acts as a proxy to the test case. To provide hints for address(),
+ an obj may also be passed -- this will be used as the test object
+ for purposes of determining the test address, if it is provided.
+ """
+
+ # Note: this method was taken from numpy's nosetester module.
+
+ # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
+ # its constructor that blocks non-default arguments from being passed
+ # down into doctest.DocTestCase
+
+ def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
+ checker=None, obj=None, result_var='_'):
+ self._result_var = result_var
+ doctests.DocTestCase.__init__(self, test,
+ optionflags=optionflags,
+ setUp=setUp, tearDown=tearDown,
+ checker=checker)
+ # Now we must actually copy the original constructor from the stdlib
+ # doctest class, because we can't call it directly and a bug in nose
+ # means it never gets passed the right arguments.
+
+ self._dt_optionflags = optionflags
+ self._dt_checker = checker
+ self._dt_test = test
+ self._dt_test_globs_ori = test.globs
+ self._dt_setUp = setUp
+ self._dt_tearDown = tearDown
+
+ # XXX - store this runner once in the object!
+ runner = IPDocTestRunner(optionflags=optionflags,
+ checker=checker, verbose=False)
+ self._dt_runner = runner
+
+
+ # Each doctest should remember the directory it was loaded from, so
+ # things like %run work without too many contortions
+ self._ori_dir = os.path.dirname(test.filename)
+
+ # Modified runTest from the default stdlib
+ def runTest(self):
+ test = self._dt_test
+ runner = self._dt_runner
+
+ old = sys.stdout
+ new = StringIO()
+ optionflags = self._dt_optionflags
+
+ if not (optionflags & REPORTING_FLAGS):
+ # The option flags don't include any reporting flags,
+ # so add the default reporting flags
+ optionflags |= _unittest_reportflags
+
+ try:
+ # Save our current directory and switch out to the one where the
+ # test was originally created, in case another doctest did a
+ # directory change. We'll restore this in the finally clause.
+ curdir = getcwd()
+ #print 'runTest in dir:', self._ori_dir # dbg
+ os.chdir(self._ori_dir)
+
+ runner.DIVIDER = "-"*70
+ failures, tries = runner.run(test,out=new.write,
+ clear_globs=False)
+ finally:
+ sys.stdout = old
+ os.chdir(curdir)
+
+ if failures:
+ raise self.failureException(self.format_failure(new.getvalue()))
+
+ def setUp(self):
+ """Modified test setup that syncs with ipython namespace"""
+ #print "setUp test", self._dt_test.examples # dbg
+ if isinstance(self._dt_test.examples[0], IPExample):
+ # for IPython examples *only*, we swap the globals with the ipython
+ # namespace, after updating it with the globals (which doctest
+ # fills with the necessary info from the module being tested).
+ self.user_ns_orig = {}
+ self.user_ns_orig.update(_ip.user_ns)
+ _ip.user_ns.update(self._dt_test.globs)
+ # We must remove the _ key in the namespace, so that Python's
+ # doctest code sets it naturally
+ _ip.user_ns.pop('_', None)
+ _ip.user_ns['__builtins__'] = builtin_mod
+ self._dt_test.globs = _ip.user_ns
+
+ super(DocTestCase, self).setUp()
+
+ def tearDown(self):
+
+ # Undo the test.globs reassignment we made, so that the parent class
+ # teardown doesn't destroy the ipython namespace
+ if isinstance(self._dt_test.examples[0], IPExample):
+ self._dt_test.globs = self._dt_test_globs_ori
+ _ip.user_ns.clear()
+ _ip.user_ns.update(self.user_ns_orig)
+
+ # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
+ # it does look like one to me: its tearDown method tries to run
+ #
+ # delattr(builtin_mod, self._result_var)
+ #
+ # without checking that the attribute really is there; it implicitly
+ # assumes it should have been set via displayhook. But if the
+ # displayhook was never called, this doesn't necessarily happen. I
+ # haven't been able to find a little self-contained example outside of
+ # ipython that would show the problem so I can report it to the nose
+ # team, but it does happen a lot in our code.
+ #
+ # So here, we just protect as narrowly as possible by trapping an
+ # attribute error whose message would be the name of self._result_var,
+ # and letting any other error propagate.
+ try:
+ super(DocTestCase, self).tearDown()
+ except AttributeError as exc:
+ if exc.args[0] != self._result_var:
+ raise
+
+
+# A simple subclassing of the original with a different class name, so we can
+# distinguish and treat differently IPython examples from pure python ones.
+class IPExample(doctest.Example): pass
+
+
+class IPExternalExample(doctest.Example):
+ """Doctest examples to be run in an external process."""
+
+ def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
+ options=None):
+ # Parent constructor
+ doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
+
+ # An EXTRA newline is needed to prevent pexpect hangs
+ self.source += '\n'
+
+
+class IPDocTestParser(doctest.DocTestParser):
+ """
+ A class used to parse strings containing doctest examples.
+
+ Note: This is a version modified to properly recognize IPython input and
+ convert any IPython examples into valid Python ones.
+ """
+ # This regular expression is used to find doctest examples in a
+ # string. It defines three groups: `source` is the source code
+ # (including leading indentation and prompts); `indent` is the
+ # indentation of the first (PS1) line of the source code; and
+ # `want` is the expected output (including leading indentation).
+
+ # Classic Python prompts or default IPython ones
+ _PS1_PY = r'>>>'
+ _PS2_PY = r'\.\.\.'
+
+ _PS1_IP = r'In\ \[\d+\]:'
+ _PS2_IP = r'\ \ \ \.\.\.+:'
+
+ _RE_TPL = r'''
+ # Source consists of a PS1 line followed by zero or more PS2 lines.
+ (?P<source>
+ (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
+ (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
+ \n? # a newline
+ # Want consists of any non-blank lines that do not start with PS1.
+ (?P<want> (?:(?![ ]*$) # Not a blank line
+ (?![ ]*%s) # Not a line starting with PS1
+ (?![ ]*%s) # Not a line starting with PS2
+ .*$\n? # But any other line
+ )*)
+ '''
+
+ _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
+ re.MULTILINE | re.VERBOSE)
+
+ _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
+ re.MULTILINE | re.VERBOSE)
+
+ # Mark a test as being fully random. In this case, we simply append the
+ # random marker ('#random') to each individual example's output. This way
+ # we don't need to modify any other code.
+ _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
+
+ # Mark tests to be executed in an external process - currently unsupported.
+ _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
+
+ def ip2py(self,source):
+ """Convert input IPython source into valid Python."""
+ block = _ip.input_transformer_manager.transform_cell(source)
+ if len(block.splitlines()) == 1:
+ return _ip.prefilter(block)
+ else:
+ return block
+
+ def parse(self, string, name='<string>'):
+ """
+ Divide the given string into examples and intervening text,
+ and return them as a list of alternating Examples and strings.
+ Line numbers for the Examples are 0-based. The optional
+ argument `name` is a name identifying this string, and is only
+ used for error messages.
+ """
+
+ #print 'Parse string:\n',string # dbg
+
+ string = string.expandtabs()
+ # If all lines begin with the same indentation, then strip it.
+ min_indent = self._min_indent(string)
+ if min_indent > 0:
+ string = '\n'.join([l[min_indent:] for l in string.split('\n')])
+
+ output = []
+ charno, lineno = 0, 0
+
+ # We make 'all random' tests by adding the '# random' mark to every
+ # block of output in the test.
+ if self._RANDOM_TEST.search(string):
+ random_marker = '\n# random'
+ else:
+ random_marker = ''
+
+ # Whether to convert the input from ipython to python syntax
+ ip2py = False
+ # Find all doctest examples in the string. First, try them as Python
+ # examples, then as IPython ones
+ terms = list(self._EXAMPLE_RE_PY.finditer(string))
+ if terms:
+ # Normal Python example
+ #print '-'*70 # dbg
+ #print 'PyExample, Source:\n',string # dbg
+ #print '-'*70 # dbg
+ Example = doctest.Example
+ else:
+ # It's an ipython example. Note that IPExamples are run
+ # in-process, so their syntax must be turned into valid python.
+ # IPExternalExamples are run out-of-process (via pexpect) so they
+ # don't need any filtering (a real ipython will be executing them).
+ terms = list(self._EXAMPLE_RE_IP.finditer(string))
+ if self._EXTERNAL_IP.search(string):
+ #print '-'*70 # dbg
+ #print 'IPExternalExample, Source:\n',string # dbg
+ #print '-'*70 # dbg
+ Example = IPExternalExample
+ else:
+ #print '-'*70 # dbg
+ #print 'IPExample, Source:\n',string # dbg
+ #print '-'*70 # dbg
+ Example = IPExample
+ ip2py = True
+
+ for m in terms:
+ # Add the pre-example text to `output`.
+ output.append(string[charno:m.start()])
+ # Update lineno (lines before this example)
+ lineno += string.count('\n', charno, m.start())
+ # Extract info from the regexp match.
+ (source, options, want, exc_msg) = \
+ self._parse_example(m, name, lineno,ip2py)
+
+ # Append the random-output marker (it defaults to empty in most
+ # cases, it's only non-empty for 'all-random' tests):
+ want += random_marker
+
+ if Example is IPExternalExample:
+ options[doctest.NORMALIZE_WHITESPACE] = True
+ want += '\n'
+
+ # Create an Example, and add it to the list.
+ if not self._IS_BLANK_OR_COMMENT(source):
+ output.append(Example(source, want, exc_msg,
+ lineno=lineno,
+ indent=min_indent+len(m.group('indent')),
+ options=options))
+ # Update lineno (lines inside this example)
+ lineno += string.count('\n', m.start(), m.end())
+ # Update charno.
+ charno = m.end()
+ # Add any remaining post-example text to `output`.
+ output.append(string[charno:])
+ return output
+
+ def _parse_example(self, m, name, lineno,ip2py=False):
+ """
+ Given a regular expression match from `_EXAMPLE_RE` (`m`),
+ return a pair `(source, want)`, where `source` is the matched
+ example's source code (with prompts and indentation stripped);
+ and `want` is the example's expected output (with indentation
+ stripped).
+
+ `name` is the string's name, and `lineno` is the line number
+ where the example starts; both are used for error messages.
+
+ Optional:
+ `ip2py`: if true, filter the input via IPython to convert the syntax
+ into valid python.
+ """
+
+ # Get the example's indentation level.
+ indent = len(m.group('indent'))
+
+ # Divide source into lines; check that they're properly
+ # indented; and then strip their indentation & prompts.
+ source_lines = m.group('source').split('\n')
+
+ # We're using variable-length input prompts
+ ps1 = m.group('ps1')
+ ps2 = m.group('ps2')
+ ps1_len = len(ps1)
+
+ self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
+ if ps2:
+ self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
+
+ source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
+
+ if ip2py:
+ # Convert source input from IPython into valid Python syntax
+ source = self.ip2py(source)
+
+ # Divide want into lines; check that it's properly indented; and
+ # then strip the indentation. Spaces before the last newline should
+ # be preserved, so plain rstrip() isn't good enough.
+ want = m.group('want')
+ want_lines = want.split('\n')
+ if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
+ del want_lines[-1] # forget final newline & spaces after it
+ self._check_prefix(want_lines, ' '*indent, name,
+ lineno + len(source_lines))
+
+ # Remove ipython output prompt that might be present in the first line
+ want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
+
+ want = '\n'.join([wl[indent:] for wl in want_lines])
+
+ # If `want` contains a traceback message, then extract it.
+ m = self._EXCEPTION_RE.match(want)
+ if m:
+ exc_msg = m.group('msg')
+ else:
+ exc_msg = None
+
+ # Extract options from the source.
+ options = self._find_options(source, name, lineno)
+
+ return source, options, want, exc_msg
+
+ def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
+ """
+ Given the lines of a source string (including prompts and
+ leading indentation), check to make sure that every prompt is
+ followed by a space character. If any line is not followed by
+ a space character, then raise ValueError.
+
+ Note: IPython-modified version which takes the input prompt length as a
+ parameter, so that prompts of variable length can be dealt with.
+ """
+ space_idx = indent+ps1_len
+ min_len = space_idx+1
+ for i, line in enumerate(lines):
+ if len(line) >= min_len and line[space_idx] != ' ':
+ raise ValueError('line %r of the docstring for %s '
+ 'lacks blank after %s: %r' %
+ (lineno+i+1, name,
+ line[indent:space_idx], line))
+
+
+SKIP = doctest.register_optionflag('SKIP')
+
+
+class IPDocTestRunner(doctest.DocTestRunner,object):
+ """Test runner that synchronizes the IPython namespace with test globals.
+ """
+
+ def run(self, test, compileflags=None, out=None, clear_globs=True):
+
+ # Hack: ipython needs access to the execution context of the example,
+ # so that it can propagate user variables loaded by %run into
+ # test.globs. We put them here into our modified %run as a function
+ # attribute. Our new %run will then only make the namespace update
+ # when called (rather than unconconditionally updating test.globs here
+ # for all examples, most of which won't be calling %run anyway).
+ #_ip._ipdoctest_test_globs = test.globs
+ #_ip._ipdoctest_test_filename = test.filename
+
+ test.globs.update(_ip.user_ns)
+
# Override terminal size to standardise traceback format
with modified_env({'COLUMNS': '80', 'LINES': '24'}):
return super(IPDocTestRunner,self).run(test,
compileflags,out,clear_globs)
-
-
-class DocFileCase(doctest.DocFileCase):
- """Overrides to provide filename
- """
- def address(self):
- return (self._dt_test.filename, None, None)
-
-
-class ExtensionDoctest(doctests.Doctest):
- """Nose Plugin that supports doctests in extension modules.
- """
- name = 'extdoctest' # call nosetests with --with-extdoctest
- enabled = True
-
- 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)
- # Pull standard doctest plugin out of config; we will do doctesting
- config.plugins.plugins = [p for p in config.plugins.plugins
- if p.name != 'doctest']
- self.doctest_tests = options.doctest_tests
- self.extension = tolist(options.doctestExtension)
-
- self.parser = doctest.DocTestParser()
- self.finder = DocTestFinder()
- self.checker = IPDoctestOutputChecker()
- self.globs = None
- self.extraglobs = None
-
-
- def loadTestsFromExtensionModule(self,filename):
- bpath,mod = os.path.split(filename)
- modname = os.path.splitext(mod)[0]
- try:
- sys.path.append(bpath)
- module = __import__(modname)
- tests = list(self.loadTestsFromModule(module))
- finally:
- sys.path.pop()
- return tests
-
- # NOTE: the method below is almost a copy of the original one in nose, with
- # a few modifications to control output checking.
-
- def loadTestsFromModule(self, module):
- #print '*** ipdoctest - lTM',module # dbg
-
- if not self.matches(module.__name__):
- log.debug("Doctest doesn't want module %s", module)
- return
-
- tests = self.finder.find(module,globs=self.globs,
- extraglobs=self.extraglobs)
- if not tests:
- return
-
- # always use whitespace and ellipsis options
- optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
-
- tests.sort()
- module_file = module.__file__
- if module_file[-4:] in ('.pyc', '.pyo'):
- module_file = module_file[:-1]
- for test in tests:
- if not test.examples:
- continue
- if not test.filename:
- test.filename = module_file
-
- yield DocTestCase(test,
- optionflags=optionflags,
- checker=self.checker)
-
-
- def loadTestsFromFile(self, filename):
- #print "ipdoctest - from file", filename # dbg
- if is_extension_module(filename):
- for t in self.loadTestsFromExtensionModule(filename):
- yield t
- else:
- if self.extension and anyp(filename.endswith, self.extension):
- name = os.path.basename(filename)
- dh = open(filename)
- try:
- doc = dh.read()
- finally:
- dh.close()
- test = self.parser.get_doctest(
- doc, globs={'__file__': filename}, name=name,
- filename=filename, lineno=0)
- if test.examples:
- #print 'FileCase:',test.examples # dbg
- yield DocFileCase(test)
- else:
- yield False # no tests to load
-
-
-class IPythonDoctest(ExtensionDoctest):
- """Nose Plugin that supports doctests in extension modules.
- """
- name = 'ipdoctest' # call nosetests with --with-ipdoctest
- enabled = True
-
- def makeTest(self, obj, parent):
- """Look for doctests in the given object, which will be a
- function, method or class.
- """
- #print 'Plugin analyzing:', obj, parent # dbg
- # always use whitespace and ellipsis options
- optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
-
- doctests = self.finder.find(obj, module=getmodule(parent))
- if doctests:
- for test in doctests:
- if len(test.examples) == 0:
- continue
-
- yield DocTestCase(test, obj=obj,
- optionflags=optionflags,
- checker=self.checker)
-
- def options(self, parser, env=os.environ):
- #print "Options for nose plugin:", self.name # dbg
- Plugin.options(self, parser, env)
- parser.add_option('--ipdoctest-tests', action='store_true',
- dest='ipdoctest_tests',
- default=env.get('NOSE_IPDOCTEST_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_IPDOCTEST_TESTS]")
- parser.add_option('--ipdoctest-extension', action="append",
- dest="ipdoctest_extension",
- help="Also look for doctests in files with "
- "this extension [NOSE_IPDOCTEST_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_IPDOCTEST_EXTENSION')
- if env_setting is not None:
- parser.set_defaults(ipdoctest_extension=tolist(env_setting))
-
- def configure(self, options, config):
- #print "Configuring nose plugin:", self.name # dbg
- Plugin.configure(self, options, config)
- # Pull standard doctest plugin out of config; we will do doctesting
- config.plugins.plugins = [p for p in config.plugins.plugins
- if p.name != 'doctest']
- self.doctest_tests = options.ipdoctest_tests
- self.extension = tolist(options.ipdoctest_extension)
-
- self.parser = IPDocTestParser()
- self.finder = DocTestFinder(parser=self.parser)
- self.checker = IPDoctestOutputChecker()
- self.globs = None
- self.extraglobs = None
+
+
+class DocFileCase(doctest.DocFileCase):
+ """Overrides to provide filename
+ """
+ def address(self):
+ return (self._dt_test.filename, None, None)
+
+
+class ExtensionDoctest(doctests.Doctest):
+ """Nose Plugin that supports doctests in extension modules.
+ """
+ name = 'extdoctest' # call nosetests with --with-extdoctest
+ enabled = True
+
+ 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)
+ # Pull standard doctest plugin out of config; we will do doctesting
+ config.plugins.plugins = [p for p in config.plugins.plugins
+ if p.name != 'doctest']
+ self.doctest_tests = options.doctest_tests
+ self.extension = tolist(options.doctestExtension)
+
+ self.parser = doctest.DocTestParser()
+ self.finder = DocTestFinder()
+ self.checker = IPDoctestOutputChecker()
+ self.globs = None
+ self.extraglobs = None
+
+
+ def loadTestsFromExtensionModule(self,filename):
+ bpath,mod = os.path.split(filename)
+ modname = os.path.splitext(mod)[0]
+ try:
+ sys.path.append(bpath)
+ module = __import__(modname)
+ tests = list(self.loadTestsFromModule(module))
+ finally:
+ sys.path.pop()
+ return tests
+
+ # NOTE: the method below is almost a copy of the original one in nose, with
+ # a few modifications to control output checking.
+
+ def loadTestsFromModule(self, module):
+ #print '*** ipdoctest - lTM',module # dbg
+
+ if not self.matches(module.__name__):
+ log.debug("Doctest doesn't want module %s", module)
+ return
+
+ tests = self.finder.find(module,globs=self.globs,
+ extraglobs=self.extraglobs)
+ if not tests:
+ return
+
+ # always use whitespace and ellipsis options
+ optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
+
+ tests.sort()
+ module_file = module.__file__
+ if module_file[-4:] in ('.pyc', '.pyo'):
+ module_file = module_file[:-1]
+ for test in tests:
+ if not test.examples:
+ continue
+ if not test.filename:
+ test.filename = module_file
+
+ yield DocTestCase(test,
+ optionflags=optionflags,
+ checker=self.checker)
+
+
+ def loadTestsFromFile(self, filename):
+ #print "ipdoctest - from file", filename # dbg
+ if is_extension_module(filename):
+ for t in self.loadTestsFromExtensionModule(filename):
+ yield t
+ else:
+ if self.extension and anyp(filename.endswith, self.extension):
+ name = os.path.basename(filename)
+ dh = open(filename)
+ try:
+ doc = dh.read()
+ finally:
+ dh.close()
+ test = self.parser.get_doctest(
+ doc, globs={'__file__': filename}, name=name,
+ filename=filename, lineno=0)
+ if test.examples:
+ #print 'FileCase:',test.examples # dbg
+ yield DocFileCase(test)
+ else:
+ yield False # no tests to load
+
+
+class IPythonDoctest(ExtensionDoctest):
+ """Nose Plugin that supports doctests in extension modules.
+ """
+ name = 'ipdoctest' # call nosetests with --with-ipdoctest
+ enabled = True
+
+ def makeTest(self, obj, parent):
+ """Look for doctests in the given object, which will be a
+ function, method or class.
+ """
+ #print 'Plugin analyzing:', obj, parent # dbg
+ # always use whitespace and ellipsis options
+ optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
+
+ doctests = self.finder.find(obj, module=getmodule(parent))
+ if doctests:
+ for test in doctests:
+ if len(test.examples) == 0:
+ continue
+
+ yield DocTestCase(test, obj=obj,
+ optionflags=optionflags,
+ checker=self.checker)
+
+ def options(self, parser, env=os.environ):
+ #print "Options for nose plugin:", self.name # dbg
+ Plugin.options(self, parser, env)
+ parser.add_option('--ipdoctest-tests', action='store_true',
+ dest='ipdoctest_tests',
+ default=env.get('NOSE_IPDOCTEST_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_IPDOCTEST_TESTS]")
+ parser.add_option('--ipdoctest-extension', action="append",
+ dest="ipdoctest_extension",
+ help="Also look for doctests in files with "
+ "this extension [NOSE_IPDOCTEST_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_IPDOCTEST_EXTENSION')
+ if env_setting is not None:
+ parser.set_defaults(ipdoctest_extension=tolist(env_setting))
+
+ def configure(self, options, config):
+ #print "Configuring nose plugin:", self.name # dbg
+ Plugin.configure(self, options, config)
+ # Pull standard doctest plugin out of config; we will do doctesting
+ config.plugins.plugins = [p for p in config.plugins.plugins
+ if p.name != 'doctest']
+ self.doctest_tests = options.ipdoctest_tests
+ self.extension = tolist(options.ipdoctest_extension)
+
+ self.parser = IPDocTestParser()
+ self.finder = DocTestFinder(parser=self.parser)
+ self.checker = IPDoctestOutputChecker()
+ self.globs = None
+ self.extraglobs = None
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/iptest.py b/contrib/python/ipython/py2/IPython/testing/plugin/iptest.py
index a75cab993f..25b4634f2f 100755
--- a/contrib/python/ipython/py2/IPython/testing/plugin/iptest.py
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/iptest.py
@@ -1,19 +1,19 @@
-#!/usr/bin/env python
-"""Nose-based test runner.
-"""
-from __future__ import print_function
-
-from nose.core import main
-from nose.plugins.builtin import plugins
-from nose.plugins.doctests import Doctest
-
-from . import ipdoctest
-from .ipdoctest import IPDocTestRunner
-
-if __name__ == '__main__':
- print('WARNING: this code is incomplete!')
- print()
-
- pp = [x() for x in plugins] # activate all builtin plugins first
- main(testRunner=IPDocTestRunner(),
- plugins=pp+[ipdoctest.IPythonDoctest(),Doctest()])
+#!/usr/bin/env python
+"""Nose-based test runner.
+"""
+from __future__ import print_function
+
+from nose.core import main
+from nose.plugins.builtin import plugins
+from nose.plugins.doctests import Doctest
+
+from . import ipdoctest
+from .ipdoctest import IPDocTestRunner
+
+if __name__ == '__main__':
+ print('WARNING: this code is incomplete!')
+ print()
+
+ pp = [x() for x in plugins] # activate all builtin plugins first
+ main(testRunner=IPDocTestRunner(),
+ plugins=pp+[ipdoctest.IPythonDoctest(),Doctest()])
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/setup.py b/contrib/python/ipython/py2/IPython/testing/plugin/setup.py
index a3281d30c8..785704337b 100755
--- a/contrib/python/ipython/py2/IPython/testing/plugin/setup.py
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/setup.py
@@ -1,18 +1,18 @@
-#!/usr/bin/env python
-"""A Nose plugin to support IPython doctests.
-"""
-
-from setuptools import setup
-
-setup(name='IPython doctest plugin',
- version='0.1',
- author='The IPython Team',
- description = 'Nose plugin to load IPython-extended doctests',
- license = 'LGPL',
- py_modules = ['ipdoctest'],
- entry_points = {
- 'nose.plugins.0.10': ['ipdoctest = ipdoctest:IPythonDoctest',
- 'extdoctest = ipdoctest:ExtensionDoctest',
- ],
- },
- )
+#!/usr/bin/env python
+"""A Nose plugin to support IPython doctests.
+"""
+
+from setuptools import setup
+
+setup(name='IPython doctest plugin',
+ version='0.1',
+ author='The IPython Team',
+ description = 'Nose plugin to load IPython-extended doctests',
+ license = 'LGPL',
+ py_modules = ['ipdoctest'],
+ entry_points = {
+ 'nose.plugins.0.10': ['ipdoctest = ipdoctest:IPythonDoctest',
+ 'extdoctest = ipdoctest:ExtensionDoctest',
+ ],
+ },
+ )
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/show_refs.py b/contrib/python/ipython/py2/IPython/testing/plugin/show_refs.py
index ef7dd157ae..4c517da949 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/show_refs.py
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/show_refs.py
@@ -1,20 +1,20 @@
-"""Simple script to show reference holding behavior.
-
-This is used by a companion test case.
-"""
-from __future__ import print_function
-
-import gc
-
-class C(object):
- def __del__(self):
- pass
- #print 'deleting object...' # dbg
-
-if __name__ == '__main__':
- c = C()
-
- c_refs = gc.get_referrers(c)
- ref_ids = list(map(id,c_refs))
-
- print('c referrers:',list(map(type,c_refs)))
+"""Simple script to show reference holding behavior.
+
+This is used by a companion test case.
+"""
+from __future__ import print_function
+
+import gc
+
+class C(object):
+ def __del__(self):
+ pass
+ #print 'deleting object...' # dbg
+
+if __name__ == '__main__':
+ c = C()
+
+ c_refs = gc.get_referrers(c)
+ ref_ids = list(map(id,c_refs))
+
+ print('c referrers:',list(map(type,c_refs)))
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/simple.py b/contrib/python/ipython/py2/IPython/testing/plugin/simple.py
index a7d33d9a16..bcc43f55e8 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/simple.py
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/simple.py
@@ -1,34 +1,34 @@
-"""Simple example using doctests.
-
-This file just contains doctests both using plain python and IPython prompts.
-All tests should be loaded by nose.
-"""
-from __future__ import print_function
-
-def pyfunc():
- """Some pure python tests...
-
- >>> pyfunc()
- 'pyfunc'
-
- >>> import os
-
- >>> 2+3
- 5
-
- >>> for i in range(3):
- ... print(i, end=' ')
- ... print(i+1, end=' ')
- ...
- 0 1 1 2 2 3
- """
- return 'pyfunc'
-
-
-def ipyfunc2():
- """Some pure python tests...
-
- >>> 1+1
- 2
- """
- return 'pyfunc2'
+"""Simple example using doctests.
+
+This file just contains doctests both using plain python and IPython prompts.
+All tests should be loaded by nose.
+"""
+from __future__ import print_function
+
+def pyfunc():
+ """Some pure python tests...
+
+ >>> pyfunc()
+ 'pyfunc'
+
+ >>> import os
+
+ >>> 2+3
+ 5
+
+ >>> for i in range(3):
+ ... print(i, end=' ')
+ ... print(i+1, end=' ')
+ ...
+ 0 1 1 2 2 3
+ """
+ return 'pyfunc'
+
+
+def ipyfunc2():
+ """Some pure python tests...
+
+ >>> 1+1
+ 2
+ """
+ return 'pyfunc2'
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/simplevars.py b/contrib/python/ipython/py2/IPython/testing/plugin/simplevars.py
index 5134c6e928..ee4039a59a 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/simplevars.py
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/simplevars.py
@@ -1,3 +1,3 @@
-from __future__ import print_function
-x = 1
-print('x is:',x)
+from __future__ import print_function
+x = 1
+print('x is:',x)
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/test_combo.txt b/contrib/python/ipython/py2/IPython/testing/plugin/test_combo.txt
index 6c8759f3e7..0de694fe7e 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/test_combo.txt
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/test_combo.txt
@@ -1,36 +1,36 @@
-=======================
- Combo testing example
-=======================
-
-This is a simple example that mixes ipython doctests::
-
- In [1]: import code
-
- In [2]: 2**12
- Out[2]: 4096
-
-with command-line example information that does *not* get executed::
-
- $ mpirun -n 4 ipengine --controller-port=10000 --controller-ip=host0
-
-and with literal examples of Python source code::
-
- controller = dict(host='myhost',
- engine_port=None, # default is 10105
- control_port=None,
- )
-
- # keys are hostnames, values are the number of engine on that host
- engines = dict(node1=2,
- node2=2,
- node3=2,
- node3=2,
- )
-
- # Force failure to detect that this test is being run.
- 1/0
-
-These source code examples are executed but no output is compared at all. An
-error or failure is reported only if an exception is raised.
-
-NOTE: the execution of pure python blocks is not yet working!
+=======================
+ Combo testing example
+=======================
+
+This is a simple example that mixes ipython doctests::
+
+ In [1]: import code
+
+ In [2]: 2**12
+ Out[2]: 4096
+
+with command-line example information that does *not* get executed::
+
+ $ mpirun -n 4 ipengine --controller-port=10000 --controller-ip=host0
+
+and with literal examples of Python source code::
+
+ controller = dict(host='myhost',
+ engine_port=None, # default is 10105
+ control_port=None,
+ )
+
+ # keys are hostnames, values are the number of engine on that host
+ engines = dict(node1=2,
+ node2=2,
+ node3=2,
+ node3=2,
+ )
+
+ # Force failure to detect that this test is being run.
+ 1/0
+
+These source code examples are executed but no output is compared at all. An
+error or failure is reported only if an exception is raised.
+
+NOTE: the execution of pure python blocks is not yet working!
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/test_example.txt b/contrib/python/ipython/py2/IPython/testing/plugin/test_example.txt
index f8b681eb4f..f6258b0615 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/test_example.txt
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/test_example.txt
@@ -1,24 +1,24 @@
-=====================================
- Tests in example form - pure python
-=====================================
-
-This file contains doctest examples embedded as code blocks, using normal
-Python prompts. See the accompanying file for similar examples using IPython
-prompts (you can't mix both types within one file). The following will be run
-as a test::
-
- >>> 1+1
- 2
- >>> print ("hello")
- hello
-
-More than one example works::
-
- >>> s="Hello World"
-
- >>> s.upper()
- 'HELLO WORLD'
-
-but you should note that the *entire* test file is considered to be a single
-test. Individual code blocks that fail are printed separately as ``example
-failures``, but the whole file is still counted and reported as one test.
+=====================================
+ Tests in example form - pure python
+=====================================
+
+This file contains doctest examples embedded as code blocks, using normal
+Python prompts. See the accompanying file for similar examples using IPython
+prompts (you can't mix both types within one file). The following will be run
+as a test::
+
+ >>> 1+1
+ 2
+ >>> print ("hello")
+ hello
+
+More than one example works::
+
+ >>> s="Hello World"
+
+ >>> s.upper()
+ 'HELLO WORLD'
+
+but you should note that the *entire* test file is considered to be a single
+test. Individual code blocks that fail are printed separately as ``example
+failures``, but the whole file is still counted and reported as one test.
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/test_exampleip.txt b/contrib/python/ipython/py2/IPython/testing/plugin/test_exampleip.txt
index 8afcbfdf7d..cbc00cc976 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/test_exampleip.txt
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/test_exampleip.txt
@@ -1,30 +1,30 @@
-=================================
- Tests in example form - IPython
-=================================
-
-You can write text files with examples that use IPython prompts (as long as you
-use the nose ipython doctest plugin), but you can not mix and match prompt
-styles in a single file. That is, you either use all ``>>>`` prompts or all
-IPython-style prompts. Your test suite *can* have both types, you just need to
-put each type of example in a separate. Using IPython prompts, you can paste
-directly from your session::
-
- In [5]: s="Hello World"
-
- In [6]: s.upper()
- Out[6]: 'HELLO WORLD'
-
-Another example::
-
- In [8]: 1+3
- Out[8]: 4
-
-Just like in IPython docstrings, you can use all IPython syntax and features::
-
- In [9]: !echo "hello"
- hello
-
- In [10]: a='hi'
-
- In [11]: !echo $a
- hi
+=================================
+ Tests in example form - IPython
+=================================
+
+You can write text files with examples that use IPython prompts (as long as you
+use the nose ipython doctest plugin), but you can not mix and match prompt
+styles in a single file. That is, you either use all ``>>>`` prompts or all
+IPython-style prompts. Your test suite *can* have both types, you just need to
+put each type of example in a separate. Using IPython prompts, you can paste
+directly from your session::
+
+ In [5]: s="Hello World"
+
+ In [6]: s.upper()
+ Out[6]: 'HELLO WORLD'
+
+Another example::
+
+ In [8]: 1+3
+ Out[8]: 4
+
+Just like in IPython docstrings, you can use all IPython syntax and features::
+
+ In [9]: !echo "hello"
+ hello
+
+ In [10]: a='hi'
+
+ In [11]: !echo $a
+ hi
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/test_ipdoctest.py b/contrib/python/ipython/py2/IPython/testing/plugin/test_ipdoctest.py
index a7add7da79..05dc387d9b 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/test_ipdoctest.py
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/test_ipdoctest.py
@@ -1,80 +1,80 @@
-"""Tests for the ipdoctest machinery itself.
-
-Note: in a file named test_X, functions whose only test is their docstring (as
-a doctest) and which have no test functionality of their own, should be called
-'doctest_foo' instead of 'test_foo', otherwise they get double-counted (the
-empty function call is counted as a test, which just inflates tests numbers
-artificially).
-"""
-from IPython.utils.py3compat import doctest_refactor_print
-
-@doctest_refactor_print
-def doctest_simple():
- """ipdoctest must handle simple inputs
-
- In [1]: 1
- Out[1]: 1
-
- In [2]: print 1
- 1
- """
-
-@doctest_refactor_print
-def doctest_multiline1():
- """The ipdoctest machinery must handle multiline examples gracefully.
-
- In [2]: for i in range(4):
- ...: print i
- ...:
- 0
- 1
- 2
- 3
- """
-
-@doctest_refactor_print
-def doctest_multiline2():
- """Multiline examples that define functions and print output.
-
- In [7]: def f(x):
- ...: return x+1
- ...:
-
- In [8]: f(1)
- Out[8]: 2
-
- In [9]: def g(x):
- ...: print 'x is:',x
- ...:
-
- In [10]: g(1)
- x is: 1
-
- In [11]: g('hello')
- x is: hello
- """
-
-
-def doctest_multiline3():
- """Multiline examples with blank lines.
-
- In [12]: def h(x):
- ....: if x>1:
- ....: return x**2
- ....: # To leave a blank line in the input, you must mark it
- ....: # with a comment character:
- ....: #
- ....: # otherwise the doctest parser gets confused.
- ....: else:
- ....: return -1
- ....:
-
- In [13]: h(5)
- Out[13]: 25
-
- In [14]: h(1)
- Out[14]: -1
-
- In [15]: h(0)
- Out[15]: -1
- """
+"""Tests for the ipdoctest machinery itself.
+
+Note: in a file named test_X, functions whose only test is their docstring (as
+a doctest) and which have no test functionality of their own, should be called
+'doctest_foo' instead of 'test_foo', otherwise they get double-counted (the
+empty function call is counted as a test, which just inflates tests numbers
+artificially).
+"""
+from IPython.utils.py3compat import doctest_refactor_print
+
+@doctest_refactor_print
+def doctest_simple():
+ """ipdoctest must handle simple inputs
+
+ In [1]: 1
+ Out[1]: 1
+
+ In [2]: print 1
+ 1
+ """
+
+@doctest_refactor_print
+def doctest_multiline1():
+ """The ipdoctest machinery must handle multiline examples gracefully.
+
+ In [2]: for i in range(4):
+ ...: print i
+ ...:
+ 0
+ 1
+ 2
+ 3
+ """
+
+@doctest_refactor_print
+def doctest_multiline2():
+ """Multiline examples that define functions and print output.
+
+ In [7]: def f(x):
+ ...: return x+1
+ ...:
+
+ In [8]: f(1)
+ Out[8]: 2
+
+ In [9]: def g(x):
+ ...: print 'x is:',x
+ ...:
+
+ In [10]: g(1)
+ x is: 1
+
+ In [11]: g('hello')
+ x is: hello
+ """
+
+
+def doctest_multiline3():
+ """Multiline examples with blank lines.
+
+ In [12]: def h(x):
+ ....: if x>1:
+ ....: return x**2
+ ....: # To leave a blank line in the input, you must mark it
+ ....: # with a comment character:
+ ....: #
+ ....: # otherwise the doctest parser gets confused.
+ ....: else:
+ ....: return -1
+ ....:
+
+ In [13]: h(5)
+ Out[13]: 25
+
+ In [14]: h(1)
+ Out[14]: -1
+
+ In [15]: h(0)
+ Out[15]: -1
+ """
diff --git a/contrib/python/ipython/py2/IPython/testing/plugin/test_refs.py b/contrib/python/ipython/py2/IPython/testing/plugin/test_refs.py
index 50d0857134..8a2a78b75d 100644
--- a/contrib/python/ipython/py2/IPython/testing/plugin/test_refs.py
+++ b/contrib/python/ipython/py2/IPython/testing/plugin/test_refs.py
@@ -1,46 +1,46 @@
-"""Some simple tests for the plugin while running scripts.
-"""
-# Module imports
-# Std lib
-import inspect
-
-# Our own
-
-#-----------------------------------------------------------------------------
-# Testing functions
-
-def test_trivial():
- """A trivial passing test."""
- pass
-
-def doctest_run():
- """Test running a trivial script.
-
- In [13]: run simplevars.py
- x is: 1
- """
-
-def doctest_runvars():
- """Test that variables defined in scripts get loaded correcly via %run.
-
- In [13]: run simplevars.py
- x is: 1
-
- In [14]: x
- Out[14]: 1
- """
-
-def doctest_ivars():
- """Test that variables defined interactively are picked up.
- In [5]: zz=1
-
- In [6]: zz
- Out[6]: 1
- """
-
-def doctest_refs():
- """DocTest reference holding issues when running scripts.
-
- In [32]: run show_refs.py
- c referrers: [<... 'dict'>]
- """
+"""Some simple tests for the plugin while running scripts.
+"""
+# Module imports
+# Std lib
+import inspect
+
+# Our own
+
+#-----------------------------------------------------------------------------
+# Testing functions
+
+def test_trivial():
+ """A trivial passing test."""
+ pass
+
+def doctest_run():
+ """Test running a trivial script.
+
+ In [13]: run simplevars.py
+ x is: 1
+ """
+
+def doctest_runvars():
+ """Test that variables defined in scripts get loaded correcly via %run.
+
+ In [13]: run simplevars.py
+ x is: 1
+
+ In [14]: x
+ Out[14]: 1
+ """
+
+def doctest_ivars():
+ """Test that variables defined interactively are picked up.
+ In [5]: zz=1
+
+ In [6]: zz
+ Out[6]: 1
+ """
+
+def doctest_refs():
+ """DocTest reference holding issues when running scripts.
+
+ In [32]: run show_refs.py
+ c referrers: [<... 'dict'>]
+ """
diff --git a/contrib/python/ipython/py2/IPython/testing/skipdoctest.py b/contrib/python/ipython/py2/IPython/testing/skipdoctest.py
index 564ca54027..8357f609b0 100644
--- a/contrib/python/ipython/py2/IPython/testing/skipdoctest.py
+++ b/contrib/python/ipython/py2/IPython/testing/skipdoctest.py
@@ -1,41 +1,41 @@
-"""Decorators marks that a doctest should be skipped, for both python 2 and 3.
-
-The IPython.testing.decorators module triggers various extra imports, including
-numpy and sympy if they're present. Since this decorator is used in core parts
-of IPython, it's in a separate module so that running IPython doesn't trigger
-those imports."""
-
-#-----------------------------------------------------------------------------
-# Copyright (C) 2009-2011 The IPython Development Team
-#
-# Distributed under the terms of the BSD License. The full license is in
-# the file COPYING, distributed as part of this software.
-#-----------------------------------------------------------------------------
-
-#-----------------------------------------------------------------------------
-# Imports
-#-----------------------------------------------------------------------------
-
-import sys
-
-#-----------------------------------------------------------------------------
-# Decorators
-#-----------------------------------------------------------------------------
-
-def skip_doctest(f):
- """Decorator - mark a function or method for skipping its doctest.
-
- This decorator allows you to mark a function whose docstring you wish to
- omit from testing, while preserving the docstring for introspection, help,
- etc."""
- f.skip_doctest = True
- return f
-
-
-def skip_doctest_py3(f):
- """Decorator - skip the doctest under Python 3."""
- f.skip_doctest = (sys.version_info[0] >= 3)
- return f
+"""Decorators marks that a doctest should be skipped, for both python 2 and 3.
+
+The IPython.testing.decorators module triggers various extra imports, including
+numpy and sympy if they're present. Since this decorator is used in core parts
+of IPython, it's in a separate module so that running IPython doesn't trigger
+those imports."""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2009-2011 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import sys
+
+#-----------------------------------------------------------------------------
+# Decorators
+#-----------------------------------------------------------------------------
+
+def skip_doctest(f):
+ """Decorator - mark a function or method for skipping its doctest.
+
+ This decorator allows you to mark a function whose docstring you wish to
+ omit from testing, while preserving the docstring for introspection, help,
+ etc."""
+ f.skip_doctest = True
+ return f
+
+
+def skip_doctest_py3(f):
+ """Decorator - skip the doctest under Python 3."""
+ f.skip_doctest = (sys.version_info[0] >= 3)
+ return f
def skip_doctest_py2(f):
"""Decorator - skip the doctest under Python 3."""
diff --git a/contrib/python/ipython/py2/IPython/testing/tools.py b/contrib/python/ipython/py2/IPython/testing/tools.py
index 23bf6a68cb..98f796fe3c 100644
--- a/contrib/python/ipython/py2/IPython/testing/tools.py
+++ b/contrib/python/ipython/py2/IPython/testing/tools.py
@@ -1,296 +1,296 @@
-"""Generic testing tools.
-
-Authors
--------
-- Fernando Perez <Fernando.Perez@berkeley.edu>
-"""
-
-from __future__ import absolute_import
-
+"""Generic testing tools.
+
+Authors
+-------
+- Fernando Perez <Fernando.Perez@berkeley.edu>
+"""
+
+from __future__ import absolute_import
+
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
-
-import os
-import re
-import sys
-import tempfile
-
-from contextlib import contextmanager
-from io import StringIO
-from subprocess import Popen, PIPE
+
+import os
+import re
+import sys
+import tempfile
+
+from contextlib import contextmanager
+from io import StringIO
+from subprocess import Popen, PIPE
try:
from unittest.mock import patch
except ImportError:
# Python 2 compatibility
from mock import patch
-
-try:
- # These tools are used by parts of the runtime, so we make the nose
- # dependency optional at this point. Nose is a hard dependency to run the
- # test suite, but NOT to use ipython itself.
- import nose.tools as nt
- has_nose = True
-except ImportError:
- has_nose = False
-
-from traitlets.config.loader import Config
-from IPython.utils.process import get_output_error_code
-from IPython.utils.text import list_strings
-from IPython.utils.io import temp_pyfile, Tee
-from IPython.utils import py3compat
-from IPython.utils.encoding import DEFAULT_ENCODING
-
-from . import decorators as dec
-from . import skipdoctest
-
-
-# The docstring for full_path doctests differently on win32 (different path
-# separator) so just skip the doctest there. The example remains informative.
-doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
-
-@doctest_deco
-def full_path(startPath,files):
- """Make full paths for all the listed files, based on startPath.
-
- Only the base part of startPath is kept, since this routine is typically
- used with a script's ``__file__`` variable as startPath. The base of startPath
- is then prepended to all the listed files, forming the output list.
-
- Parameters
- ----------
- startPath : string
- Initial path to use as the base for the results. This path is split
- using os.path.split() and only its first component is kept.
-
- files : string or list
- One or more files.
-
- Examples
- --------
-
- >>> full_path('/foo/bar.py',['a.txt','b.txt'])
- ['/foo/a.txt', '/foo/b.txt']
-
- >>> full_path('/foo',['a.txt','b.txt'])
- ['/a.txt', '/b.txt']
-
- If a single file is given, the output is still a list::
-
- >>> full_path('/foo','a.txt')
- ['/a.txt']
- """
-
- files = list_strings(files)
- base = os.path.split(startPath)[0]
- return [ os.path.join(base,f) for f in files ]
-
-
-def parse_test_output(txt):
- """Parse the output of a test run and return errors, failures.
-
- Parameters
- ----------
- txt : str
- Text output of a test run, assumed to contain a line of one of the
- following forms::
-
- 'FAILED (errors=1)'
- 'FAILED (failures=1)'
- 'FAILED (errors=1, failures=1)'
-
- Returns
- -------
- nerr, nfail
- number of errors and failures.
- """
-
- err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
- if err_m:
- nerr = int(err_m.group(1))
- nfail = 0
- return nerr, nfail
-
- fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
- if fail_m:
- nerr = 0
- nfail = int(fail_m.group(1))
- return nerr, nfail
-
- both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
- re.MULTILINE)
- if both_m:
- nerr = int(both_m.group(1))
- nfail = int(both_m.group(2))
- return nerr, nfail
-
- # If the input didn't match any of these forms, assume no error/failures
- return 0, 0
-
-
-# So nose doesn't think this is a test
-parse_test_output.__test__ = False
-
-
-def default_argv():
- """Return a valid default argv for creating testing instances of ipython"""
-
- return ['--quick', # so no config file is loaded
- # Other defaults to minimize side effects on stdout
- '--colors=NoColor', '--no-term-title','--no-banner',
- '--autocall=0']
-
-
-def default_config():
- """Return a config object with good defaults for testing."""
- config = Config()
- config.TerminalInteractiveShell.colors = 'NoColor'
- config.TerminalTerminalInteractiveShell.term_title = False,
- config.TerminalInteractiveShell.autocall = 0
- f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
- config.HistoryManager.hist_file = f.name
- f.close()
- config.HistoryManager.db_cache_size = 10000
- return config
-
-
-def get_ipython_cmd(as_string=False):
- """
- Return appropriate IPython command line name. By default, this will return
- a list that can be used with subprocess.Popen, for example, but passing
- `as_string=True` allows for returning the IPython command as a string.
-
- Parameters
- ----------
- as_string: bool
- Flag to allow to return the command as a string.
- """
- ipython_cmd = [sys.executable, "-m", "IPython"]
-
- if as_string:
- ipython_cmd = " ".join(ipython_cmd)
-
- return ipython_cmd
-
-def ipexec(fname, options=None, commands=()):
- """Utility to call 'ipython filename'.
-
- Starts IPython with a minimal and safe configuration to make startup as fast
- as possible.
-
- Note that this starts IPython in a subprocess!
-
- Parameters
- ----------
- fname : str
- Name of file to be executed (should have .py or .ipy extension).
-
- options : optional, list
- Extra command-line flags to be passed to IPython.
-
- commands : optional, list
- Commands to send in on stdin
-
- Returns
- -------
- (stdout, stderr) of ipython subprocess.
- """
- if options is None: options = []
-
+
+try:
+ # These tools are used by parts of the runtime, so we make the nose
+ # dependency optional at this point. Nose is a hard dependency to run the
+ # test suite, but NOT to use ipython itself.
+ import nose.tools as nt
+ has_nose = True
+except ImportError:
+ has_nose = False
+
+from traitlets.config.loader import Config
+from IPython.utils.process import get_output_error_code
+from IPython.utils.text import list_strings
+from IPython.utils.io import temp_pyfile, Tee
+from IPython.utils import py3compat
+from IPython.utils.encoding import DEFAULT_ENCODING
+
+from . import decorators as dec
+from . import skipdoctest
+
+
+# The docstring for full_path doctests differently on win32 (different path
+# separator) so just skip the doctest there. The example remains informative.
+doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
+
+@doctest_deco
+def full_path(startPath,files):
+ """Make full paths for all the listed files, based on startPath.
+
+ Only the base part of startPath is kept, since this routine is typically
+ used with a script's ``__file__`` variable as startPath. The base of startPath
+ is then prepended to all the listed files, forming the output list.
+
+ Parameters
+ ----------
+ startPath : string
+ Initial path to use as the base for the results. This path is split
+ using os.path.split() and only its first component is kept.
+
+ files : string or list
+ One or more files.
+
+ Examples
+ --------
+
+ >>> full_path('/foo/bar.py',['a.txt','b.txt'])
+ ['/foo/a.txt', '/foo/b.txt']
+
+ >>> full_path('/foo',['a.txt','b.txt'])
+ ['/a.txt', '/b.txt']
+
+ If a single file is given, the output is still a list::
+
+ >>> full_path('/foo','a.txt')
+ ['/a.txt']
+ """
+
+ files = list_strings(files)
+ base = os.path.split(startPath)[0]
+ return [ os.path.join(base,f) for f in files ]
+
+
+def parse_test_output(txt):
+ """Parse the output of a test run and return errors, failures.
+
+ Parameters
+ ----------
+ txt : str
+ Text output of a test run, assumed to contain a line of one of the
+ following forms::
+
+ 'FAILED (errors=1)'
+ 'FAILED (failures=1)'
+ 'FAILED (errors=1, failures=1)'
+
+ Returns
+ -------
+ nerr, nfail
+ number of errors and failures.
+ """
+
+ err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
+ if err_m:
+ nerr = int(err_m.group(1))
+ nfail = 0
+ return nerr, nfail
+
+ fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
+ if fail_m:
+ nerr = 0
+ nfail = int(fail_m.group(1))
+ return nerr, nfail
+
+ both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
+ re.MULTILINE)
+ if both_m:
+ nerr = int(both_m.group(1))
+ nfail = int(both_m.group(2))
+ return nerr, nfail
+
+ # If the input didn't match any of these forms, assume no error/failures
+ return 0, 0
+
+
+# So nose doesn't think this is a test
+parse_test_output.__test__ = False
+
+
+def default_argv():
+ """Return a valid default argv for creating testing instances of ipython"""
+
+ return ['--quick', # so no config file is loaded
+ # Other defaults to minimize side effects on stdout
+ '--colors=NoColor', '--no-term-title','--no-banner',
+ '--autocall=0']
+
+
+def default_config():
+ """Return a config object with good defaults for testing."""
+ config = Config()
+ config.TerminalInteractiveShell.colors = 'NoColor'
+ config.TerminalTerminalInteractiveShell.term_title = False,
+ config.TerminalInteractiveShell.autocall = 0
+ f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
+ config.HistoryManager.hist_file = f.name
+ f.close()
+ config.HistoryManager.db_cache_size = 10000
+ return config
+
+
+def get_ipython_cmd(as_string=False):
+ """
+ Return appropriate IPython command line name. By default, this will return
+ a list that can be used with subprocess.Popen, for example, but passing
+ `as_string=True` allows for returning the IPython command as a string.
+
+ Parameters
+ ----------
+ as_string: bool
+ Flag to allow to return the command as a string.
+ """
+ ipython_cmd = [sys.executable, "-m", "IPython"]
+
+ if as_string:
+ ipython_cmd = " ".join(ipython_cmd)
+
+ return ipython_cmd
+
+def ipexec(fname, options=None, commands=()):
+ """Utility to call 'ipython filename'.
+
+ Starts IPython with a minimal and safe configuration to make startup as fast
+ as possible.
+
+ Note that this starts IPython in a subprocess!
+
+ Parameters
+ ----------
+ fname : str
+ Name of file to be executed (should have .py or .ipy extension).
+
+ options : optional, list
+ Extra command-line flags to be passed to IPython.
+
+ commands : optional, list
+ Commands to send in on stdin
+
+ Returns
+ -------
+ (stdout, stderr) of ipython subprocess.
+ """
+ if options is None: options = []
+
cmdargs = default_argv() + options
-
- test_dir = os.path.dirname(__file__)
-
- ipython_cmd = get_ipython_cmd()
- # Absolute path for filename
- full_fname = os.path.join(test_dir, fname)
- full_cmd = ipython_cmd + cmdargs + [full_fname]
- env = os.environ.copy()
- # FIXME: ignore all warnings in ipexec while we have shims
- # should we keep suppressing warnings here, even after removing shims?
- env['PYTHONWARNINGS'] = 'ignore'
- # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
- for k, v in env.items():
- # Debug a bizarre failure we've seen on Windows:
- # TypeError: environment can only contain strings
- if not isinstance(v, str):
- print(k, v)
- p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
- out, err = p.communicate(input=py3compat.str_to_bytes('\n'.join(commands)) or None)
- out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
- # `import readline` causes 'ESC[?1034h' to be output sometimes,
- # so strip that out before doing comparisons
- if out:
- out = re.sub(r'\x1b\[[^h]+h', '', out)
- return out, err
-
-
-def ipexec_validate(fname, expected_out, expected_err='',
- options=None, commands=()):
- """Utility to call 'ipython filename' and validate output/error.
-
- This function raises an AssertionError if the validation fails.
-
- Note that this starts IPython in a subprocess!
-
- Parameters
- ----------
- fname : str
- Name of the file to be executed (should have .py or .ipy extension).
-
- expected_out : str
- Expected stdout of the process.
-
- expected_err : optional, str
- Expected stderr of the process.
-
- options : optional, list
- Extra command-line flags to be passed to IPython.
-
- Returns
- -------
- None
- """
-
- import nose.tools as nt
-
- out, err = ipexec(fname, options, commands)
- #print 'OUT', out # dbg
- #print 'ERR', err # dbg
- # If there are any errors, we must check those befor stdout, as they may be
- # more informative than simply having an empty stdout.
- if err:
- if expected_err:
- nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
- else:
- raise ValueError('Running file %r produced error: %r' %
- (fname, err))
- # If no errors or output on stderr was expected, match stdout
- nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
-
-
-class TempFileMixin(object):
- """Utility class to create temporary Python/IPython files.
-
- Meant as a mixin class for test cases."""
-
- def mktmp(self, src, ext='.py'):
- """Make a valid python temp file."""
- fname, f = temp_pyfile(src, ext)
- self.tmpfile = f
- self.fname = fname
-
- def tearDown(self):
- if hasattr(self, 'tmpfile'):
- # If the tmpfile wasn't made because of skipped tests, like in
- # win32, there's nothing to cleanup.
- self.tmpfile.close()
- try:
- os.unlink(self.fname)
- except:
- # On Windows, even though we close the file, we still can't
- # delete it. I have no clue why
- pass
-
+
+ test_dir = os.path.dirname(__file__)
+
+ ipython_cmd = get_ipython_cmd()
+ # Absolute path for filename
+ full_fname = os.path.join(test_dir, fname)
+ full_cmd = ipython_cmd + cmdargs + [full_fname]
+ env = os.environ.copy()
+ # FIXME: ignore all warnings in ipexec while we have shims
+ # should we keep suppressing warnings here, even after removing shims?
+ env['PYTHONWARNINGS'] = 'ignore'
+ # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
+ for k, v in env.items():
+ # Debug a bizarre failure we've seen on Windows:
+ # TypeError: environment can only contain strings
+ if not isinstance(v, str):
+ print(k, v)
+ p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
+ out, err = p.communicate(input=py3compat.str_to_bytes('\n'.join(commands)) or None)
+ out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
+ # `import readline` causes 'ESC[?1034h' to be output sometimes,
+ # so strip that out before doing comparisons
+ if out:
+ out = re.sub(r'\x1b\[[^h]+h', '', out)
+ return out, err
+
+
+def ipexec_validate(fname, expected_out, expected_err='',
+ options=None, commands=()):
+ """Utility to call 'ipython filename' and validate output/error.
+
+ This function raises an AssertionError if the validation fails.
+
+ Note that this starts IPython in a subprocess!
+
+ Parameters
+ ----------
+ fname : str
+ Name of the file to be executed (should have .py or .ipy extension).
+
+ expected_out : str
+ Expected stdout of the process.
+
+ expected_err : optional, str
+ Expected stderr of the process.
+
+ options : optional, list
+ Extra command-line flags to be passed to IPython.
+
+ Returns
+ -------
+ None
+ """
+
+ import nose.tools as nt
+
+ out, err = ipexec(fname, options, commands)
+ #print 'OUT', out # dbg
+ #print 'ERR', err # dbg
+ # If there are any errors, we must check those befor stdout, as they may be
+ # more informative than simply having an empty stdout.
+ if err:
+ if expected_err:
+ nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
+ else:
+ raise ValueError('Running file %r produced error: %r' %
+ (fname, err))
+ # If no errors or output on stderr was expected, match stdout
+ nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
+
+
+class TempFileMixin(object):
+ """Utility class to create temporary Python/IPython files.
+
+ Meant as a mixin class for test cases."""
+
+ def mktmp(self, src, ext='.py'):
+ """Make a valid python temp file."""
+ fname, f = temp_pyfile(src, ext)
+ self.tmpfile = f
+ self.fname = fname
+
+ def tearDown(self):
+ if hasattr(self, 'tmpfile'):
+ # If the tmpfile wasn't made because of skipped tests, like in
+ # win32, there's nothing to cleanup.
+ self.tmpfile.close()
+ try:
+ os.unlink(self.fname)
+ except:
+ # On Windows, even though we close the file, we still can't
+ # delete it. I have no clue why
+ pass
+
def __enter__(self):
return self
@@ -298,149 +298,149 @@ class TempFileMixin(object):
self.tearDown()
-pair_fail_msg = ("Testing {0}\n\n"
- "In:\n"
- " {1!r}\n"
- "Expected:\n"
- " {2!r}\n"
- "Got:\n"
- " {3!r}\n")
-def check_pairs(func, pairs):
- """Utility function for the common case of checking a function with a
- sequence of input/output pairs.
-
- Parameters
- ----------
- func : callable
- The function to be tested. Should accept a single argument.
- pairs : iterable
- A list of (input, expected_output) tuples.
-
- Returns
- -------
- None. Raises an AssertionError if any output does not match the expected
- value.
- """
- name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
- for inp, expected in pairs:
- out = func(inp)
- assert out == expected, pair_fail_msg.format(name, inp, expected, out)
-
-
-if py3compat.PY3:
- MyStringIO = StringIO
-else:
- # In Python 2, stdout/stderr can have either bytes or unicode written to them,
- # so we need a class that can handle both.
- class MyStringIO(StringIO):
- def write(self, s):
- s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
- super(MyStringIO, self).write(s)
-
-_re_type = type(re.compile(r''))
-
-notprinted_msg = """Did not find {0!r} in printed output (on {1}):
--------
-{2!s}
--------
-"""
-
-class AssertPrints(object):
- """Context manager for testing that code prints certain text.
-
- Examples
- --------
- >>> with AssertPrints("abc", suppress=False):
- ... print("abcd")
- ... print("def")
- ...
- abcd
- def
- """
- def __init__(self, s, channel='stdout', suppress=True):
- self.s = s
- if isinstance(self.s, (py3compat.string_types, _re_type)):
- self.s = [self.s]
- self.channel = channel
- self.suppress = suppress
-
- def __enter__(self):
- self.orig_stream = getattr(sys, self.channel)
- self.buffer = MyStringIO()
- self.tee = Tee(self.buffer, channel=self.channel)
- setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
-
- def __exit__(self, etype, value, traceback):
- try:
- if value is not None:
- # If an error was raised, don't check anything else
- return False
- self.tee.flush()
- setattr(sys, self.channel, self.orig_stream)
- printed = self.buffer.getvalue()
- for s in self.s:
- if isinstance(s, _re_type):
- assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
- else:
- assert s in printed, notprinted_msg.format(s, self.channel, printed)
- return False
- finally:
- self.tee.close()
-
-printed_msg = """Found {0!r} in printed output (on {1}):
--------
-{2!s}
--------
-"""
-
-class AssertNotPrints(AssertPrints):
- """Context manager for checking that certain output *isn't* produced.
-
- Counterpart of AssertPrints"""
- def __exit__(self, etype, value, traceback):
- try:
- if value is not None:
- # If an error was raised, don't check anything else
- self.tee.close()
- return False
- self.tee.flush()
- setattr(sys, self.channel, self.orig_stream)
- printed = self.buffer.getvalue()
- for s in self.s:
- if isinstance(s, _re_type):
- assert not s.search(printed),printed_msg.format(
- s.pattern, self.channel, printed)
- else:
- assert s not in printed, printed_msg.format(
- s, self.channel, printed)
- return False
- finally:
- self.tee.close()
-
-@contextmanager
-def mute_warn():
- from IPython.utils import warn
- save_warn = warn.warn
- warn.warn = lambda *a, **kw: None
- try:
- yield
- finally:
- warn.warn = save_warn
-
-@contextmanager
-def make_tempfile(name):
- """ Create an empty, named, temporary file for the duration of the context.
- """
- f = open(name, 'w')
- f.close()
- try:
- yield
- finally:
- os.unlink(name)
-
+pair_fail_msg = ("Testing {0}\n\n"
+ "In:\n"
+ " {1!r}\n"
+ "Expected:\n"
+ " {2!r}\n"
+ "Got:\n"
+ " {3!r}\n")
+def check_pairs(func, pairs):
+ """Utility function for the common case of checking a function with a
+ sequence of input/output pairs.
+
+ Parameters
+ ----------
+ func : callable
+ The function to be tested. Should accept a single argument.
+ pairs : iterable
+ A list of (input, expected_output) tuples.
+
+ Returns
+ -------
+ None. Raises an AssertionError if any output does not match the expected
+ value.
+ """
+ name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
+ for inp, expected in pairs:
+ out = func(inp)
+ assert out == expected, pair_fail_msg.format(name, inp, expected, out)
+
+
+if py3compat.PY3:
+ MyStringIO = StringIO
+else:
+ # In Python 2, stdout/stderr can have either bytes or unicode written to them,
+ # so we need a class that can handle both.
+ class MyStringIO(StringIO):
+ def write(self, s):
+ s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
+ super(MyStringIO, self).write(s)
+
+_re_type = type(re.compile(r''))
+
+notprinted_msg = """Did not find {0!r} in printed output (on {1}):
+-------
+{2!s}
+-------
+"""
+
+class AssertPrints(object):
+ """Context manager for testing that code prints certain text.
+
+ Examples
+ --------
+ >>> with AssertPrints("abc", suppress=False):
+ ... print("abcd")
+ ... print("def")
+ ...
+ abcd
+ def
+ """
+ def __init__(self, s, channel='stdout', suppress=True):
+ self.s = s
+ if isinstance(self.s, (py3compat.string_types, _re_type)):
+ self.s = [self.s]
+ self.channel = channel
+ self.suppress = suppress
+
+ def __enter__(self):
+ self.orig_stream = getattr(sys, self.channel)
+ self.buffer = MyStringIO()
+ self.tee = Tee(self.buffer, channel=self.channel)
+ setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
+
+ def __exit__(self, etype, value, traceback):
+ try:
+ if value is not None:
+ # If an error was raised, don't check anything else
+ return False
+ self.tee.flush()
+ setattr(sys, self.channel, self.orig_stream)
+ printed = self.buffer.getvalue()
+ for s in self.s:
+ if isinstance(s, _re_type):
+ assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
+ else:
+ assert s in printed, notprinted_msg.format(s, self.channel, printed)
+ return False
+ finally:
+ self.tee.close()
+
+printed_msg = """Found {0!r} in printed output (on {1}):
+-------
+{2!s}
+-------
+"""
+
+class AssertNotPrints(AssertPrints):
+ """Context manager for checking that certain output *isn't* produced.
+
+ Counterpart of AssertPrints"""
+ def __exit__(self, etype, value, traceback):
+ try:
+ if value is not None:
+ # If an error was raised, don't check anything else
+ self.tee.close()
+ return False
+ self.tee.flush()
+ setattr(sys, self.channel, self.orig_stream)
+ printed = self.buffer.getvalue()
+ for s in self.s:
+ if isinstance(s, _re_type):
+ assert not s.search(printed),printed_msg.format(
+ s.pattern, self.channel, printed)
+ else:
+ assert s not in printed, printed_msg.format(
+ s, self.channel, printed)
+ return False
+ finally:
+ self.tee.close()
+
+@contextmanager
+def mute_warn():
+ from IPython.utils import warn
+ save_warn = warn.warn
+ warn.warn = lambda *a, **kw: None
+ try:
+ yield
+ finally:
+ warn.warn = save_warn
+
+@contextmanager
+def make_tempfile(name):
+ """ Create an empty, named, temporary file for the duration of the context.
+ """
+ f = open(name, 'w')
+ f.close()
+ try:
+ yield
+ finally:
+ os.unlink(name)
+
def fake_input(inputs):
"""Temporarily replace the input() function to return the given values
-
+
Use as a context manager:
with fake_input(['result1', 'result2']):
@@ -460,24 +460,24 @@ def fake_input(inputs):
'input' if py3compat.PY3 else 'raw_input')
return patch(input_name, mock_input)
-def help_output_test(subcommand=''):
- """test that `ipython [subcommand] -h` works"""
- cmd = get_ipython_cmd() + [subcommand, '-h']
- out, err, rc = get_output_error_code(cmd)
- nt.assert_equal(rc, 0, err)
- nt.assert_not_in("Traceback", err)
- nt.assert_in("Options", out)
- nt.assert_in("--help-all", out)
- return out, err
-
-
-def help_all_output_test(subcommand=''):
- """test that `ipython [subcommand] --help-all` works"""
- cmd = get_ipython_cmd() + [subcommand, '--help-all']
- out, err, rc = get_output_error_code(cmd)
- nt.assert_equal(rc, 0, err)
- nt.assert_not_in("Traceback", err)
- nt.assert_in("Options", out)
+def help_output_test(subcommand=''):
+ """test that `ipython [subcommand] -h` works"""
+ cmd = get_ipython_cmd() + [subcommand, '-h']
+ out, err, rc = get_output_error_code(cmd)
+ nt.assert_equal(rc, 0, err)
+ nt.assert_not_in("Traceback", err)
+ nt.assert_in("Options", out)
+ nt.assert_in("--help-all", out)
+ return out, err
+
+
+def help_all_output_test(subcommand=''):
+ """test that `ipython [subcommand] --help-all` works"""
+ cmd = get_ipython_cmd() + [subcommand, '--help-all']
+ out, err, rc = get_output_error_code(cmd)
+ nt.assert_equal(rc, 0, err)
+ nt.assert_not_in("Traceback", err)
+ nt.assert_in("Options", out)
nt.assert_in("Class", out)
- return out, err
-
+ return out, err
+