##// END OF EJS Templates
Fix error in test decorator.
Fernando Perez -
Show More
@@ -1,146 +1,147 b''
1 1 """Decorators for labeling test objects.
2 2
3 3 Decorators that merely return a modified version of the original
4 4 function object are straightforward. Decorators that return a new
5 5 function object need to use
6 6 nose.tools.make_decorator(original_function)(decorator) in returning
7 7 the decorator, in order to preserve metadata such as function name,
8 8 setup and teardown functions and so on - see nose.tools for more
9 9 information.
10 10
11 11 NOTE: This file contains IPython-specific decorators and imports the
12 12 numpy.testing.decorators file, which we've copied verbatim. Any of our own
13 13 code will be added at the bottom if we end up extending this.
14 14 """
15 15
16 16 # Stdlib imports
17 17 import inspect
18 18
19 19 # Third-party imports
20 20
21 21 # This is Michele Simionato's decorator module, also kept verbatim.
22 22 from decorator_msim import decorator, update_wrapper
23 23
24 24 # Grab the numpy-specific decorators which we keep in a file that we
25 25 # occasionally update from upstream: decorators_numpy.py is an IDENTICAL copy
26 26 # of numpy.testing.decorators.
27 27 from decorators_numpy import *
28 28
29 29 ##############################################################################
30 30 # Local code begins
31 31
32 32 # Utility functions
33 33
34 34 def apply_wrapper(wrapper,func):
35 35 """Apply a wrapper to a function for decoration.
36 36
37 37 This mixes Michele Simionato's decorator tool with nose's make_decorator,
38 38 to apply a wrapper in a decorator so that all nose attributes, as well as
39 39 function signature and other properties, survive the decoration cleanly.
40 40 This will ensure that wrapped functions can still be well introspected via
41 41 IPython, for example.
42 42 """
43 43 import nose.tools
44 44
45 45 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
46 46
47 47
48 48 def make_label_dec(label,ds=None):
49 49 """Factory function to create a decorator that applies one or more labels.
50 50
51 51 :Parameters:
52 52 label : string or sequence
53 53 One or more labels that will be applied by the decorator to the functions
54 54 it decorates. Labels are attributes of the decorated function with their
55 55 value set to True.
56 56
57 57 :Keywords:
58 58 ds : string
59 59 An optional docstring for the resulting decorator. If not given, a
60 60 default docstring is auto-generated.
61 61
62 62 :Returns:
63 63 A decorator.
64 64
65 65 :Examples:
66 66
67 67 A simple labeling decorator:
68 68 >>> slow = make_label_dec('slow')
69 69 >>> print slow.__doc__
70 70 Labels a test as 'slow'.
71 71
72 72 And one that uses multiple labels and a custom docstring:
73 73 >>> rare = make_label_dec(['slow','hard'],
74 74 ... "Mix labels 'slow' and 'hard' for rare tests.")
75 75 >>> print rare.__doc__
76 76 Mix labels 'slow' and 'hard' for rare tests.
77 77
78 78 Now, let's test using this one:
79 79 >>> @rare
80 80 ... def f(): pass
81 81 ...
82 82 >>>
83 83 >>> f.slow
84 84 True
85 85 >>> f.hard
86 86 True
87 87 """
88 88
89 89 if isinstance(label,basestring):
90 90 labels = [label]
91 91 else:
92 92 labels = label
93 93
94 94 # Validate that the given label(s) are OK for use in setattr() by doing a
95 95 # dry run on a dummy function.
96 96 tmp = lambda : None
97 97 for label in labels:
98 98 setattr(tmp,label,True)
99 99
100 100 # This is the actual decorator we'll return
101 101 def decor(f):
102 102 for label in labels:
103 103 setattr(f,label,True)
104 104 return f
105 105
106 106 # Apply the user's docstring, or autogenerate a basic one
107 107 if ds is None:
108 108 ds = "Labels a test as %r." % label
109 109 decor.__doc__ = ds
110 110
111 111 return decor
112 112
113 113 #-----------------------------------------------------------------------------
114 114 # Decorators for public use
115 115
116 116 skip_doctest = make_label_dec('skip_doctest',
117 117 """Decorator - mark a function or method for skipping its doctest.
118 118
119 119 This decorator allows you to mark a function whose docstring you wish to
120 120 omit from testing, while preserving the docstring for introspection, help,
121 121 etc.""")
122 122
123
124 def skip(func,msg=''):
123 def skip(msg=''):
125 124 """Decorator - mark a test function for skipping from test suite.
126 125
127 126 :Parameters:
128 127
129 128 func : function
130 129 Test function to be skipped
131 130
132 131 msg : string
133 132 Optional message to be added.
134 133 """
135 134
136 135 import nose
137 136
137 def inner(func):
138
138 139 def wrapper(*a,**k):
139 140 if msg: out = '\n'+msg
140 141 else: out = ''
141 142 raise nose.SkipTest("Skipping test for function: %s%s" %
142 143 (func.__name__,out))
143 144
144 145 return apply_wrapper(wrapper,func)
145 146
146
147 return inner
@@ -1,180 +1,185 b''
1 1 # Module imports
2 2 # Std lib
3 3 import inspect
4 4
5 5 # Third party
6 6
7 7 # Our own
8 8 from IPython.testing import decorators as dec
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Utilities
12 12
13 13 # Note: copied from OInspect, kept here so the testing stuff doesn't create
14 14 # circular dependencies and is easier to reuse.
15 15 def getargspec(obj):
16 16 """Get the names and default values of a function's arguments.
17 17
18 18 A tuple of four things is returned: (args, varargs, varkw, defaults).
19 19 'args' is a list of the argument names (it may contain nested lists).
20 20 'varargs' and 'varkw' are the names of the * and ** arguments or None.
21 21 'defaults' is an n-tuple of the default values of the last n arguments.
22 22
23 23 Modified version of inspect.getargspec from the Python Standard
24 24 Library."""
25 25
26 26 if inspect.isfunction(obj):
27 27 func_obj = obj
28 28 elif inspect.ismethod(obj):
29 29 func_obj = obj.im_func
30 30 else:
31 31 raise TypeError, 'arg is not a Python function'
32 32 args, varargs, varkw = inspect.getargs(func_obj.func_code)
33 33 return args, varargs, varkw, func_obj.func_defaults
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Testing functions
37 37
38 38 def test_trivial():
39 39 """A trivial passing test."""
40 40 pass
41 41
42 42
43 43 @dec.skip
44 44 def test_deliberately_broken():
45 45 """A deliberately broken test - we want to skip this one."""
46 46 1/0
47 47
48 @dec.skip('foo')
49 def test_deliberately_broken2():
50 """Another deliberately broken test - we want to skip this one."""
51 1/0
52
48 53
49 54 # Verify that we can correctly skip the doctest for a function at will, but
50 55 # that the docstring itself is NOT destroyed by the decorator.
51 56 @dec.skip_doctest
52 57 def doctest_bad(x,y=1,**k):
53 58 """A function whose doctest we need to skip.
54 59
55 60 >>> 1+1
56 61 3
57 62 """
58 63 print 'x:',x
59 64 print 'y:',y
60 65 print 'k:',k
61 66
62 67
63 68 def call_doctest_bad():
64 69 """Check that we can still call the decorated functions.
65 70
66 71 >>> doctest_bad(3,y=4)
67 72 x: 3
68 73 y: 4
69 74 k: {}
70 75 """
71 76 pass
72 77
73 78
74 79 # Doctest skipping should work for class methods too
75 80 class foo(object):
76 81 """Foo
77 82
78 83 Example:
79 84
80 85 >>> 1+1
81 86 2
82 87 """
83 88
84 89 @dec.skip_doctest
85 90 def __init__(self,x):
86 91 """Make a foo.
87 92
88 93 Example:
89 94
90 95 >>> f = foo(3)
91 96 junk
92 97 """
93 98 print 'Making a foo.'
94 99 self.x = x
95 100
96 101 @dec.skip_doctest
97 102 def bar(self,y):
98 103 """Example:
99 104
100 105 >>> f = foo(3)
101 106 >>> f.bar(0)
102 107 boom!
103 108 >>> 1/0
104 109 bam!
105 110 """
106 111 return 1/y
107 112
108 113 def baz(self,y):
109 114 """Example:
110 115
111 116 >>> f = foo(3)
112 117 Making a foo.
113 118 >>> f.baz(3)
114 119 True
115 120 """
116 121 return self.x==y
117 122
118 123
119 124 def test_skip_dt_decorator():
120 125 """Doctest-skipping decorator should preserve the docstring.
121 126 """
122 127 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
123 128 check = """A function whose doctest we need to skip.
124 129
125 130 >>> 1+1
126 131 3
127 132 """
128 133 # Fetch the docstring from doctest_bad after decoration.
129 134 val = doctest_bad.__doc__
130 135
131 136 assert check==val,"doctest_bad docstrings don't match"
132 137
133 138
134 139 def test_skip_dt_decorator2():
135 140 """Doctest-skipping decorator should preserve function signature.
136 141 """
137 142 # Hardcoded correct answer
138 143 dtargs = (['x', 'y'], None, 'k', (1,))
139 144 # Introspect out the value
140 145 dtargsr = getargspec(doctest_bad)
141 146 assert dtargsr==dtargs, \
142 147 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
143 148
144 149
145 150 def doctest_run():
146 151 """Test running a trivial script.
147 152
148 153 In [13]: run simplevars.py
149 154 x is: 1
150 155 """
151 156
152 157 #@dec.skip_doctest
153 158 def doctest_runvars():
154 159 """Test that variables defined in scripts get loaded correcly via %run.
155 160
156 161 In [13]: run simplevars.py
157 162 x is: 1
158 163
159 164 In [14]: x
160 165 Out[14]: 1
161 166 """
162 167
163 168 def doctest_ivars():
164 169 """Test that variables defined interactively are picked up.
165 170 In [5]: zz=1
166 171
167 172 In [6]: zz
168 173 Out[6]: 1
169 174 """
170 175
171 176 @dec.skip_doctest
172 177 def doctest_refs():
173 178 """DocTest reference holding issues when running scripts.
174 179
175 180 In [32]: run show_refs.py
176 181 c referrers: [<type 'dict'>]
177 182
178 183 In [33]: map(type,gc.get_referrers(c))
179 184 Out[33]: [<type 'dict'>]
180 185 """
General Comments 0
You need to be logged in to leave comments. Login now