test_decorators.py
166 lines
| 3.9 KiB
| text/x-python
|
PythonLexer
Fernando Perez
|
r1721 | """Tests for the decorators we've created for IPython. | ||
""" | ||||
# Module imports | ||||
# Std lib | ||||
import inspect | ||||
import sys | ||||
# Our own | ||||
from IPython.testing import decorators as dec | ||||
Nikita Kniazev
|
r26938 | from IPython.testing.skipdoctest import skip_doctest | ||
Fernando Perez
|
r1721 | |||
#----------------------------------------------------------------------------- | ||||
# Utilities | ||||
# Note: copied from OInspect, kept here so the testing stuff doesn't create | ||||
# circular dependencies and is easier to reuse. | ||||
def getargspec(obj): | ||||
"""Get the names and default values of a function's arguments. | ||||
A tuple of four things is returned: (args, varargs, varkw, defaults). | ||||
'args' is a list of the argument names (it may contain nested lists). | ||||
'varargs' and 'varkw' are the names of the * and ** arguments or None. | ||||
'defaults' is an n-tuple of the default values of the last n arguments. | ||||
Modified version of inspect.getargspec from the Python Standard | ||||
Library.""" | ||||
if inspect.isfunction(obj): | ||||
func_obj = obj | ||||
elif inspect.ismethod(obj): | ||||
Thomas Kluyver
|
r13370 | func_obj = obj.__func__ | ||
Fernando Perez
|
r1721 | else: | ||
Bradley M. Froehle
|
r7843 | raise TypeError('arg is not a Python function') | ||
Thomas Kluyver
|
r13362 | args, varargs, varkw = inspect.getargs(func_obj.__code__) | ||
return args, varargs, varkw, func_obj.__defaults__ | ||||
Fernando Perez
|
r1721 | |||
#----------------------------------------------------------------------------- | ||||
# Testing functions | ||||
Fernando Perez
|
r2368 | @dec.as_unittest | ||
def trivial(): | ||||
"""A trivial test""" | ||||
pass | ||||
Matthias Bussonnier
|
r25097 | @dec.skip() | ||
Fernando Perez
|
r1721 | def test_deliberately_broken(): | ||
"""A deliberately broken test - we want to skip this one.""" | ||||
1/0 | ||||
Brian Granger
|
r1963 | @dec.skip('Testing the skip decorator') | ||
Fernando Perez
|
r1721 | def test_deliberately_broken2(): | ||
"""Another deliberately broken test - we want to skip this one.""" | ||||
1/0 | ||||
# Verify that we can correctly skip the doctest for a function at will, but | ||||
# that the docstring itself is NOT destroyed by the decorator. | ||||
Nikita Kniazev
|
r26938 | @skip_doctest | ||
Fernando Perez
|
r1721 | def doctest_bad(x,y=1,**k): | ||
"""A function whose doctest we need to skip. | ||||
>>> 1+1 | ||||
3 | ||||
""" | ||||
Thomas Kluyver
|
r13348 | print('x:',x) | ||
print('y:',y) | ||||
print('k:',k) | ||||
Fernando Perez
|
r1721 | |||
def call_doctest_bad(): | ||||
"""Check that we can still call the decorated functions. | ||||
>>> doctest_bad(3,y=4) | ||||
x: 3 | ||||
y: 4 | ||||
k: {} | ||||
""" | ||||
pass | ||||
def test_skip_dt_decorator(): | ||||
"""Doctest-skipping decorator should preserve the docstring. | ||||
""" | ||||
# Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring! | ||||
check = """A function whose doctest we need to skip. | ||||
>>> 1+1 | ||||
3 | ||||
""" | ||||
# Fetch the docstring from doctest_bad after decoration. | ||||
val = doctest_bad.__doc__ | ||||
Samuel Gaist
|
r26884 | assert check == val, "doctest_bad docstrings don't match" | ||
Fernando Perez
|
r2479 | |||
Fernando Perez
|
r1721 | |||
# Doctest skipping should work for class methods too | ||||
Fernando Perez
|
r2479 | class FooClass(object): | ||
"""FooClass | ||||
Fernando Perez
|
r1721 | |||
Example: | ||||
>>> 1+1 | ||||
2 | ||||
""" | ||||
Nikita Kniazev
|
r26938 | @skip_doctest | ||
Fernando Perez
|
r1721 | def __init__(self,x): | ||
Fernando Perez
|
r2479 | """Make a FooClass. | ||
Fernando Perez
|
r1721 | |||
Example: | ||||
Fernando Perez
|
r2479 | >>> f = FooClass(3) | ||
Fernando Perez
|
r1721 | junk | ||
""" | ||||
Thomas Kluyver
|
r13348 | print('Making a FooClass.') | ||
Fernando Perez
|
r1721 | self.x = x | ||
Nikita Kniazev
|
r26938 | @skip_doctest | ||
Fernando Perez
|
r1721 | def bar(self,y): | ||
"""Example: | ||||
Fernando Perez
|
r2479 | >>> ff = FooClass(3) | ||
>>> ff.bar(0) | ||||
Fernando Perez
|
r1721 | boom! | ||
>>> 1/0 | ||||
bam! | ||||
""" | ||||
return 1/y | ||||
def baz(self,y): | ||||
"""Example: | ||||
Fernando Perez
|
r2479 | >>> ff2 = FooClass(3) | ||
Making a FooClass. | ||||
>>> ff2.baz(3) | ||||
Fernando Perez
|
r1721 | True | ||
""" | ||||
return self.x==y | ||||
def test_skip_dt_decorator2(): | ||||
"""Doctest-skipping decorator should preserve function signature. | ||||
""" | ||||
# Hardcoded correct answer | ||||
dtargs = (['x', 'y'], None, 'k', (1,)) | ||||
# Introspect out the value | ||||
dtargsr = getargspec(doctest_bad) | ||||
assert dtargsr==dtargs, \ | ||||
"Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,) | ||||
@dec.skip_linux | ||||
def test_linux(): | ||||
Samuel Gaist
|
r26884 | assert sys.platform.startswith("linux") is False, "This test can't run under linux" | ||
Fernando Perez
|
r1721 | |||
@dec.skip_win32 | ||||
def test_win32(): | ||||
Samuel Gaist
|
r26884 | assert sys.platform != "win32", "This test can't run under windows" | ||
Fernando Perez
|
r1721 | |||
@dec.skip_osx | ||||
def test_osx(): | ||||
Samuel Gaist
|
r26884 | assert sys.platform != "darwin", "This test can't run under osx" | ||