##// END OF EJS Templates
Add optional message to @skip test decorator.
Fernando Perez -
Show More
@@ -1,135 +1,146 b''
1 """Decorators for labeling test objects.
1 """Decorators for labeling test objects.
2
2
3 Decorators that merely return a modified version of the original
3 Decorators that merely return a modified version of the original
4 function object are straightforward. Decorators that return a new
4 function object are straightforward. Decorators that return a new
5 function object need to use
5 function object need to use
6 nose.tools.make_decorator(original_function)(decorator) in returning
6 nose.tools.make_decorator(original_function)(decorator) in returning
7 the decorator, in order to preserve metadata such as function name,
7 the decorator, in order to preserve metadata such as function name,
8 setup and teardown functions and so on - see nose.tools for more
8 setup and teardown functions and so on - see nose.tools for more
9 information.
9 information.
10
10
11 NOTE: This file contains IPython-specific decorators and imports the
11 NOTE: This file contains IPython-specific decorators and imports the
12 numpy.testing.decorators file, which we've copied verbatim. Any of our own
12 numpy.testing.decorators file, which we've copied verbatim. Any of our own
13 code will be added at the bottom if we end up extending this.
13 code will be added at the bottom if we end up extending this.
14 """
14 """
15
15
16 # Stdlib imports
16 # Stdlib imports
17 import inspect
17 import inspect
18
18
19 # Third-party imports
19 # Third-party imports
20
20
21 # This is Michele Simionato's decorator module, also kept verbatim.
21 # This is Michele Simionato's decorator module, also kept verbatim.
22 from decorator_msim import decorator, update_wrapper
22 from decorator_msim import decorator, update_wrapper
23
23
24 # Grab the numpy-specific decorators which we keep in a file that we
24 # Grab the numpy-specific decorators which we keep in a file that we
25 # occasionally update from upstream: decorators_numpy.py is an IDENTICAL copy
25 # occasionally update from upstream: decorators_numpy.py is an IDENTICAL copy
26 # of numpy.testing.decorators.
26 # of numpy.testing.decorators.
27 from decorators_numpy import *
27 from decorators_numpy import *
28
28
29 ##############################################################################
29 ##############################################################################
30 # Local code begins
30 # Local code begins
31
31
32 # Utility functions
32 # Utility functions
33
33
34 def apply_wrapper(wrapper,func):
34 def apply_wrapper(wrapper,func):
35 """Apply a wrapper to a function for decoration.
35 """Apply a wrapper to a function for decoration.
36
36
37 This mixes Michele Simionato's decorator tool with nose's make_decorator,
37 This mixes Michele Simionato's decorator tool with nose's make_decorator,
38 to apply a wrapper in a decorator so that all nose attributes, as well as
38 to apply a wrapper in a decorator so that all nose attributes, as well as
39 function signature and other properties, survive the decoration cleanly.
39 function signature and other properties, survive the decoration cleanly.
40 This will ensure that wrapped functions can still be well introspected via
40 This will ensure that wrapped functions can still be well introspected via
41 IPython, for example.
41 IPython, for example.
42 """
42 """
43 import nose.tools
43 import nose.tools
44
44
45 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
45 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
46
46
47
47
48 def make_label_dec(label,ds=None):
48 def make_label_dec(label,ds=None):
49 """Factory function to create a decorator that applies one or more labels.
49 """Factory function to create a decorator that applies one or more labels.
50
50
51 :Parameters:
51 :Parameters:
52 label : string or sequence
52 label : string or sequence
53 One or more labels that will be applied by the decorator to the functions
53 One or more labels that will be applied by the decorator to the functions
54 it decorates. Labels are attributes of the decorated function with their
54 it decorates. Labels are attributes of the decorated function with their
55 value set to True.
55 value set to True.
56
56
57 :Keywords:
57 :Keywords:
58 ds : string
58 ds : string
59 An optional docstring for the resulting decorator. If not given, a
59 An optional docstring for the resulting decorator. If not given, a
60 default docstring is auto-generated.
60 default docstring is auto-generated.
61
61
62 :Returns:
62 :Returns:
63 A decorator.
63 A decorator.
64
64
65 :Examples:
65 :Examples:
66
66
67 A simple labeling decorator:
67 A simple labeling decorator:
68 >>> slow = make_label_dec('slow')
68 >>> slow = make_label_dec('slow')
69 >>> print slow.__doc__
69 >>> print slow.__doc__
70 Labels a test as 'slow'.
70 Labels a test as 'slow'.
71
71
72 And one that uses multiple labels and a custom docstring:
72 And one that uses multiple labels and a custom docstring:
73 >>> rare = make_label_dec(['slow','hard'],
73 >>> rare = make_label_dec(['slow','hard'],
74 ... "Mix labels 'slow' and 'hard' for rare tests.")
74 ... "Mix labels 'slow' and 'hard' for rare tests.")
75 >>> print rare.__doc__
75 >>> print rare.__doc__
76 Mix labels 'slow' and 'hard' for rare tests.
76 Mix labels 'slow' and 'hard' for rare tests.
77
77
78 Now, let's test using this one:
78 Now, let's test using this one:
79 >>> @rare
79 >>> @rare
80 ... def f(): pass
80 ... def f(): pass
81 ...
81 ...
82 >>>
82 >>>
83 >>> f.slow
83 >>> f.slow
84 True
84 True
85 >>> f.hard
85 >>> f.hard
86 True
86 True
87 """
87 """
88
88
89 if isinstance(label,basestring):
89 if isinstance(label,basestring):
90 labels = [label]
90 labels = [label]
91 else:
91 else:
92 labels = label
92 labels = label
93
93
94 # Validate that the given label(s) are OK for use in setattr() by doing a
94 # Validate that the given label(s) are OK for use in setattr() by doing a
95 # dry run on a dummy function.
95 # dry run on a dummy function.
96 tmp = lambda : None
96 tmp = lambda : None
97 for label in labels:
97 for label in labels:
98 setattr(tmp,label,True)
98 setattr(tmp,label,True)
99
99
100 # This is the actual decorator we'll return
100 # This is the actual decorator we'll return
101 def decor(f):
101 def decor(f):
102 for label in labels:
102 for label in labels:
103 setattr(f,label,True)
103 setattr(f,label,True)
104 return f
104 return f
105
105
106 # Apply the user's docstring, or autogenerate a basic one
106 # Apply the user's docstring, or autogenerate a basic one
107 if ds is None:
107 if ds is None:
108 ds = "Labels a test as %r." % label
108 ds = "Labels a test as %r." % label
109 decor.__doc__ = ds
109 decor.__doc__ = ds
110
110
111 return decor
111 return decor
112
112
113 #-----------------------------------------------------------------------------
113 #-----------------------------------------------------------------------------
114 # Decorators for public use
114 # Decorators for public use
115
115
116 skip_doctest = make_label_dec('skip_doctest',
116 skip_doctest = make_label_dec('skip_doctest',
117 """Decorator - mark a function or method for skipping its doctest.
117 """Decorator - mark a function or method for skipping its doctest.
118
118
119 This decorator allows you to mark a function whose docstring you wish to
119 This decorator allows you to mark a function whose docstring you wish to
120 omit from testing, while preserving the docstring for introspection, help,
120 omit from testing, while preserving the docstring for introspection, help,
121 etc.""")
121 etc.""")
122
122
123
123
124 def skip(func):
124 def skip(func,msg=''):
125 """Decorator - mark a test function for skipping from test suite."""
125 """Decorator - mark a test function for skipping from test suite.
126
127 :Parameters:
128
129 func : function
130 Test function to be skipped
131
132 msg : string
133 Optional message to be added.
134 """
126
135
127 import nose
136 import nose
128
137
129 def wrapper(*a,**k):
138 def wrapper(*a,**k):
130 raise nose.SkipTest("Skipping test for function: %s" %
139 if msg:
131 func.__name__)
140 msg = '\n'+msg
141 raise nose.SkipTest("Skipping test for function: %s%s" %
142 (func.__name__,msg))
132
143
133 return apply_wrapper(wrapper,func)
144 return apply_wrapper(wrapper,func)
134
145
135
146
General Comments 0
You need to be logged in to leave comments. Login now