Imported Upstream version 1.1.2
[platform/upstream/python-nose.git] / nose / tools / nontrivial.py
1 """Tools not exempt from being descended into in tracebacks"""
2
3 import time
4
5
6 __all__ = ['make_decorator', 'raises', 'set_trace', 'timed', 'with_setup',
7            'TimeExpired', 'istest', 'nottest']
8
9
10 class TimeExpired(AssertionError):
11     pass
12
13
14 def make_decorator(func):
15     """
16     Wraps a test decorator so as to properly replicate metadata
17     of the decorated function, including nose's additional stuff
18     (namely, setup and teardown).
19     """
20     def decorate(newfunc):
21         if hasattr(func, 'compat_func_name'):
22             name = func.compat_func_name
23         else:
24             name = func.__name__
25         newfunc.__dict__ = func.__dict__
26         newfunc.__doc__ = func.__doc__
27         newfunc.__module__ = func.__module__
28         if not hasattr(newfunc, 'compat_co_firstlineno'):
29             newfunc.compat_co_firstlineno = func.func_code.co_firstlineno
30         try:
31             newfunc.__name__ = name
32         except TypeError:
33             # can't set func name in 2.3
34             newfunc.compat_func_name = name
35         return newfunc
36     return decorate
37
38
39 def raises(*exceptions):
40     """Test must raise one of expected exceptions to pass.
41
42     Example use::
43
44       @raises(TypeError, ValueError)
45       def test_raises_type_error():
46           raise TypeError("This test passes")
47
48       @raises(Exception)
49       def test_that_fails_by_passing():
50           pass
51
52     If you want to test many assertions about exceptions in a single test,
53     you may want to use `assert_raises` instead.
54     """
55     valid = ' or '.join([e.__name__ for e in exceptions])
56     def decorate(func):
57         name = func.__name__
58         def newfunc(*arg, **kw):
59             try:
60                 func(*arg, **kw)
61             except exceptions:
62                 pass
63             except:
64                 raise
65             else:
66                 message = "%s() did not raise %s" % (name, valid)
67                 raise AssertionError(message)
68         newfunc = make_decorator(func)(newfunc)
69         return newfunc
70     return decorate
71
72
73 def set_trace():
74     """Call pdb.set_trace in the calling frame, first restoring
75     sys.stdout to the real output stream. Note that sys.stdout is NOT
76     reset to whatever it was before the call once pdb is done!
77     """
78     import pdb
79     import sys
80     stdout = sys.stdout
81     sys.stdout = sys.__stdout__
82     pdb.Pdb().set_trace(sys._getframe().f_back)
83     
84
85 def timed(limit):
86     """Test must finish within specified time limit to pass.
87
88     Example use::
89
90       @timed(.1)
91       def test_that_fails():
92           time.sleep(.2)
93     """
94     def decorate(func):
95         def newfunc(*arg, **kw):
96             start = time.time()
97             func(*arg, **kw)
98             end = time.time()
99             if end - start > limit:
100                 raise TimeExpired("Time limit (%s) exceeded" % limit)
101         newfunc = make_decorator(func)(newfunc)
102         return newfunc
103     return decorate
104
105
106 def with_setup(setup=None, teardown=None):
107     """Decorator to add setup and/or teardown methods to a test function::
108
109       @with_setup(setup, teardown)
110       def test_something():
111           " ... "
112
113     Note that `with_setup` is useful *only* for test functions, not for test
114     methods or inside of TestCase subclasses.
115     """
116     def decorate(func, setup=setup, teardown=teardown):
117         if setup:
118             if hasattr(func, 'setup'):
119                 _old_s = func.setup
120                 def _s():
121                     setup()
122                     _old_s()
123                 func.setup = _s
124             else:
125                 func.setup = setup
126         if teardown:
127             if hasattr(func, 'teardown'):
128                 _old_t = func.teardown
129                 def _t():
130                     _old_t()
131                     teardown()
132                 func.teardown = _t
133             else:
134                 func.teardown = teardown
135         return func
136     return decorate
137
138
139 def istest(func):
140     """Decorator to mark a function or method as a test
141     """
142     func.__test__ = True
143     return func
144
145
146 def nottest(func):
147     """Decorator to mark a function or method as *not* a test
148     """
149     func.__test__ = False
150     return func