diff options
| author | Mikhail Borisov <[email protected]> | 2022-02-10 16:45:40 +0300 | 
|---|---|---|
| committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:45:40 +0300 | 
| commit | 5d50718e66d9c037dc587a0211110b7d25a66185 (patch) | |
| tree | e98df59de24d2ef7c77baed9f41e4875a2fef972 /contrib/python/ipython/py2/IPython/testing | |
| parent | a6a92afe03e02795227d2641b49819b687f088f8 (diff) | |
Restoring authorship annotation for Mikhail Borisov <[email protected]>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/ipython/py2/IPython/testing')
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 6011b39f77d..165f503169a 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 179ec6f6997..4b0bb8ba9ca 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 2fe72f6cae3..c9807ce70e2 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 a40702cc673..3983393112c 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 9a5a3d6f580..4018264125c 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 6d8834f193c..95aa06e4a4e 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 04ea8320fba..da059816e24 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 <[email protected]>  -"""  -  -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 <[email protected]> +""" + +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 d57d198f15d..6f999a38fd3 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 e08380d9de5..6b34f9e5e10 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 081bf355719..5e02629bf74 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 64e7e536f80..bc750e0efd1 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 25b4634f2f3..a75cab993fc 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 785704337b0..a3281d30c8d 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 4c517da949c..ef7dd157aeb 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 bcc43f55e81..a7d33d9a166 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 ee4039a59ac..5134c6e928b 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 0de694fe7e5..6c8759f3e72 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 f6258b0615d..f8b681eb4ff 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 cbc00cc9761..8afcbfdf7d8 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 05dc387d9b2..a7add7da792 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 8a2a78b75d3..50d0857134e 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 8357f609b0e..564ca540272 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 98f796fe3c1..23bf6a68cb2 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 <[email protected]>  -"""  -  -from __future__ import absolute_import  -  +"""Generic testing tools. + +Authors +------- +- Fernando Perez <[email protected]> +""" + +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 +  | 
