##// END OF EJS Templates
Merge pull request #12008 from meeseeksmachine/auto-backport-of-pr-12007-on-7.10.x...
Merge pull request #12008 from meeseeksmachine/auto-backport-of-pr-12007-on-7.10.x Backport PR #12007 on branch 7.10.x (Fix the right inputhook)

File last commit:

r25224:93500dbe
r25331:cef81a6f merge
Show More
decorators.py
383 lines | 12.5 KiB | text/x-python | PythonLexer
Thomas Kluyver
Use better temp file for onlyif_unicode_paths test.
r3904 # -*- coding: utf-8 -*-
Fernando Perez
Checkpoint with more tests working....
r1420 """Decorators for labeling test objects.
Fernando Perez
Update decorators and test scripts.
r1848 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.
Fernando Perez
Checkpoint with more tests working....
r1420
Fernando Perez
Add new decorators to skip os-specific tests....
r1721 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.
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368 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.
Paul Ivanov
make know failures report as 'K'...
r3511 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.
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368
Fernando Perez
Checkpoint with more tests working....
r1420 """
Min RK
use py3compat.which in common locations
r21122 # Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368
Paul Ivanov
skip tests when display variable is not set
r11970 import os
Hugo
Remove redundant Python 2 code
r24010 import shutil
import sys
Thomas Kluyver
Add test decorator onlyif_unicode_paths....
r3903 import tempfile
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368 import unittest
Matthias Bussonnier
Actually warn that some function will be removed....
r21788 import warnings
Diego Garcia
use `import_module` instead of `__import__` ( FIX #10008 )
r22954 from importlib import import_module
Fernando Perez
Checkpoint with more tests working....
r1420
MinRK
remove decorator from external
r20813 from decorator import decorator
Fernando Perez
Checkpoint with more tests working....
r1420
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414 # Expose the unittest-driven decorators
Thomas Kluyver
Use explicit relative imports...
r13347 from .ipunittest import ipdoctest, ipdocstring
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414
Fernando Perez
Checkpoint with more tests working....
r1420 # Grab the numpy-specific decorators which we keep in a file that we
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368 # occasionally update from upstream: decorators.py is a copy of
# numpy.testing.decorators, we expose all of it here.
Matthias Bussonnier
Properly don't require numpy to run tests....
r25029 from IPython.external.decorators import knownfailureif
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368
#-----------------------------------------------------------------------------
# Classes and functions
#-----------------------------------------------------------------------------
Fernando Perez
Checkpoint with more tests working....
r1420
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368 # 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
Fernando Perez
Checkpoint with more tests working....
r1420
# Utility functions
Matthias Bussonnier
Add stacklevel to a few deprecation warnings
r22989 def apply_wrapper(wrapper, func):
Fernando Perez
Checkpoint with more tests working....
r1420 """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.
"""
Matthias Bussonnier
Rephrase deprecation warning since 5.0 has been released.
r22991 warnings.warn("The function `apply_wrapper` is deprecated since IPython 4.0",
Matthias Bussonnier
Add stacklevel to a few deprecation warnings
r22989 DeprecationWarning, stacklevel=2)
Fernando Perez
Checkpoint with more tests working....
r1420 import nose.tools
return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
Matthias Bussonnier
Add stacklevel to a few deprecation warnings
r22989 def make_label_dec(label, ds=None):
Fernando Perez
Checkpoint with more tests working....
r1420 """Factory function to create a decorator that applies one or more labels.
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368 Parameters
----------
Fernando Perez
Checkpoint with more tests working....
r1420 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.
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368 Returns
-------
Fernando Perez
Checkpoint with more tests working....
r1420 A decorator.
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368 Examples
--------
Fernando Perez
Checkpoint with more tests working....
r1420
A simple labeling decorator:
Fernando Perez
Change doctest that was failing due to python2/3 print syntax issues.
r11040 >>> slow = make_label_dec('slow')
>>> slow.__doc__
"Labels a test as 'slow'."
Nicholas Bollweg
add skip_win32_py38 decorator, skip another test
r25224
Fernando Perez
Checkpoint with more tests working....
r1420 And one that uses multiple labels and a custom docstring:
Nicholas Bollweg
add skip_win32_py38 decorator, skip another test
r25224
Fernando Perez
Checkpoint with more tests working....
r1420 >>> rare = make_label_dec(['slow','hard'],
... "Mix labels 'slow' and 'hard' for rare tests.")
Fernando Perez
Change doctest that was failing due to python2/3 print syntax issues.
r11040 >>> rare.__doc__
"Mix labels 'slow' and 'hard' for rare tests."
Fernando Perez
Checkpoint with more tests working....
r1420
Now, let's test using this one:
>>> @rare
... def f(): pass
...
>>>
>>> f.slow
True
>>> f.hard
True
"""
Matthias Bussonnier
Rephrase deprecation warning since 5.0 has been released.
r22991 warnings.warn("The function `make_label_dec` is deprecated since IPython 4.0",
Matthias Bussonnier
Add stacklevel to a few deprecation warnings
r22989 DeprecationWarning, stacklevel=2)
Srinivas Reddy Thatiparthy
convert string_types to str
r23037 if isinstance(label, str):
Fernando Perez
Checkpoint with more tests working....
r1420 labels = [label]
else:
labels = label
Bernardo B. Marques
remove all trailling spaces
r4872
Fernando Perez
Checkpoint with more tests working....
r1420 # 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
Bernardo B. Marques
remove all trailling spaces
r4872
Fernando Perez
Checkpoint with more tests working....
r1420 # Apply the user's docstring, or autogenerate a basic one
if ds is None:
ds = "Labels a test as %r." % label
decor.__doc__ = ds
Bernardo B. Marques
remove all trailling spaces
r4872
Fernando Perez
Checkpoint with more tests working....
r1420 return decor
Fernando Perez
Update decorators and test scripts.
r1848 # 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
Fernando Perez
Update docs for automatic API building.
r1850 ----------
Thomas Kluyver
Various docs fixes
r13595
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.
Fernando Perez
Update decorators and test scripts.
r1848 msg : string
Thomas Kluyver
Various docs fixes
r13595 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.
Fernando Perez
Update decorators and test scripts.
r1848
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):
Bernardo B. Marques
remove all trailling spaces
r4872 # Local import to avoid a hard nose dependency and only incur the
# import time overhead at actual test-time.
Fernando Perez
Update decorators and test scripts.
r1848 import nose
# Allow for both boolean or callable skip conditions.
if callable(skip_condition):
Fernando Perez
Add new @onlyif decorator, the reverse of @skipif....
r2452 skip_val = skip_condition
Fernando Perez
Update decorators and test scripts.
r1848 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:
Bernardo B. Marques
remove all trailling spaces
r4872 return f(*args, **kwargs)
Fernando Perez
Update decorators and test scripts.
r1848
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
Bernardo B. Marques
remove all trailling spaces
r4872
Fernando Perez
Update decorators and test scripts.
r1848 return nose.tools.make_decorator(f)(skipper)
return skip_decorator
Jason Grout
Fix typo in comment (insert space)
r6177 # A version with the condition set to true, common case just to attach a message
Fernando Perez
Update decorators and test scripts.
r1848 # to a skip decorator
def skip(msg=None):
"""Decorator factory - mark a test function for skipping from test suite.
Fernando Perez
Add new decorators to skip os-specific tests....
r1721
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368 Parameters
----------
Fernando Perez
Add optional message to @skip test decorator.
r1560 msg : string
Optional message to be added.
Fernando Perez
Update decorators and test scripts.
r1848
Fernando Perez
Add new testing support machinery with better parametric tests....
r2368 Returns
-------
Fernando Perez
Update decorators and test scripts.
r1848 decorator : function
Decorator, which, when applied to a function, causes SkipTest
to be raised, with the optional message added.
Fernando Perez
Add optional message to @skip test decorator.
r1560 """
Matthias Bussonnier
Fix skip decorator....
r25097 if msg and not isinstance(msg, str):
raise ValueError('invalid object passed to `@skip` decorator, did you '
'meant `@skip()` with brackets ?')
return skipif(True, msg)
Gael Varoquaux
Fix tests when ipdoctest nose plugin is enable (Grrr, no isolation at...
r1505
Fernando Perez
Fix error in test decorator.
r1577
Fernando Perez
Add new @onlyif decorator, the reverse of @skipif....
r2452 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)
Fernando Perez
Update decorators and test scripts.
r1848 #-----------------------------------------------------------------------------
# Utility functions for decorators
Paul Ivanov
skip sympy tests if sympy not installed
r3504 def module_not_available(module):
"""Can module be imported? Returns true if module does NOT import.
Fernando Perez
Fix error in test decorator.
r1577
Paul Ivanov
skip sympy tests if sympy not installed
r3504 This is used to make a decorator to skip tests that require module to be
Fernando Perez
Update decorators and test scripts.
r1848 available, but delay the 'import numpy' to test execution time.
"""
try:
Diego Garcia
use `import_module` instead of `__import__` ( FIX #10008 )
r22954 mod = import_module(module)
Paul Ivanov
skip sympy tests if sympy not installed
r3504 mod_not_avail = False
Fernando Perez
Update decorators and test scripts.
r1848 except ImportError:
Paul Ivanov
skip sympy tests if sympy not installed
r3504 mod_not_avail = True
Fernando Perez
Update decorators and test scripts.
r1848
Paul Ivanov
remove unnecessary yield
r3505 return mod_not_avail
Fernando Perez
Update decorators and test scripts.
r1848
Paul Ivanov
skip tests when display variable is not set
r11970
def decorated_dummy(dec, name):
"""Return a dummy function decorated with dec, with the given name.
Nicholas Bollweg
add skip_win32_py38 decorator, skip another test
r25224
Paul Ivanov
skip tests when display variable is not set
r11970 Examples
--------
import IPython.testing.decorators as dec
setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
"""
Matthias Bussonnier
Rephrase deprecation warning since 5.0 has been released.
r22991 warnings.warn("The function `decorated_dummy` is deprecated since IPython 4.0",
Matthias Bussonnier
Add stacklevel to a few deprecation warnings
r22989 DeprecationWarning, stacklevel=2)
Paul Ivanov
skip tests when display variable is not set
r11970 dummy = lambda: None
dummy.__name__ = name
return dec(dummy)
Fernando Perez
Update decorators and test scripts.
r1848 #-----------------------------------------------------------------------------
# Decorators for public use
Fernando Perez
Add new decorators to skip os-specific tests....
r1721 # Decorators to skip certain tests on specific platforms.
Fernando Perez
Merging upstream changes from trunk (after fixing small conflicts).
r1872 skip_win32 = skipif(sys.platform == 'win32',
Fernando Perez
Update decorators and test scripts.
r1848 "This test does not run under Windows")
MinRK
check linux with startswith('linux') instead of =='linux2'...
r4138 skip_linux = skipif(sys.platform.startswith('linux'),
Fernando Perez
Merging upstream changes from trunk (after fixing small conflicts).
r1872 "This test does not run under Linux")
skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
Fernando Perez
Update decorators and test scripts.
r1848
Jorgen Stenarson
Moved skip decorator to testing and created similar ones for OSX and linux, create delete testdirs in module setup/teardown
r1803 # Decorators to skip tests if not on specific platforms.
Fernando Perez
Merging upstream changes from trunk (after fixing small conflicts).
r1872 skip_if_not_win32 = skipif(sys.platform != 'win32',
"This test only runs under Windows")
MinRK
check linux with startswith('linux') instead of =='linux2'...
r4138 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
Fernando Perez
Merging upstream changes from trunk (after fixing small conflicts).
r1872 "This test only runs under Linux")
skip_if_not_osx = skipif(sys.platform != 'darwin',
"This test only runs under OSX")
Paul Ivanov
skip tests when display variable is not set
r11970
_x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
Paul Ivanov
use get, for when DISPLAY variable isn't defined
r12135 os.environ.get('DISPLAY', '') == '')
Paul Ivanov
skip tests when display variable is not set
r11970 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
Nicholas Bollweg
add skip_win32_py38 decorator, skip another test
r25224
# Decorators to skip certain tests on specific platform/python combinations
skip_win32_py38 = skipif(sys.version_info > (3,8) and os.name == 'nt')
Paul Ivanov
skip tests when display variable is not set
r11970 # not a decorator itself, returns a dummy function to be used as setup
def skip_file_no_x11(name):
Matthias Bussonnier
Rephrase deprecation warning since 5.0 has been released.
r22991 warnings.warn("The function `skip_file_no_x11` is deprecated since IPython 4.0",
Matthias Bussonnier
Add stacklevel to a few deprecation warnings
r22989 DeprecationWarning, stacklevel=2)
Paul Ivanov
skip tests when display variable is not set
r11970 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
Fernando Perez
Merging upstream changes from trunk (after fixing small conflicts).
r1872 # Other skip decorators
Fernando Perez
Update decorators and test scripts.
r1848
MinRK
add generic @skip_without(mod) test decorator
r5146 # generic skip without module
skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
Jens Hedegaard Nielsen
Add skipif_not_matplotlib decorator
r4788
MinRK
add generic @skip_without(mod) test decorator
r5146 skipif_not_numpy = skip_without('numpy')
skipif_not_matplotlib = skip_without('matplotlib')
skipif_not_sympy = skip_without('sympy')
Paul Ivanov
skip sympy tests if sympy not installed
r3504
Matthias Bussonnier
Properly don't require numpy to run tests....
r25029 skip_known_failure = knownfailureif(True,'This test is known to fail')
Fernando Perez
Fixes for test suite in win32 when all dependencies (esp. Twisted) are...
r2461
# 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
Thomas Kluyver
Add test decorator onlyif_unicode_paths....
r3903
# 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:
Thomas Kluyver
Use better temp file for onlyif_unicode_paths test.
r3904 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
Thomas Kluyver
Add test decorator onlyif_unicode_paths....
r3903 except UnicodeEncodeError:
unicode_paths = False
else:
unicode_paths = True
Thomas Kluyver
Use better temp file for onlyif_unicode_paths test.
r3904 f.close()
Thomas Kluyver
Add test decorator onlyif_unicode_paths....
r3903
onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
"where we can use unicode in filenames."))
Takafumi Arakaki
Add tests for IPython.lib.latextools
r7858
def onlyif_cmds_exist(*commands):
"""
Decorator to skip test when at least one of `commands` is not found.
"""
for cmd in commands:
Hugo
Remove redundant Python 2 code
r24010 if not shutil.which(cmd):
Min RK
use py3compat.which in common locations
r21122 return skip("This test runs only if command '{0}' "
"is installed".format(cmd))
Takafumi Arakaki
Add tests for IPython.lib.latextools
r7858 return null_deco
MinRK
add @onlyif_any_cmd_exists...
r15438
def onlyif_any_cmd_exists(*commands):
"""
Decorator to skip test unless at least one of `commands` is found.
"""
Matthias Bussonnier
Rephrase deprecation warning since 5.0 has been released.
r22991 warnings.warn("The function `onlyif_any_cmd_exists` is deprecated since IPython 4.0",
Matthias Bussonnier
Add stacklevel to a few deprecation warnings
r22989 DeprecationWarning, stacklevel=2)
MinRK
add @onlyif_any_cmd_exists...
r15438 for cmd in commands:
Hugo
Remove redundant Python 2 code
r24010 if shutil.which(cmd):
Min RK
use py3compat.which in common locations
r21122 return null_deco
MinRK
add @onlyif_any_cmd_exists...
r15438 return skip("This test runs only if one of the commands {0} "
"is installed".format(commands))