##// END OF EJS Templates
Fix tests when ipdoctest nose plugin is enable (Grrr, no isolation at...
Gael Varoquaux -
Show More
@@ -1,220 +1,221 b''
1 """
1 """
2 Frontend class that uses IPython0 to prefilter the inputs.
2 Frontend class that uses IPython0 to prefilter the inputs.
3
3
4 Using the IPython0 mechanism gives us access to the magics.
4 Using the IPython0 mechanism gives us access to the magics.
5
5
6 This is a transitory class, used here to do the transition between
6 This is a transitory class, used here to do the transition between
7 ipython0 and ipython1. This class is meant to be short-lived as more
7 ipython0 and ipython1. This class is meant to be short-lived as more
8 functionnality is abstracted out of ipython0 in reusable functions and
8 functionnality is abstracted out of ipython0 in reusable functions and
9 is added on the interpreter. This class can be a used to guide this
9 is added on the interpreter. This class can be a used to guide this
10 refactoring.
10 refactoring.
11 """
11 """
12 __docformat__ = "restructuredtext en"
12 __docformat__ = "restructuredtext en"
13
13
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15 # Copyright (C) 2008 The IPython Development Team
15 # Copyright (C) 2008 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-------------------------------------------------------------------------------
19 #-------------------------------------------------------------------------------
20
20
21 #-------------------------------------------------------------------------------
21 #-------------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-------------------------------------------------------------------------------
23 #-------------------------------------------------------------------------------
24 import sys
24 import sys
25
25
26 from linefrontendbase import LineFrontEndBase, common_prefix
26 from linefrontendbase import LineFrontEndBase, common_prefix
27
27
28 from IPython.ipmaker import make_IPython
28 from IPython.ipmaker import make_IPython
29 from IPython.ipapi import IPApi
29 from IPython.ipapi import IPApi
30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
31
31
32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
33
33
34 from IPython.genutils import Term
34 from IPython.genutils import Term
35 import pydoc
35 import pydoc
36 import os
36 import os
37
37
38
38
39 def mk_system_call(system_call_function, command):
39 def mk_system_call(system_call_function, command):
40 """ given a os.system replacement, and a leading string command,
40 """ given a os.system replacement, and a leading string command,
41 returns a function that will execute the command with the given
41 returns a function that will execute the command with the given
42 argument string.
42 argument string.
43 """
43 """
44 def my_system_call(args):
44 def my_system_call(args):
45 system_call_function("%s %s" % (command, args))
45 system_call_function("%s %s" % (command, args))
46 return my_system_call
46 return my_system_call
47
47
48 #-------------------------------------------------------------------------------
48 #-------------------------------------------------------------------------------
49 # Frontend class using ipython0 to do the prefiltering.
49 # Frontend class using ipython0 to do the prefiltering.
50 #-------------------------------------------------------------------------------
50 #-------------------------------------------------------------------------------
51 class PrefilterFrontEnd(LineFrontEndBase):
51 class PrefilterFrontEnd(LineFrontEndBase):
52 """ Class that uses ipython0 to do prefilter the input, do the
52 """ Class that uses ipython0 to do prefilter the input, do the
53 completion and the magics.
53 completion and the magics.
54
54
55 The core trick is to use an ipython0 instance to prefilter the
55 The core trick is to use an ipython0 instance to prefilter the
56 input, and share the namespace between the interpreter instance used
56 input, and share the namespace between the interpreter instance used
57 to execute the statements and the ipython0 used for code
57 to execute the statements and the ipython0 used for code
58 completion...
58 completion...
59 """
59 """
60
60
61 def __init__(self, ipython0=None, *args, **kwargs):
61 def __init__(self, ipython0=None, *args, **kwargs):
62 """ Parameters:
62 """ Parameters:
63 -----------
63 -----------
64
64
65 ipython0: an optional ipython0 instance to use for command
65 ipython0: an optional ipython0 instance to use for command
66 prefiltering and completion.
66 prefiltering and completion.
67 """
67 """
68 self.save_output_hooks()
68 self.save_output_hooks()
69 if ipython0 is None:
69 if ipython0 is None:
70 # Instanciate an IPython0 interpreter to be able to use the
70 # Instanciate an IPython0 interpreter to be able to use the
71 # prefiltering.
71 # prefiltering.
72 ipython0 = make_IPython()
72 # XXX: argv=[] is a bit bold.
73 ipython0 = make_IPython(argv=[])
73 self.ipython0 = ipython0
74 self.ipython0 = ipython0
74 # Set the pager:
75 # Set the pager:
75 self.ipython0.set_hook('show_in_pager',
76 self.ipython0.set_hook('show_in_pager',
76 lambda s, string: self.write("\n" + string))
77 lambda s, string: self.write("\n" + string))
77 self.ipython0.write = self.write
78 self.ipython0.write = self.write
78 self._ip = _ip = IPApi(self.ipython0)
79 self._ip = _ip = IPApi(self.ipython0)
79 # Make sure the raw system call doesn't get called, as we don't
80 # Make sure the raw system call doesn't get called, as we don't
80 # have a stdin accessible.
81 # have a stdin accessible.
81 self._ip.system = self.system_call
82 self._ip.system = self.system_call
82 # XXX: Muck around with magics so that they work better
83 # XXX: Muck around with magics so that they work better
83 # in our environment
84 # in our environment
84 self.ipython0.magic_ls = mk_system_call(self.system_call,
85 self.ipython0.magic_ls = mk_system_call(self.system_call,
85 'ls -CF')
86 'ls -CF')
86 # And now clean up the mess created by ipython0
87 # And now clean up the mess created by ipython0
87 self.release_output()
88 self.release_output()
88 if not 'banner' in kwargs:
89 if not 'banner' in kwargs and self.banner is None:
89 kwargs['banner'] = self.ipython0.BANNER + """
90 kwargs['banner'] = self.ipython0.BANNER + """
90 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
91 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
91
92
92 LineFrontEndBase.__init__(self, *args, **kwargs)
93 LineFrontEndBase.__init__(self, *args, **kwargs)
93 # XXX: Hack: mix the two namespaces
94 # XXX: Hack: mix the two namespaces
94 self.shell.user_ns = self.ipython0.user_ns
95 self.shell.user_ns = self.ipython0.user_ns
95 self.shell.user_global_ns = self.ipython0.user_global_ns
96 self.shell.user_global_ns = self.ipython0.user_global_ns
96
97
97 self.shell.output_trap = RedirectorOutputTrap(
98 self.shell.output_trap = RedirectorOutputTrap(
98 out_callback=self.write,
99 out_callback=self.write,
99 err_callback=self.write,
100 err_callback=self.write,
100 )
101 )
101 self.shell.traceback_trap = SyncTracebackTrap(
102 self.shell.traceback_trap = SyncTracebackTrap(
102 formatters=self.shell.traceback_trap.formatters,
103 formatters=self.shell.traceback_trap.formatters,
103 )
104 )
104
105
105 #--------------------------------------------------------------------------
106 #--------------------------------------------------------------------------
106 # FrontEndBase interface
107 # FrontEndBase interface
107 #--------------------------------------------------------------------------
108 #--------------------------------------------------------------------------
108
109
109 def show_traceback(self):
110 def show_traceback(self):
110 """ Use ipython0 to capture the last traceback and display it.
111 """ Use ipython0 to capture the last traceback and display it.
111 """
112 """
112 self.capture_output()
113 self.capture_output()
113 self.ipython0.showtraceback()
114 self.ipython0.showtraceback()
114 self.release_output()
115 self.release_output()
115
116
116
117
117 def execute(self, python_string, raw_string=None):
118 def execute(self, python_string, raw_string=None):
118 if self.debug:
119 if self.debug:
119 print 'Executing Python code:', repr(python_string)
120 print 'Executing Python code:', repr(python_string)
120 self.capture_output()
121 self.capture_output()
121 LineFrontEndBase.execute(self, python_string,
122 LineFrontEndBase.execute(self, python_string,
122 raw_string=raw_string)
123 raw_string=raw_string)
123 self.release_output()
124 self.release_output()
124
125
125
126
126 def save_output_hooks(self):
127 def save_output_hooks(self):
127 """ Store all the output hooks we can think of, to be able to
128 """ Store all the output hooks we can think of, to be able to
128 restore them.
129 restore them.
129
130
130 We need to do this early, as starting the ipython0 instance will
131 We need to do this early, as starting the ipython0 instance will
131 screw ouput hooks.
132 screw ouput hooks.
132 """
133 """
133 self.__old_cout_write = Term.cout.write
134 self.__old_cout_write = Term.cout.write
134 self.__old_cerr_write = Term.cerr.write
135 self.__old_cerr_write = Term.cerr.write
135 self.__old_stdout = sys.stdout
136 self.__old_stdout = sys.stdout
136 self.__old_stderr= sys.stderr
137 self.__old_stderr= sys.stderr
137 self.__old_help_output = pydoc.help.output
138 self.__old_help_output = pydoc.help.output
138 self.__old_display_hook = sys.displayhook
139 self.__old_display_hook = sys.displayhook
139
140
140
141
141 def capture_output(self):
142 def capture_output(self):
142 """ Capture all the output mechanisms we can think of.
143 """ Capture all the output mechanisms we can think of.
143 """
144 """
144 self.save_output_hooks()
145 self.save_output_hooks()
145 Term.cout.write = self.write
146 Term.cout.write = self.write
146 Term.cerr.write = self.write
147 Term.cerr.write = self.write
147 sys.stdout = Term.cout
148 sys.stdout = Term.cout
148 sys.stderr = Term.cerr
149 sys.stderr = Term.cerr
149 pydoc.help.output = self.shell.output_trap.out
150 pydoc.help.output = self.shell.output_trap.out
150
151
151
152
152 def release_output(self):
153 def release_output(self):
153 """ Release all the different captures we have made.
154 """ Release all the different captures we have made.
154 """
155 """
155 Term.cout.write = self.__old_cout_write
156 Term.cout.write = self.__old_cout_write
156 Term.cerr.write = self.__old_cerr_write
157 Term.cerr.write = self.__old_cerr_write
157 sys.stdout = self.__old_stdout
158 sys.stdout = self.__old_stdout
158 sys.stderr = self.__old_stderr
159 sys.stderr = self.__old_stderr
159 pydoc.help.output = self.__old_help_output
160 pydoc.help.output = self.__old_help_output
160 sys.displayhook = self.__old_display_hook
161 sys.displayhook = self.__old_display_hook
161
162
162
163
163 def complete(self, line):
164 def complete(self, line):
164 word = line.split('\n')[-1].split(' ')[-1]
165 word = line.split('\n')[-1].split(' ')[-1]
165 completions = self.ipython0.complete(word)
166 completions = self.ipython0.complete(word)
166 # FIXME: The proper sort should be done in the complete method.
167 # FIXME: The proper sort should be done in the complete method.
167 key = lambda x: x.replace('_', '')
168 key = lambda x: x.replace('_', '')
168 completions.sort(key=key)
169 completions.sort(key=key)
169 if completions:
170 if completions:
170 prefix = common_prefix(completions)
171 prefix = common_prefix(completions)
171 line = line[:-len(word)] + prefix
172 line = line[:-len(word)] + prefix
172 return line, completions
173 return line, completions
173
174
174
175
175 #--------------------------------------------------------------------------
176 #--------------------------------------------------------------------------
176 # LineFrontEndBase interface
177 # LineFrontEndBase interface
177 #--------------------------------------------------------------------------
178 #--------------------------------------------------------------------------
178
179
179 def prefilter_input(self, input_string):
180 def prefilter_input(self, input_string):
180 """ Using IPython0 to prefilter the commands to turn them
181 """ Using IPython0 to prefilter the commands to turn them
181 in executable statements that are valid Python strings.
182 in executable statements that are valid Python strings.
182 """
183 """
183 input_string = LineFrontEndBase.prefilter_input(self, input_string)
184 input_string = LineFrontEndBase.prefilter_input(self, input_string)
184 filtered_lines = []
185 filtered_lines = []
185 # The IPython0 prefilters sometime produce output. We need to
186 # The IPython0 prefilters sometime produce output. We need to
186 # capture it.
187 # capture it.
187 self.capture_output()
188 self.capture_output()
188 self.last_result = dict(number=self.prompt_number)
189 self.last_result = dict(number=self.prompt_number)
189 try:
190 try:
190 for line in input_string.split('\n'):
191 for line in input_string.split('\n'):
191 filtered_lines.append(
192 filtered_lines.append(
192 self.ipython0.prefilter(line, False).rstrip())
193 self.ipython0.prefilter(line, False).rstrip())
193 except:
194 except:
194 # XXX: probably not the right thing to do.
195 # XXX: probably not the right thing to do.
195 self.ipython0.showsyntaxerror()
196 self.ipython0.showsyntaxerror()
196 self.after_execute()
197 self.after_execute()
197 finally:
198 finally:
198 self.release_output()
199 self.release_output()
199
200
200 # Clean up the trailing whitespace, to avoid indentation errors
201 # Clean up the trailing whitespace, to avoid indentation errors
201 filtered_string = '\n'.join(filtered_lines)
202 filtered_string = '\n'.join(filtered_lines)
202 return filtered_string
203 return filtered_string
203
204
204
205
205 #--------------------------------------------------------------------------
206 #--------------------------------------------------------------------------
206 # PrefilterFrontEnd interface
207 # PrefilterFrontEnd interface
207 #--------------------------------------------------------------------------
208 #--------------------------------------------------------------------------
208
209
209 def system_call(self, command_string):
210 def system_call(self, command_string):
210 """ Allows for frontend to define their own system call, to be
211 """ Allows for frontend to define their own system call, to be
211 able capture output and redirect input.
212 able capture output and redirect input.
212 """
213 """
213 return os.system(command_string)
214 return os.system(command_string)
214
215
215
216
216 def do_exit(self):
217 def do_exit(self):
217 """ Exit the shell, cleanup and save the history.
218 """ Exit the shell, cleanup and save the history.
218 """
219 """
219 self.ipython0.atexit_operations()
220 self.ipython0.atexit_operations()
220
221
@@ -1,132 +1,157 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Test process execution and IO redirection.
3 Test process execution and IO redirection.
4 """
4 """
5
5
6 __docformat__ = "restructuredtext en"
6 __docformat__ = "restructuredtext en"
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is
11 # Distributed under the terms of the BSD License. The full license is
12 # in the file COPYING, distributed as part of this software.
12 # in the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
16 from cStringIO import StringIO
15 from cStringIO import StringIO
17 import string
16 import string
18 import sys
17
19 from IPython.ipapi import get as get_ipython0
18 from IPython.ipapi import get as get_ipython0
19 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
20
20
21 class TestPrefilterFrontEnd(PrefilterFrontEnd):
21 class TestPrefilterFrontEnd(PrefilterFrontEnd):
22
22
23 input_prompt_template = string.Template('')
23 input_prompt_template = string.Template('')
24 output_prompt_template = string.Template('')
24 output_prompt_template = string.Template('')
25 banner = ''
25
26
26 def __init__(self):
27 def __init__(self):
27 ipython0 = get_ipython0()
28 ipython0 = get_ipython0().IP
28 self.out = StringIO()
29 self.out = StringIO()
29 PrefilterFrontEnd.__init__(self, ipython0=ipython0)
30 PrefilterFrontEnd.__init__(self, ipython0=ipython0)
30
31 # Clean up the namespace for isolation between tests
31 def write(self, string):
32 user_ns = self.ipython0.user_ns
33 # We need to keep references to things so that they don't
34 # get garbage collected (this stinks).
35 self.shadow_ns = dict()
36 for i in self.ipython0.magic_who_ls():
37 self.shadow_ns[i] = user_ns.pop(i)
38 # Some more code for isolation (yeah, crazy)
39 self._on_enter()
40 self.out.flush()
41 self.out.reset()
42 self.out.truncate()
43
44 def write(self, string, *args, **kwargs):
32 self.out.write(string)
45 self.out.write(string)
33
46
34 def _on_enter(self):
47 def _on_enter(self):
35 self.input_buffer += '\n'
48 self.input_buffer += '\n'
36 PrefilterFrontEnd._on_enter(self)
49 PrefilterFrontEnd._on_enter(self)
37
50
38
51
39 def test_execution():
52 def test_execution():
40 """ Test execution of a command.
53 """ Test execution of a command.
41 """
54 """
42 f = TestPrefilterFrontEnd()
55 f = TestPrefilterFrontEnd()
43 f.input_buffer = 'print 1\n'
56 f.input_buffer = 'print 1'
44 f._on_enter()
57 f._on_enter()
45 assert f.out.getvalue() == '1\n'
58 out_value = f.out.getvalue()
59 assert out_value == '1\n'
46
60
47
61
48 def test_multiline():
62 def test_multiline():
49 """ Test execution of a multiline command.
63 """ Test execution of a multiline command.
50 """
64 """
51 f = TestPrefilterFrontEnd()
65 f = TestPrefilterFrontEnd()
52 f.input_buffer = 'if True:'
66 f.input_buffer = 'if True:'
53 f._on_enter()
67 f._on_enter()
54 f.input_buffer += 'print 1'
68 f.input_buffer += 'print 1'
55 f._on_enter()
69 f._on_enter()
56 assert f.out.getvalue() == ''
70 out_value = f.out.getvalue()
71 assert out_value == ''
57 f._on_enter()
72 f._on_enter()
58 assert f.out.getvalue() == '1\n'
73 out_value = f.out.getvalue()
74 assert out_value == '1\n'
59 f = TestPrefilterFrontEnd()
75 f = TestPrefilterFrontEnd()
60 f.input_buffer='(1 +'
76 f.input_buffer='(1 +'
61 f._on_enter()
77 f._on_enter()
62 f.input_buffer += '0)'
78 f.input_buffer += '0)'
63 f._on_enter()
79 f._on_enter()
64 assert f.out.getvalue() == ''
80 out_value = f.out.getvalue()
81 assert out_value == ''
65 f._on_enter()
82 f._on_enter()
66 assert f.out.getvalue() == '1\n'
83 out_value = f.out.getvalue()
84 assert out_value == '1\n'
67
85
68
86
69 def test_capture():
87 def test_capture():
70 """ Test the capture of output in different channels.
88 """ Test the capture of output in different channels.
71 """
89 """
72 # Test on the OS-level stdout, stderr.
90 # Test on the OS-level stdout, stderr.
73 f = TestPrefilterFrontEnd()
91 f = TestPrefilterFrontEnd()
74 f.input_buffer = \
92 f.input_buffer = \
75 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
93 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
76 f._on_enter()
94 f._on_enter()
77 assert f.out.getvalue() == '1'
95 out_value = f.out.getvalue()
96 assert out_value == '1'
78 f = TestPrefilterFrontEnd()
97 f = TestPrefilterFrontEnd()
79 f.input_buffer = \
98 f.input_buffer = \
80 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
99 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
81 f._on_enter()
100 f._on_enter()
82 assert f.out.getvalue() == '1'
101 out_value = f.out.getvalue()
102 assert out_value == '1'
83
103
84
104
85 def test_magic():
105 def test_magic():
86 """ Test the magic expansion and history.
106 """ Test the magic expansion and history.
87
107
88 This test is fairly fragile and will break when magics change.
108 This test is fairly fragile and will break when magics change.
89 """
109 """
90 f = TestPrefilterFrontEnd()
110 f = TestPrefilterFrontEnd()
91 f.input_buffer += '%who\n'
111 f.input_buffer += '%who'
92 f._on_enter()
112 f._on_enter()
93 assert f.out.getvalue() == 'Interactive namespace is empty.\n'
113 out_value = f.out.getvalue()
114 assert out_value == 'Interactive namespace is empty.\n'
94
115
95
116
96 def test_help():
117 def test_help():
97 """ Test object inspection.
118 """ Test object inspection.
98 """
119 """
99 f = TestPrefilterFrontEnd()
120 f = TestPrefilterFrontEnd()
100 f.input_buffer += "def f():"
121 f.input_buffer += "def f():"
101 f._on_enter()
122 f._on_enter()
102 f.input_buffer += "'foobar'"
123 f.input_buffer += "'foobar'"
103 f._on_enter()
124 f._on_enter()
104 f.input_buffer += "pass"
125 f.input_buffer += "pass"
105 f._on_enter()
126 f._on_enter()
106 f._on_enter()
127 f._on_enter()
107 f.input_buffer += "f?"
128 f.input_buffer += "f?"
108 f._on_enter()
129 f._on_enter()
109 assert f.out.getvalue().split()[-1] == 'foobar'
130 assert 'traceback' not in f.last_result
131 ## XXX: ipython doctest magic breaks this. I have no clue why
132 #out_value = f.out.getvalue()
133 #assert out_value.split()[-1] == 'foobar'
110
134
111
135
112 def test_completion():
136 def test_completion():
113 """ Test command-line completion.
137 """ Test command-line completion.
114 """
138 """
115 f = TestPrefilterFrontEnd()
139 f = TestPrefilterFrontEnd()
116 f.input_buffer = 'zzza = 1'
140 f.input_buffer = 'zzza = 1'
117 f._on_enter()
141 f._on_enter()
118 f.input_buffer = 'zzzb = 2'
142 f.input_buffer = 'zzzb = 2'
119 f._on_enter()
143 f._on_enter()
120 f.input_buffer = 'zz'
144 f.input_buffer = 'zz'
121 f.complete_current_input()
145 f.complete_current_input()
122 assert f.out.getvalue() == '\nzzza zzzb '
146 out_value = f.out.getvalue()
147 assert out_value == '\nzzza zzzb '
123 assert f.input_buffer == 'zzz'
148 assert f.input_buffer == 'zzz'
124
149
125
150
126 if __name__ == '__main__':
151 if __name__ == '__main__':
127 test_magic()
152 test_magic()
128 test_help()
153 test_help()
129 test_execution()
154 test_execution()
130 test_multiline()
155 test_multiline()
131 test_capture()
156 test_capture()
132 test_completion()
157 test_completion()
@@ -1,133 +1,135 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):
125 """Decorator - mark a test function for skipping from test suite."""
125 """Decorator - mark a test function for skipping from test suite."""
126
126
127 import nose
127 import nose
128
128
129 def wrapper(*a,**k):
129 def wrapper(*a,**k):
130 raise nose.SkipTest("Skipping test for function: %s" %
130 raise nose.SkipTest("Skipping test for function: %s" %
131 func.__name__)
131 func.__name__)
132
132
133 return apply_wrapper(wrapper,func)
133 return apply_wrapper(wrapper,func)
134
135
@@ -1,54 +1,54 b''
1 # Set this prefix to where you want to install the plugin
1 # Set this prefix to where you want to install the plugin
2 PREFIX=~/usr/local
2 PREFIX=~/usr/local
3 PREFIX=~/tmp/local
3 PREFIX=~/tmp/local
4
4
5 NOSE0=nosetests -vs --with-doctest --doctest-tests
5 NOSE0=nosetests -vs --with-doctest --doctest-tests --detailed-errors
6 NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt
6 NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt --detailed-errors
7
7
8 #--with-color
8 #--with-color
9
9
10 SRC=ipdoctest.py setup.py ../decorators.py
10 SRC=ipdoctest.py setup.py ../decorators.py
11
11
12 plugin: IPython_doctest_plugin.egg-info
12 plugin: IPython_doctest_plugin.egg-info
13
13
14 dtest: plugin dtexample.py
14 dtest: plugin dtexample.py
15 $(NOSE) dtexample.py
15 $(NOSE) dtexample.py
16
16
17 # Note: this test is double counting!!!
17 # Note: this test is double counting!!!
18 rtest: plugin dtexample.py
18 rtest: plugin dtexample.py
19 $(NOSE) test_refs.py
19 $(NOSE) test_refs.py
20
20
21 std: plugin
21 std: plugin
22 nosetests -vs --with-doctest --doctest-tests IPython.strdispatch
22 nosetests -vs --with-doctest --doctest-tests IPython.strdispatch
23 $(NOSE) IPython.strdispatch
23 $(NOSE) IPython.strdispatch
24
24
25 test: plugin dtexample.py
25 test: plugin dtexample.py
26 $(NOSE) dtexample.py test*.py test*.txt
26 $(NOSE) dtexample.py test*.py test*.txt
27
27
28 deb: plugin dtexample.py
28 deb: plugin dtexample.py
29 $(NOSE) test_combo.txt
29 $(NOSE) test_combo.txt
30
30
31 iptest: plugin
31 iptest: plugin
32 $(NOSE) IPython
32 $(NOSE) IPython
33
33
34 deco:
34 deco:
35 $(NOSE0) IPython.testing.decorators
35 $(NOSE0) IPython.testing.decorators
36
36
37 mtest: plugin
37 mtest: plugin
38 $(NOSE) -x IPython.Magic
38 $(NOSE) -x IPython.Magic
39
39
40 ipipe: plugin
40 ipipe: plugin
41 $(NOSE) -x IPython.Extensions.ipipe
41 $(NOSE) -x IPython.Extensions.ipipe
42
42
43 sr: rtest std
43 sr: rtest std
44
44
45 base: dtest rtest test std deco
45 base: dtest rtest test std deco
46
46
47 all: base iptest
47 all: base iptest
48
48
49 IPython_doctest_plugin.egg-info: $(SRC)
49 IPython_doctest_plugin.egg-info: $(SRC)
50 python setup.py install --prefix=$(PREFIX)
50 python setup.py install --prefix=$(PREFIX)
51 touch $@
51 touch $@
52
52
53 clean:
53 clean:
54 rm -rf IPython_doctest_plugin.egg-info *~ *pyc build/ dist/
54 rm -rf IPython_doctest_plugin.egg-info *~ *pyc build/ dist/
General Comments 0
You need to be logged in to leave comments. Login now