##// END OF EJS Templates
Move crash handling to the application level and simplify class structure....
Move crash handling to the application level and simplify class structure. Starting to try to take real advantage of the refactoring, to have generic crash handling. This also lets us initialize the app without needing all the self.attempt() wrappers, since now there's a good system-wide crash handler at the app level (not inside the shell instance). I didn't yet remove the attempt() method because we may have occasional uses for it (we still do, but in one place only). I also removed some extra class layers that weren't quite needed. Creating classes solely for the purpose of passing parameters makes the code (IMO) harder to understand, I kept getting lost in parts of the class hierarchy. I think these changes provide the same flexibility but with easier to follow code (less things to remember, basically). What I tried to do was to use argument passing instead of inheritance for all cases I saw where the inheritance wasn't really adding new functionality. In some cases, this actually allowed me to remove methods that were effectively duplicated in the subclasses.

File last commit:

r2368:277cf879
r2403:08d6ac78
Show More
test_decorators.py
219 lines | 5.4 KiB | text/x-python | PythonLexer
"""Tests for the decorators we've created for IPython.
"""
# Module imports
# Std lib
import inspect
import sys
import unittest
# Third party
import nose.tools as nt
# Our own
from IPython.testing import decorators as dec
from IPython.testing.ipunittest import ParametricTestCase
#-----------------------------------------------------------------------------
# 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):
func_obj = obj.im_func
else:
raise TypeError, 'arg is not a Python function'
args, varargs, varkw = inspect.getargs(func_obj.func_code)
return args, varargs, varkw, func_obj.func_defaults
#-----------------------------------------------------------------------------
# Testing functions
@dec.as_unittest
def trivial():
"""A trivial test"""
pass
# Some examples of parametric tests.
def is_smaller(i,j):
assert i<j,"%s !< %s" % (i,j)
class Tester(ParametricTestCase):
def test_parametric(self):
yield is_smaller(3, 4)
x, y = 1, 2
yield is_smaller(x, y)
@dec.parametric
def test_par_standalone():
yield is_smaller(3, 4)
x, y = 1, 2
yield is_smaller(x, y)
@dec.skip
def test_deliberately_broken():
"""A deliberately broken test - we want to skip this one."""
1/0
@dec.skip('Testing the skip decorator')
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.
@dec.skip_doctest
def doctest_bad(x,y=1,**k):
"""A function whose doctest we need to skip.
>>> 1+1
3
"""
print 'x:',x
print 'y:',y
print 'k:',k
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__
assert check==val,"doctest_bad docstrings don't match"
# Doctest skipping should work for class methods too
class foo(object):
"""Foo
Example:
>>> 1+1
2
"""
@dec.skip_doctest
def __init__(self,x):
"""Make a foo.
Example:
>>> f = foo(3)
junk
"""
print 'Making a foo.'
self.x = x
@dec.skip_doctest
def bar(self,y):
"""Example:
>>> f = foo(3)
>>> f.bar(0)
boom!
>>> 1/0
bam!
"""
return 1/y
def baz(self,y):
"""Example:
>>> f = foo(3)
Making a foo.
>>> f.baz(3)
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():
nt.assert_not_equals(sys.platform,'linux2',"This test can't run under linux")
@dec.skip_win32
def test_win32():
nt.assert_not_equals(sys.platform,'win32',"This test can't run under windows")
@dec.skip_osx
def test_osx():
nt.assert_not_equals(sys.platform,'darwin',"This test can't run under osx")
# Verify that the same decorators work for methods.
# Note: this code is identical to that in test_decorators_trial, but that one
# uses twisted's unittest, not the one from the stdlib, which we are using
# here. While somewhat redundant, we want to check both with the stdlib and
# with twisted, so the duplication is OK.
class TestDecoratorsTrial(unittest.TestCase):
@dec.skip()
def test_deliberately_broken(self):
"""A deliberately broken test - we want to skip this one."""
1/0
@dec.skip('Testing the skip decorator')
def test_deliberately_broken2(self):
"""Another deliberately broken test - we want to skip this one."""
1/0
@dec.skip_linux
def test_linux(self):
self.assertNotEquals(sys.platform, 'linux2',
"This test can't run under linux")
@dec.skip_win32
def test_win32(self):
self.assertNotEquals(sys.platform, 'win32',
"This test can't run under windows")
@dec.skip_osx
def test_osx(self):
self.assertNotEquals(sys.platform, 'darwin',
"This test can't run under osx")