##// END OF EJS Templates
Make default argv for testing instances....
Fernando Perez -
Show More
@@ -1,875 +1,889 b''
1 """Nose Plugin that supports IPython doctests.
1 """Nose Plugin that supports IPython doctests.
2
2
3 Limitations:
3 Limitations:
4
4
5 - When generating examples for use as doctests, make sure that you have
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by starting ipython with the
6 pretty-printing OFF. This can be done either by starting ipython with the
7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
8 interactively disabling it with %Pprint. This is required so that IPython
8 interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
10 execution.
11
11
12 - Do not rely on specific prompt numbers for results (such as using
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
15 won't even have these special _NN variables set at all.
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Module imports
19 # Module imports
20
20
21 # From the standard library
21 # From the standard library
22 import __builtin__
22 import __builtin__
23 import commands
23 import commands
24 import doctest
24 import doctest
25 import inspect
25 import inspect
26 import logging
26 import logging
27 import os
27 import os
28 import re
28 import re
29 import sys
29 import sys
30 import traceback
30 import traceback
31 import unittest
31 import unittest
32
32
33 from inspect import getmodule
33 from inspect import getmodule
34 from StringIO import StringIO
34 from StringIO import StringIO
35
35
36 # We are overriding the default doctest runner, so we need to import a few
36 # We are overriding the default doctest runner, so we need to import a few
37 # things from doctest directly
37 # things from doctest directly
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
39 _unittest_reportflags, DocTestRunner,
39 _unittest_reportflags, DocTestRunner,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
41 _exception_traceback,
41 _exception_traceback,
42 linecache)
42 linecache)
43
43
44 # Third-party modules
44 # Third-party modules
45 import nose.core
45 import nose.core
46
46
47 from nose.plugins import doctests, Plugin
47 from nose.plugins import doctests, Plugin
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Module globals and other constants
51 # Module globals and other constants
52
52
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55 ###########################################################################
55 ###########################################################################
56 # *** HACK ***
56 # *** HACK ***
57 # We must start our own ipython object and heavily muck with it so that all the
57 # We must start our own ipython object and heavily muck with it so that all the
58 # modifications IPython makes to system behavior don't send the doctest
58 # modifications IPython makes to system behavior don't send the doctest
59 # machinery into a fit. This code should be considered a gross hack, but it
59 # machinery into a fit. This code should be considered a gross hack, but it
60 # gets the job done.
60 # gets the job done.
61
61
62 def default_argv():
63 """Return a valid default argv for creating testing instances of ipython"""
64
65 # Get the install directory for the user configuration and tell ipython to
66 # use the default profile from there.
67 from IPython import UserConfig
68 ipcdir = os.path.dirname(UserConfig.__file__)
69 #ipconf = os.path.join(ipcdir,'ipy_user_conf.py')
70 ipconf = os.path.join(ipcdir,'ipythonrc')
71 #print 'conf:',ipconf # dbg
72
73 return ['--colors=NoColor','--noterm_title','-rcfile=%s' % ipconf]
74
62
75
63 # Hack to modify the %run command so we can sync the user's namespace with the
76 # Hack to modify the %run command so we can sync the user's namespace with the
64 # test globals. Once we move over to a clean magic system, this will be done
77 # test globals. Once we move over to a clean magic system, this will be done
65 # with much less ugliness.
78 # with much less ugliness.
66
79
67 class py_file_finder(object):
80 class py_file_finder(object):
68 def __init__(self,test_filename):
81 def __init__(self,test_filename):
69 self.test_filename = test_filename
82 self.test_filename = test_filename
70
83
71 def __call__(self,name):
84 def __call__(self,name):
72 from IPython.genutils import get_py_filename
85 from IPython.genutils import get_py_filename
73 try:
86 try:
74 return get_py_filename(name)
87 return get_py_filename(name)
75 except IOError:
88 except IOError:
76 test_dir = os.path.dirname(self.test_filename)
89 test_dir = os.path.dirname(self.test_filename)
77 new_path = os.path.join(test_dir,name)
90 new_path = os.path.join(test_dir,name)
78 return get_py_filename(new_path)
91 return get_py_filename(new_path)
79
92
80
93
81 def _run_ns_sync(self,arg_s,runner=None):
94 def _run_ns_sync(self,arg_s,runner=None):
82 """Modified version of %run that syncs testing namespaces.
95 """Modified version of %run that syncs testing namespaces.
83
96
84 This is strictly needed for running doctests that call %run.
97 This is strictly needed for running doctests that call %run.
85 """
98 """
86
99
87 finder = py_file_finder(_run_ns_sync.test_filename)
100 finder = py_file_finder(_run_ns_sync.test_filename)
88 out = _ip.IP.magic_run_ori(arg_s,runner,finder)
101 out = _ip.IP.magic_run_ori(arg_s,runner,finder)
89 _run_ns_sync.test_globs.update(_ip.user_ns)
102 _run_ns_sync.test_globs.update(_ip.user_ns)
90 return out
103 return out
91
104
92
105
93 class ipnsdict(dict):
106 class ipnsdict(dict):
94 """A special subclass of dict for use as an IPython namespace in doctests.
107 """A special subclass of dict for use as an IPython namespace in doctests.
95
108
96 This subclass adds a simple checkpointing capability so that when testing
109 This subclass adds a simple checkpointing capability so that when testing
97 machinery clears it (we use it as the test execution context), it doesn't
110 machinery clears it (we use it as the test execution context), it doesn't
98 get completely destroyed.
111 get completely destroyed.
99 """
112 """
100
113
101 def __init__(self,*a):
114 def __init__(self,*a):
102 dict.__init__(self,*a)
115 dict.__init__(self,*a)
103 self._savedict = {}
116 self._savedict = {}
104
117
105 def clear(self):
118 def clear(self):
106 dict.clear(self)
119 dict.clear(self)
107 self.update(self._savedict)
120 self.update(self._savedict)
108
121
109 def _checkpoint(self):
122 def _checkpoint(self):
110 self._savedict.clear()
123 self._savedict.clear()
111 self._savedict.update(self)
124 self._savedict.update(self)
112
125
113 def update(self,other):
126 def update(self,other):
114 self._checkpoint()
127 self._checkpoint()
115 dict.update(self,other)
128 dict.update(self,other)
116 # If '_' is in the namespace, python won't set it when executing code,
129 # If '_' is in the namespace, python won't set it when executing code,
117 # and we have examples that test it. So we ensure that the namespace
130 # and we have examples that test it. So we ensure that the namespace
118 # is always 'clean' of it before it's used for test code execution.
131 # is always 'clean' of it before it's used for test code execution.
119 self.pop('_',None)
132 self.pop('_',None)
120
133
121
134
122 def start_ipython():
135 def start_ipython():
123 """Start a global IPython shell, which we need for IPython-specific syntax.
136 """Start a global IPython shell, which we need for IPython-specific syntax.
124 """
137 """
125
138
126 # This function should only ever run once!
139 # This function should only ever run once!
127 if hasattr(start_ipython,'already_called'):
140 if hasattr(start_ipython,'already_called'):
128 return
141 return
129 start_ipython.already_called = True
142 start_ipython.already_called = True
130
143
131 # Ok, first time we're called, go ahead
144 # Ok, first time we're called, go ahead
132 import new
145 import new
133
146
134 import IPython
147 import IPython
135
148
136 def xsys(cmd):
149 def xsys(cmd):
137 """Execute a command and print its output.
150 """Execute a command and print its output.
138
151
139 This is just a convenience function to replace the IPython system call
152 This is just a convenience function to replace the IPython system call
140 with one that is more doctest-friendly.
153 with one that is more doctest-friendly.
141 """
154 """
142 cmd = _ip.IP.var_expand(cmd,depth=1)
155 cmd = _ip.IP.var_expand(cmd,depth=1)
143 sys.stdout.write(commands.getoutput(cmd))
156 sys.stdout.write(commands.getoutput(cmd))
144 sys.stdout.flush()
157 sys.stdout.flush()
145
158
146 # Store certain global objects that IPython modifies
159 # Store certain global objects that IPython modifies
147 _displayhook = sys.displayhook
160 _displayhook = sys.displayhook
148 _excepthook = sys.excepthook
161 _excepthook = sys.excepthook
149 _main = sys.modules.get('__main__')
162 _main = sys.modules.get('__main__')
150
163
164 argv = default_argv()
165
151 # Start IPython instance. We customize it to start with minimal frills.
166 # Start IPython instance. We customize it to start with minimal frills.
152 user_ns,global_ns = IPython.ipapi.make_user_namespaces(ipnsdict(),dict())
167 user_ns,global_ns = IPython.ipapi.make_user_namespaces(ipnsdict(),dict())
153 IPython.Shell.IPShell(['--colors=NoColor','--noterm_title'],
168 IPython.Shell.IPShell(argv,user_ns,global_ns)
154 user_ns,global_ns)
155
169
156 # Deactivate the various python system hooks added by ipython for
170 # Deactivate the various python system hooks added by ipython for
157 # interactive convenience so we don't confuse the doctest system
171 # interactive convenience so we don't confuse the doctest system
158 sys.modules['__main__'] = _main
172 sys.modules['__main__'] = _main
159 sys.displayhook = _displayhook
173 sys.displayhook = _displayhook
160 sys.excepthook = _excepthook
174 sys.excepthook = _excepthook
161
175
162 # So that ipython magics and aliases can be doctested (they work by making
176 # So that ipython magics and aliases can be doctested (they work by making
163 # a call into a global _ip object)
177 # a call into a global _ip object)
164 _ip = IPython.ipapi.get()
178 _ip = IPython.ipapi.get()
165 __builtin__._ip = _ip
179 __builtin__._ip = _ip
166
180
167 # Modify the IPython system call with one that uses getoutput, so that we
181 # Modify the IPython system call with one that uses getoutput, so that we
168 # can capture subcommands and print them to Python's stdout, otherwise the
182 # can capture subcommands and print them to Python's stdout, otherwise the
169 # doctest machinery would miss them.
183 # doctest machinery would miss them.
170 _ip.system = xsys
184 _ip.system = xsys
171
185
172 # Also patch our %run function in.
186 # Also patch our %run function in.
173 im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__)
187 im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__)
174 _ip.IP.magic_run_ori = _ip.IP.magic_run
188 _ip.IP.magic_run_ori = _ip.IP.magic_run
175 _ip.IP.magic_run = im
189 _ip.IP.magic_run = im
176
190
177 # The start call MUST be made here. I'm not sure yet why it doesn't work if
191 # The start call MUST be made here. I'm not sure yet why it doesn't work if
178 # it is made later, at plugin initialization time, but in all my tests, that's
192 # it is made later, at plugin initialization time, but in all my tests, that's
179 # the case.
193 # the case.
180 start_ipython()
194 start_ipython()
181
195
182 # *** END HACK ***
196 # *** END HACK ***
183 ###########################################################################
197 ###########################################################################
184
198
185 # Classes and functions
199 # Classes and functions
186
200
187 def is_extension_module(filename):
201 def is_extension_module(filename):
188 """Return whether the given filename is an extension module.
202 """Return whether the given filename is an extension module.
189
203
190 This simply checks that the extension is either .so or .pyd.
204 This simply checks that the extension is either .so or .pyd.
191 """
205 """
192 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
206 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
193
207
194
208
195 class DocTestSkip(object):
209 class DocTestSkip(object):
196 """Object wrapper for doctests to be skipped."""
210 """Object wrapper for doctests to be skipped."""
197
211
198 ds_skip = """Doctest to skip.
212 ds_skip = """Doctest to skip.
199 >>> 1 #doctest: +SKIP
213 >>> 1 #doctest: +SKIP
200 """
214 """
201
215
202 def __init__(self,obj):
216 def __init__(self,obj):
203 self.obj = obj
217 self.obj = obj
204
218
205 def __getattribute__(self,key):
219 def __getattribute__(self,key):
206 if key == '__doc__':
220 if key == '__doc__':
207 return DocTestSkip.ds_skip
221 return DocTestSkip.ds_skip
208 else:
222 else:
209 return getattr(object.__getattribute__(self,'obj'),key)
223 return getattr(object.__getattribute__(self,'obj'),key)
210
224
211 # Modified version of the one in the stdlib, that fixes a python bug (doctests
225 # Modified version of the one in the stdlib, that fixes a python bug (doctests
212 # not found in extension modules, http://bugs.python.org/issue3158)
226 # not found in extension modules, http://bugs.python.org/issue3158)
213 class DocTestFinder(doctest.DocTestFinder):
227 class DocTestFinder(doctest.DocTestFinder):
214
228
215 def _from_module(self, module, object):
229 def _from_module(self, module, object):
216 """
230 """
217 Return true if the given object is defined in the given
231 Return true if the given object is defined in the given
218 module.
232 module.
219 """
233 """
220 if module is None:
234 if module is None:
221 return True
235 return True
222 elif inspect.isfunction(object):
236 elif inspect.isfunction(object):
223 return module.__dict__ is object.func_globals
237 return module.__dict__ is object.func_globals
224 elif inspect.isbuiltin(object):
238 elif inspect.isbuiltin(object):
225 return module.__name__ == object.__module__
239 return module.__name__ == object.__module__
226 elif inspect.isclass(object):
240 elif inspect.isclass(object):
227 return module.__name__ == object.__module__
241 return module.__name__ == object.__module__
228 elif inspect.ismethod(object):
242 elif inspect.ismethod(object):
229 # This one may be a bug in cython that fails to correctly set the
243 # This one may be a bug in cython that fails to correctly set the
230 # __module__ attribute of methods, but since the same error is easy
244 # __module__ attribute of methods, but since the same error is easy
231 # to make by extension code writers, having this safety in place
245 # to make by extension code writers, having this safety in place
232 # isn't such a bad idea
246 # isn't such a bad idea
233 return module.__name__ == object.im_class.__module__
247 return module.__name__ == object.im_class.__module__
234 elif inspect.getmodule(object) is not None:
248 elif inspect.getmodule(object) is not None:
235 return module is inspect.getmodule(object)
249 return module is inspect.getmodule(object)
236 elif hasattr(object, '__module__'):
250 elif hasattr(object, '__module__'):
237 return module.__name__ == object.__module__
251 return module.__name__ == object.__module__
238 elif isinstance(object, property):
252 elif isinstance(object, property):
239 return True # [XX] no way not be sure.
253 return True # [XX] no way not be sure.
240 else:
254 else:
241 raise ValueError("object must be a class or function")
255 raise ValueError("object must be a class or function")
242
256
243 def _find(self, tests, obj, name, module, source_lines, globs, seen):
257 def _find(self, tests, obj, name, module, source_lines, globs, seen):
244 """
258 """
245 Find tests for the given object and any contained objects, and
259 Find tests for the given object and any contained objects, and
246 add them to `tests`.
260 add them to `tests`.
247 """
261 """
248
262
249 if hasattr(obj,"skip_doctest"):
263 if hasattr(obj,"skip_doctest"):
250 #print 'SKIPPING DOCTEST FOR:',obj # dbg
264 #print 'SKIPPING DOCTEST FOR:',obj # dbg
251 obj = DocTestSkip(obj)
265 obj = DocTestSkip(obj)
252
266
253 doctest.DocTestFinder._find(self,tests, obj, name, module,
267 doctest.DocTestFinder._find(self,tests, obj, name, module,
254 source_lines, globs, seen)
268 source_lines, globs, seen)
255
269
256 # Below we re-run pieces of the above method with manual modifications,
270 # Below we re-run pieces of the above method with manual modifications,
257 # because the original code is buggy and fails to correctly identify
271 # because the original code is buggy and fails to correctly identify
258 # doctests in extension modules.
272 # doctests in extension modules.
259
273
260 # Local shorthands
274 # Local shorthands
261 from inspect import isroutine, isclass, ismodule
275 from inspect import isroutine, isclass, ismodule
262
276
263 # Look for tests in a module's contained objects.
277 # Look for tests in a module's contained objects.
264 if inspect.ismodule(obj) and self._recurse:
278 if inspect.ismodule(obj) and self._recurse:
265 for valname, val in obj.__dict__.items():
279 for valname, val in obj.__dict__.items():
266 valname1 = '%s.%s' % (name, valname)
280 valname1 = '%s.%s' % (name, valname)
267 if ( (isroutine(val) or isclass(val))
281 if ( (isroutine(val) or isclass(val))
268 and self._from_module(module, val) ):
282 and self._from_module(module, val) ):
269
283
270 self._find(tests, val, valname1, module, source_lines,
284 self._find(tests, val, valname1, module, source_lines,
271 globs, seen)
285 globs, seen)
272
286
273 # Look for tests in a class's contained objects.
287 # Look for tests in a class's contained objects.
274 if inspect.isclass(obj) and self._recurse:
288 if inspect.isclass(obj) and self._recurse:
275 #print 'RECURSE into class:',obj # dbg
289 #print 'RECURSE into class:',obj # dbg
276 for valname, val in obj.__dict__.items():
290 for valname, val in obj.__dict__.items():
277 # Special handling for staticmethod/classmethod.
291 # Special handling for staticmethod/classmethod.
278 if isinstance(val, staticmethod):
292 if isinstance(val, staticmethod):
279 val = getattr(obj, valname)
293 val = getattr(obj, valname)
280 if isinstance(val, classmethod):
294 if isinstance(val, classmethod):
281 val = getattr(obj, valname).im_func
295 val = getattr(obj, valname).im_func
282
296
283 # Recurse to methods, properties, and nested classes.
297 # Recurse to methods, properties, and nested classes.
284 if ((inspect.isfunction(val) or inspect.isclass(val) or
298 if ((inspect.isfunction(val) or inspect.isclass(val) or
285 inspect.ismethod(val) or
299 inspect.ismethod(val) or
286 isinstance(val, property)) and
300 isinstance(val, property)) and
287 self._from_module(module, val)):
301 self._from_module(module, val)):
288 valname = '%s.%s' % (name, valname)
302 valname = '%s.%s' % (name, valname)
289 self._find(tests, val, valname, module, source_lines,
303 self._find(tests, val, valname, module, source_lines,
290 globs, seen)
304 globs, seen)
291
305
292
306
293 class IPDoctestOutputChecker(doctest.OutputChecker):
307 class IPDoctestOutputChecker(doctest.OutputChecker):
294 """Second-chance checker with support for random tests.
308 """Second-chance checker with support for random tests.
295
309
296 If the default comparison doesn't pass, this checker looks in the expected
310 If the default comparison doesn't pass, this checker looks in the expected
297 output string for flags that tell us to ignore the output.
311 output string for flags that tell us to ignore the output.
298 """
312 """
299
313
300 random_re = re.compile(r'#\s*random\s+')
314 random_re = re.compile(r'#\s*random\s+')
301
315
302 def check_output(self, want, got, optionflags):
316 def check_output(self, want, got, optionflags):
303 """Check output, accepting special markers embedded in the output.
317 """Check output, accepting special markers embedded in the output.
304
318
305 If the output didn't pass the default validation but the special string
319 If the output didn't pass the default validation but the special string
306 '#random' is included, we accept it."""
320 '#random' is included, we accept it."""
307
321
308 # Let the original tester verify first, in case people have valid tests
322 # Let the original tester verify first, in case people have valid tests
309 # that happen to have a comment saying '#random' embedded in.
323 # that happen to have a comment saying '#random' embedded in.
310 ret = doctest.OutputChecker.check_output(self, want, got,
324 ret = doctest.OutputChecker.check_output(self, want, got,
311 optionflags)
325 optionflags)
312 if not ret and self.random_re.search(want):
326 if not ret and self.random_re.search(want):
313 #print >> sys.stderr, 'RANDOM OK:',want # dbg
327 #print >> sys.stderr, 'RANDOM OK:',want # dbg
314 return True
328 return True
315
329
316 return ret
330 return ret
317
331
318
332
319 class DocTestCase(doctests.DocTestCase):
333 class DocTestCase(doctests.DocTestCase):
320 """Proxy for DocTestCase: provides an address() method that
334 """Proxy for DocTestCase: provides an address() method that
321 returns the correct address for the doctest case. Otherwise
335 returns the correct address for the doctest case. Otherwise
322 acts as a proxy to the test case. To provide hints for address(),
336 acts as a proxy to the test case. To provide hints for address(),
323 an obj may also be passed -- this will be used as the test object
337 an obj may also be passed -- this will be used as the test object
324 for purposes of determining the test address, if it is provided.
338 for purposes of determining the test address, if it is provided.
325 """
339 """
326
340
327 # Note: this method was taken from numpy's nosetester module.
341 # Note: this method was taken from numpy's nosetester module.
328
342
329 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
343 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
330 # its constructor that blocks non-default arguments from being passed
344 # its constructor that blocks non-default arguments from being passed
331 # down into doctest.DocTestCase
345 # down into doctest.DocTestCase
332
346
333 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
347 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
334 checker=None, obj=None, result_var='_'):
348 checker=None, obj=None, result_var='_'):
335 self._result_var = result_var
349 self._result_var = result_var
336 doctests.DocTestCase.__init__(self, test,
350 doctests.DocTestCase.__init__(self, test,
337 optionflags=optionflags,
351 optionflags=optionflags,
338 setUp=setUp, tearDown=tearDown,
352 setUp=setUp, tearDown=tearDown,
339 checker=checker)
353 checker=checker)
340 # Now we must actually copy the original constructor from the stdlib
354 # Now we must actually copy the original constructor from the stdlib
341 # doctest class, because we can't call it directly and a bug in nose
355 # doctest class, because we can't call it directly and a bug in nose
342 # means it never gets passed the right arguments.
356 # means it never gets passed the right arguments.
343
357
344 self._dt_optionflags = optionflags
358 self._dt_optionflags = optionflags
345 self._dt_checker = checker
359 self._dt_checker = checker
346 self._dt_test = test
360 self._dt_test = test
347 self._dt_setUp = setUp
361 self._dt_setUp = setUp
348 self._dt_tearDown = tearDown
362 self._dt_tearDown = tearDown
349
363
350 # XXX - store this runner once in the object!
364 # XXX - store this runner once in the object!
351 runner = IPDocTestRunner(optionflags=optionflags,
365 runner = IPDocTestRunner(optionflags=optionflags,
352 checker=checker, verbose=False)
366 checker=checker, verbose=False)
353 self._dt_runner = runner
367 self._dt_runner = runner
354
368
355
369
356 # Each doctest should remember what directory it was loaded from...
370 # Each doctest should remember what directory it was loaded from...
357 self._ori_dir = os.getcwd()
371 self._ori_dir = os.getcwd()
358
372
359 # Modified runTest from the default stdlib
373 # Modified runTest from the default stdlib
360 def runTest(self):
374 def runTest(self):
361 test = self._dt_test
375 test = self._dt_test
362 runner = self._dt_runner
376 runner = self._dt_runner
363
377
364 old = sys.stdout
378 old = sys.stdout
365 new = StringIO()
379 new = StringIO()
366 optionflags = self._dt_optionflags
380 optionflags = self._dt_optionflags
367
381
368 if not (optionflags & REPORTING_FLAGS):
382 if not (optionflags & REPORTING_FLAGS):
369 # The option flags don't include any reporting flags,
383 # The option flags don't include any reporting flags,
370 # so add the default reporting flags
384 # so add the default reporting flags
371 optionflags |= _unittest_reportflags
385 optionflags |= _unittest_reportflags
372
386
373 try:
387 try:
374 # Save our current directory and switch out to the one where the
388 # Save our current directory and switch out to the one where the
375 # test was originally created, in case another doctest did a
389 # test was originally created, in case another doctest did a
376 # directory change. We'll restore this in the finally clause.
390 # directory change. We'll restore this in the finally clause.
377 curdir = os.getcwd()
391 curdir = os.getcwd()
378 os.chdir(self._ori_dir)
392 os.chdir(self._ori_dir)
379
393
380 runner.DIVIDER = "-"*70
394 runner.DIVIDER = "-"*70
381 failures, tries = runner.run(test,out=new.write,
395 failures, tries = runner.run(test,out=new.write,
382 clear_globs=False)
396 clear_globs=False)
383 finally:
397 finally:
384 sys.stdout = old
398 sys.stdout = old
385 os.chdir(curdir)
399 os.chdir(curdir)
386
400
387 if failures:
401 if failures:
388 raise self.failureException(self.format_failure(new.getvalue()))
402 raise self.failureException(self.format_failure(new.getvalue()))
389
403
390 def setUp(self):
404 def setUp(self):
391 """Modified test setup that syncs with ipython namespace"""
405 """Modified test setup that syncs with ipython namespace"""
392
406
393 if isinstance(self._dt_test.examples[0],IPExample):
407 if isinstance(self._dt_test.examples[0],IPExample):
394 # for IPython examples *only*, we swap the globals with the ipython
408 # for IPython examples *only*, we swap the globals with the ipython
395 # namespace, after updating it with the globals (which doctest
409 # namespace, after updating it with the globals (which doctest
396 # fills with the necessary info from the module being tested).
410 # fills with the necessary info from the module being tested).
397 _ip.IP.user_ns.update(self._dt_test.globs)
411 _ip.IP.user_ns.update(self._dt_test.globs)
398 self._dt_test.globs = _ip.IP.user_ns
412 self._dt_test.globs = _ip.IP.user_ns
399
413
400 doctests.DocTestCase.setUp(self)
414 doctests.DocTestCase.setUp(self)
401
415
402
416
403 # A simple subclassing of the original with a different class name, so we can
417 # A simple subclassing of the original with a different class name, so we can
404 # distinguish and treat differently IPython examples from pure python ones.
418 # distinguish and treat differently IPython examples from pure python ones.
405 class IPExample(doctest.Example): pass
419 class IPExample(doctest.Example): pass
406
420
407
421
408 class IPExternalExample(doctest.Example):
422 class IPExternalExample(doctest.Example):
409 """Doctest examples to be run in an external process."""
423 """Doctest examples to be run in an external process."""
410
424
411 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
425 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
412 options=None):
426 options=None):
413 # Parent constructor
427 # Parent constructor
414 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
428 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
415
429
416 # An EXTRA newline is needed to prevent pexpect hangs
430 # An EXTRA newline is needed to prevent pexpect hangs
417 self.source += '\n'
431 self.source += '\n'
418
432
419
433
420 class IPDocTestParser(doctest.DocTestParser):
434 class IPDocTestParser(doctest.DocTestParser):
421 """
435 """
422 A class used to parse strings containing doctest examples.
436 A class used to parse strings containing doctest examples.
423
437
424 Note: This is a version modified to properly recognize IPython input and
438 Note: This is a version modified to properly recognize IPython input and
425 convert any IPython examples into valid Python ones.
439 convert any IPython examples into valid Python ones.
426 """
440 """
427 # This regular expression is used to find doctest examples in a
441 # This regular expression is used to find doctest examples in a
428 # string. It defines three groups: `source` is the source code
442 # string. It defines three groups: `source` is the source code
429 # (including leading indentation and prompts); `indent` is the
443 # (including leading indentation and prompts); `indent` is the
430 # indentation of the first (PS1) line of the source code; and
444 # indentation of the first (PS1) line of the source code; and
431 # `want` is the expected output (including leading indentation).
445 # `want` is the expected output (including leading indentation).
432
446
433 # Classic Python prompts or default IPython ones
447 # Classic Python prompts or default IPython ones
434 _PS1_PY = r'>>>'
448 _PS1_PY = r'>>>'
435 _PS2_PY = r'\.\.\.'
449 _PS2_PY = r'\.\.\.'
436
450
437 _PS1_IP = r'In\ \[\d+\]:'
451 _PS1_IP = r'In\ \[\d+\]:'
438 _PS2_IP = r'\ \ \ \.\.\.+:'
452 _PS2_IP = r'\ \ \ \.\.\.+:'
439
453
440 _RE_TPL = r'''
454 _RE_TPL = r'''
441 # Source consists of a PS1 line followed by zero or more PS2 lines.
455 # Source consists of a PS1 line followed by zero or more PS2 lines.
442 (?P<source>
456 (?P<source>
443 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
457 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
444 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
458 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
445 \n? # a newline
459 \n? # a newline
446 # Want consists of any non-blank lines that do not start with PS1.
460 # Want consists of any non-blank lines that do not start with PS1.
447 (?P<want> (?:(?![ ]*$) # Not a blank line
461 (?P<want> (?:(?![ ]*$) # Not a blank line
448 (?![ ]*%s) # Not a line starting with PS1
462 (?![ ]*%s) # Not a line starting with PS1
449 (?![ ]*%s) # Not a line starting with PS2
463 (?![ ]*%s) # Not a line starting with PS2
450 .*$\n? # But any other line
464 .*$\n? # But any other line
451 )*)
465 )*)
452 '''
466 '''
453
467
454 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
468 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
455 re.MULTILINE | re.VERBOSE)
469 re.MULTILINE | re.VERBOSE)
456
470
457 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
471 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
458 re.MULTILINE | re.VERBOSE)
472 re.MULTILINE | re.VERBOSE)
459
473
460 # Mark a test as being fully random. In this case, we simply append the
474 # Mark a test as being fully random. In this case, we simply append the
461 # random marker ('#random') to each individual example's output. This way
475 # random marker ('#random') to each individual example's output. This way
462 # we don't need to modify any other code.
476 # we don't need to modify any other code.
463 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
477 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
464
478
465 # Mark tests to be executed in an external process - currently unsupported.
479 # Mark tests to be executed in an external process - currently unsupported.
466 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
480 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
467
481
468 def ip2py(self,source):
482 def ip2py(self,source):
469 """Convert input IPython source into valid Python."""
483 """Convert input IPython source into valid Python."""
470 out = []
484 out = []
471 newline = out.append
485 newline = out.append
472 #print 'IPSRC:\n',source,'\n###' # dbg
486 #print 'IPSRC:\n',source,'\n###' # dbg
473 # The input source must be first stripped of all bracketing whitespace
487 # The input source must be first stripped of all bracketing whitespace
474 # and turned into lines, so it looks to the parser like regular user
488 # and turned into lines, so it looks to the parser like regular user
475 # input
489 # input
476 for lnum,line in enumerate(source.strip().splitlines()):
490 for lnum,line in enumerate(source.strip().splitlines()):
477 newline(_ip.IP.prefilter(line,lnum>0))
491 newline(_ip.IP.prefilter(line,lnum>0))
478 newline('') # ensure a closing newline, needed by doctest
492 newline('') # ensure a closing newline, needed by doctest
479 #print "PYSRC:", '\n'.join(out) # dbg
493 #print "PYSRC:", '\n'.join(out) # dbg
480 return '\n'.join(out)
494 return '\n'.join(out)
481
495
482 def parse(self, string, name='<string>'):
496 def parse(self, string, name='<string>'):
483 """
497 """
484 Divide the given string into examples and intervening text,
498 Divide the given string into examples and intervening text,
485 and return them as a list of alternating Examples and strings.
499 and return them as a list of alternating Examples and strings.
486 Line numbers for the Examples are 0-based. The optional
500 Line numbers for the Examples are 0-based. The optional
487 argument `name` is a name identifying this string, and is only
501 argument `name` is a name identifying this string, and is only
488 used for error messages.
502 used for error messages.
489 """
503 """
490
504
491 #print 'Parse string:\n',string # dbg
505 #print 'Parse string:\n',string # dbg
492
506
493 string = string.expandtabs()
507 string = string.expandtabs()
494 # If all lines begin with the same indentation, then strip it.
508 # If all lines begin with the same indentation, then strip it.
495 min_indent = self._min_indent(string)
509 min_indent = self._min_indent(string)
496 if min_indent > 0:
510 if min_indent > 0:
497 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
511 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
498
512
499 output = []
513 output = []
500 charno, lineno = 0, 0
514 charno, lineno = 0, 0
501
515
502 # We make 'all random' tests by adding the '# random' mark to every
516 # We make 'all random' tests by adding the '# random' mark to every
503 # block of output in the test.
517 # block of output in the test.
504 if self._RANDOM_TEST.search(string):
518 if self._RANDOM_TEST.search(string):
505 random_marker = '\n# random'
519 random_marker = '\n# random'
506 else:
520 else:
507 random_marker = ''
521 random_marker = ''
508
522
509 # Whether to convert the input from ipython to python syntax
523 # Whether to convert the input from ipython to python syntax
510 ip2py = False
524 ip2py = False
511 # Find all doctest examples in the string. First, try them as Python
525 # Find all doctest examples in the string. First, try them as Python
512 # examples, then as IPython ones
526 # examples, then as IPython ones
513 terms = list(self._EXAMPLE_RE_PY.finditer(string))
527 terms = list(self._EXAMPLE_RE_PY.finditer(string))
514 if terms:
528 if terms:
515 # Normal Python example
529 # Normal Python example
516 #print '-'*70 # dbg
530 #print '-'*70 # dbg
517 #print 'PyExample, Source:\n',string # dbg
531 #print 'PyExample, Source:\n',string # dbg
518 #print '-'*70 # dbg
532 #print '-'*70 # dbg
519 Example = doctest.Example
533 Example = doctest.Example
520 else:
534 else:
521 # It's an ipython example. Note that IPExamples are run
535 # It's an ipython example. Note that IPExamples are run
522 # in-process, so their syntax must be turned into valid python.
536 # in-process, so their syntax must be turned into valid python.
523 # IPExternalExamples are run out-of-process (via pexpect) so they
537 # IPExternalExamples are run out-of-process (via pexpect) so they
524 # don't need any filtering (a real ipython will be executing them).
538 # don't need any filtering (a real ipython will be executing them).
525 terms = list(self._EXAMPLE_RE_IP.finditer(string))
539 terms = list(self._EXAMPLE_RE_IP.finditer(string))
526 if self._EXTERNAL_IP.search(string):
540 if self._EXTERNAL_IP.search(string):
527 #print '-'*70 # dbg
541 #print '-'*70 # dbg
528 #print 'IPExternalExample, Source:\n',string # dbg
542 #print 'IPExternalExample, Source:\n',string # dbg
529 #print '-'*70 # dbg
543 #print '-'*70 # dbg
530 Example = IPExternalExample
544 Example = IPExternalExample
531 else:
545 else:
532 #print '-'*70 # dbg
546 #print '-'*70 # dbg
533 #print 'IPExample, Source:\n',string # dbg
547 #print 'IPExample, Source:\n',string # dbg
534 #print '-'*70 # dbg
548 #print '-'*70 # dbg
535 Example = IPExample
549 Example = IPExample
536 ip2py = True
550 ip2py = True
537
551
538 for m in terms:
552 for m in terms:
539 # Add the pre-example text to `output`.
553 # Add the pre-example text to `output`.
540 output.append(string[charno:m.start()])
554 output.append(string[charno:m.start()])
541 # Update lineno (lines before this example)
555 # Update lineno (lines before this example)
542 lineno += string.count('\n', charno, m.start())
556 lineno += string.count('\n', charno, m.start())
543 # Extract info from the regexp match.
557 # Extract info from the regexp match.
544 (source, options, want, exc_msg) = \
558 (source, options, want, exc_msg) = \
545 self._parse_example(m, name, lineno,ip2py)
559 self._parse_example(m, name, lineno,ip2py)
546
560
547 # Append the random-output marker (it defaults to empty in most
561 # Append the random-output marker (it defaults to empty in most
548 # cases, it's only non-empty for 'all-random' tests):
562 # cases, it's only non-empty for 'all-random' tests):
549 want += random_marker
563 want += random_marker
550
564
551 if Example is IPExternalExample:
565 if Example is IPExternalExample:
552 options[doctest.NORMALIZE_WHITESPACE] = True
566 options[doctest.NORMALIZE_WHITESPACE] = True
553 want += '\n'
567 want += '\n'
554
568
555 # Create an Example, and add it to the list.
569 # Create an Example, and add it to the list.
556 if not self._IS_BLANK_OR_COMMENT(source):
570 if not self._IS_BLANK_OR_COMMENT(source):
557 output.append(Example(source, want, exc_msg,
571 output.append(Example(source, want, exc_msg,
558 lineno=lineno,
572 lineno=lineno,
559 indent=min_indent+len(m.group('indent')),
573 indent=min_indent+len(m.group('indent')),
560 options=options))
574 options=options))
561 # Update lineno (lines inside this example)
575 # Update lineno (lines inside this example)
562 lineno += string.count('\n', m.start(), m.end())
576 lineno += string.count('\n', m.start(), m.end())
563 # Update charno.
577 # Update charno.
564 charno = m.end()
578 charno = m.end()
565 # Add any remaining post-example text to `output`.
579 # Add any remaining post-example text to `output`.
566 output.append(string[charno:])
580 output.append(string[charno:])
567 return output
581 return output
568
582
569 def _parse_example(self, m, name, lineno,ip2py=False):
583 def _parse_example(self, m, name, lineno,ip2py=False):
570 """
584 """
571 Given a regular expression match from `_EXAMPLE_RE` (`m`),
585 Given a regular expression match from `_EXAMPLE_RE` (`m`),
572 return a pair `(source, want)`, where `source` is the matched
586 return a pair `(source, want)`, where `source` is the matched
573 example's source code (with prompts and indentation stripped);
587 example's source code (with prompts and indentation stripped);
574 and `want` is the example's expected output (with indentation
588 and `want` is the example's expected output (with indentation
575 stripped).
589 stripped).
576
590
577 `name` is the string's name, and `lineno` is the line number
591 `name` is the string's name, and `lineno` is the line number
578 where the example starts; both are used for error messages.
592 where the example starts; both are used for error messages.
579
593
580 Optional:
594 Optional:
581 `ip2py`: if true, filter the input via IPython to convert the syntax
595 `ip2py`: if true, filter the input via IPython to convert the syntax
582 into valid python.
596 into valid python.
583 """
597 """
584
598
585 # Get the example's indentation level.
599 # Get the example's indentation level.
586 indent = len(m.group('indent'))
600 indent = len(m.group('indent'))
587
601
588 # Divide source into lines; check that they're properly
602 # Divide source into lines; check that they're properly
589 # indented; and then strip their indentation & prompts.
603 # indented; and then strip their indentation & prompts.
590 source_lines = m.group('source').split('\n')
604 source_lines = m.group('source').split('\n')
591
605
592 # We're using variable-length input prompts
606 # We're using variable-length input prompts
593 ps1 = m.group('ps1')
607 ps1 = m.group('ps1')
594 ps2 = m.group('ps2')
608 ps2 = m.group('ps2')
595 ps1_len = len(ps1)
609 ps1_len = len(ps1)
596
610
597 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
611 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
598 if ps2:
612 if ps2:
599 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
613 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
600
614
601 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
615 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
602
616
603 if ip2py:
617 if ip2py:
604 # Convert source input from IPython into valid Python syntax
618 # Convert source input from IPython into valid Python syntax
605 source = self.ip2py(source)
619 source = self.ip2py(source)
606
620
607 # Divide want into lines; check that it's properly indented; and
621 # Divide want into lines; check that it's properly indented; and
608 # then strip the indentation. Spaces before the last newline should
622 # then strip the indentation. Spaces before the last newline should
609 # be preserved, so plain rstrip() isn't good enough.
623 # be preserved, so plain rstrip() isn't good enough.
610 want = m.group('want')
624 want = m.group('want')
611 want_lines = want.split('\n')
625 want_lines = want.split('\n')
612 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
626 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
613 del want_lines[-1] # forget final newline & spaces after it
627 del want_lines[-1] # forget final newline & spaces after it
614 self._check_prefix(want_lines, ' '*indent, name,
628 self._check_prefix(want_lines, ' '*indent, name,
615 lineno + len(source_lines))
629 lineno + len(source_lines))
616
630
617 # Remove ipython output prompt that might be present in the first line
631 # Remove ipython output prompt that might be present in the first line
618 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
632 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
619
633
620 want = '\n'.join([wl[indent:] for wl in want_lines])
634 want = '\n'.join([wl[indent:] for wl in want_lines])
621
635
622 # If `want` contains a traceback message, then extract it.
636 # If `want` contains a traceback message, then extract it.
623 m = self._EXCEPTION_RE.match(want)
637 m = self._EXCEPTION_RE.match(want)
624 if m:
638 if m:
625 exc_msg = m.group('msg')
639 exc_msg = m.group('msg')
626 else:
640 else:
627 exc_msg = None
641 exc_msg = None
628
642
629 # Extract options from the source.
643 # Extract options from the source.
630 options = self._find_options(source, name, lineno)
644 options = self._find_options(source, name, lineno)
631
645
632 return source, options, want, exc_msg
646 return source, options, want, exc_msg
633
647
634 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
648 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
635 """
649 """
636 Given the lines of a source string (including prompts and
650 Given the lines of a source string (including prompts and
637 leading indentation), check to make sure that every prompt is
651 leading indentation), check to make sure that every prompt is
638 followed by a space character. If any line is not followed by
652 followed by a space character. If any line is not followed by
639 a space character, then raise ValueError.
653 a space character, then raise ValueError.
640
654
641 Note: IPython-modified version which takes the input prompt length as a
655 Note: IPython-modified version which takes the input prompt length as a
642 parameter, so that prompts of variable length can be dealt with.
656 parameter, so that prompts of variable length can be dealt with.
643 """
657 """
644 space_idx = indent+ps1_len
658 space_idx = indent+ps1_len
645 min_len = space_idx+1
659 min_len = space_idx+1
646 for i, line in enumerate(lines):
660 for i, line in enumerate(lines):
647 if len(line) >= min_len and line[space_idx] != ' ':
661 if len(line) >= min_len and line[space_idx] != ' ':
648 raise ValueError('line %r of the docstring for %s '
662 raise ValueError('line %r of the docstring for %s '
649 'lacks blank after %s: %r' %
663 'lacks blank after %s: %r' %
650 (lineno+i+1, name,
664 (lineno+i+1, name,
651 line[indent:space_idx], line))
665 line[indent:space_idx], line))
652
666
653
667
654 SKIP = doctest.register_optionflag('SKIP')
668 SKIP = doctest.register_optionflag('SKIP')
655
669
656
670
657 class IPDocTestRunner(doctest.DocTestRunner,object):
671 class IPDocTestRunner(doctest.DocTestRunner,object):
658 """Test runner that synchronizes the IPython namespace with test globals.
672 """Test runner that synchronizes the IPython namespace with test globals.
659 """
673 """
660
674
661 def run(self, test, compileflags=None, out=None, clear_globs=True):
675 def run(self, test, compileflags=None, out=None, clear_globs=True):
662
676
663 # Hack: ipython needs access to the execution context of the example,
677 # Hack: ipython needs access to the execution context of the example,
664 # so that it can propagate user variables loaded by %run into
678 # so that it can propagate user variables loaded by %run into
665 # test.globs. We put them here into our modified %run as a function
679 # test.globs. We put them here into our modified %run as a function
666 # attribute. Our new %run will then only make the namespace update
680 # attribute. Our new %run will then only make the namespace update
667 # when called (rather than unconconditionally updating test.globs here
681 # when called (rather than unconconditionally updating test.globs here
668 # for all examples, most of which won't be calling %run anyway).
682 # for all examples, most of which won't be calling %run anyway).
669 _run_ns_sync.test_globs = test.globs
683 _run_ns_sync.test_globs = test.globs
670 _run_ns_sync.test_filename = test.filename
684 _run_ns_sync.test_filename = test.filename
671
685
672 return super(IPDocTestRunner,self).run(test,
686 return super(IPDocTestRunner,self).run(test,
673 compileflags,out,clear_globs)
687 compileflags,out,clear_globs)
674
688
675
689
676 class DocFileCase(doctest.DocFileCase):
690 class DocFileCase(doctest.DocFileCase):
677 """Overrides to provide filename
691 """Overrides to provide filename
678 """
692 """
679 def address(self):
693 def address(self):
680 return (self._dt_test.filename, None, None)
694 return (self._dt_test.filename, None, None)
681
695
682
696
683 class ExtensionDoctest(doctests.Doctest):
697 class ExtensionDoctest(doctests.Doctest):
684 """Nose Plugin that supports doctests in extension modules.
698 """Nose Plugin that supports doctests in extension modules.
685 """
699 """
686 name = 'extdoctest' # call nosetests with --with-extdoctest
700 name = 'extdoctest' # call nosetests with --with-extdoctest
687 enabled = True
701 enabled = True
688
702
689 def __init__(self,exclude_patterns=None):
703 def __init__(self,exclude_patterns=None):
690 """Create a new ExtensionDoctest plugin.
704 """Create a new ExtensionDoctest plugin.
691
705
692 Parameters
706 Parameters
693 ----------
707 ----------
694
708
695 exclude_patterns : sequence of strings, optional
709 exclude_patterns : sequence of strings, optional
696 These patterns are compiled as regular expressions, subsequently used
710 These patterns are compiled as regular expressions, subsequently used
697 to exclude any filename which matches them from inclusion in the test
711 to exclude any filename which matches them from inclusion in the test
698 suite (using pattern.search(), NOT pattern.match() ).
712 suite (using pattern.search(), NOT pattern.match() ).
699 """
713 """
700
714
701 if exclude_patterns is None:
715 if exclude_patterns is None:
702 exclude_patterns = []
716 exclude_patterns = []
703 self.exclude_patterns = map(re.compile,exclude_patterns)
717 self.exclude_patterns = map(re.compile,exclude_patterns)
704 doctests.Doctest.__init__(self)
718 doctests.Doctest.__init__(self)
705
719
706 def options(self, parser, env=os.environ):
720 def options(self, parser, env=os.environ):
707 Plugin.options(self, parser, env)
721 Plugin.options(self, parser, env)
708 parser.add_option('--doctest-tests', action='store_true',
722 parser.add_option('--doctest-tests', action='store_true',
709 dest='doctest_tests',
723 dest='doctest_tests',
710 default=env.get('NOSE_DOCTEST_TESTS',True),
724 default=env.get('NOSE_DOCTEST_TESTS',True),
711 help="Also look for doctests in test modules. "
725 help="Also look for doctests in test modules. "
712 "Note that classes, methods and functions should "
726 "Note that classes, methods and functions should "
713 "have either doctests or non-doctest tests, "
727 "have either doctests or non-doctest tests, "
714 "not both. [NOSE_DOCTEST_TESTS]")
728 "not both. [NOSE_DOCTEST_TESTS]")
715 parser.add_option('--doctest-extension', action="append",
729 parser.add_option('--doctest-extension', action="append",
716 dest="doctestExtension",
730 dest="doctestExtension",
717 help="Also look for doctests in files with "
731 help="Also look for doctests in files with "
718 "this extension [NOSE_DOCTEST_EXTENSION]")
732 "this extension [NOSE_DOCTEST_EXTENSION]")
719 # Set the default as a list, if given in env; otherwise
733 # Set the default as a list, if given in env; otherwise
720 # an additional value set on the command line will cause
734 # an additional value set on the command line will cause
721 # an error.
735 # an error.
722 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
736 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
723 if env_setting is not None:
737 if env_setting is not None:
724 parser.set_defaults(doctestExtension=tolist(env_setting))
738 parser.set_defaults(doctestExtension=tolist(env_setting))
725
739
726
740
727 def configure(self, options, config):
741 def configure(self, options, config):
728 Plugin.configure(self, options, config)
742 Plugin.configure(self, options, config)
729 self.doctest_tests = options.doctest_tests
743 self.doctest_tests = options.doctest_tests
730 self.extension = tolist(options.doctestExtension)
744 self.extension = tolist(options.doctestExtension)
731
745
732 self.parser = doctest.DocTestParser()
746 self.parser = doctest.DocTestParser()
733 self.finder = DocTestFinder()
747 self.finder = DocTestFinder()
734 self.checker = IPDoctestOutputChecker()
748 self.checker = IPDoctestOutputChecker()
735 self.globs = None
749 self.globs = None
736 self.extraglobs = None
750 self.extraglobs = None
737
751
738
752
739 def loadTestsFromExtensionModule(self,filename):
753 def loadTestsFromExtensionModule(self,filename):
740 bpath,mod = os.path.split(filename)
754 bpath,mod = os.path.split(filename)
741 modname = os.path.splitext(mod)[0]
755 modname = os.path.splitext(mod)[0]
742 try:
756 try:
743 sys.path.append(bpath)
757 sys.path.append(bpath)
744 module = __import__(modname)
758 module = __import__(modname)
745 tests = list(self.loadTestsFromModule(module))
759 tests = list(self.loadTestsFromModule(module))
746 finally:
760 finally:
747 sys.path.pop()
761 sys.path.pop()
748 return tests
762 return tests
749
763
750 # NOTE: the method below is almost a copy of the original one in nose, with
764 # NOTE: the method below is almost a copy of the original one in nose, with
751 # a few modifications to control output checking.
765 # a few modifications to control output checking.
752
766
753 def loadTestsFromModule(self, module):
767 def loadTestsFromModule(self, module):
754 #print '*** ipdoctest - lTM',module # dbg
768 #print '*** ipdoctest - lTM',module # dbg
755
769
756 if not self.matches(module.__name__):
770 if not self.matches(module.__name__):
757 log.debug("Doctest doesn't want module %s", module)
771 log.debug("Doctest doesn't want module %s", module)
758 return
772 return
759
773
760 tests = self.finder.find(module,globs=self.globs,
774 tests = self.finder.find(module,globs=self.globs,
761 extraglobs=self.extraglobs)
775 extraglobs=self.extraglobs)
762 if not tests:
776 if not tests:
763 return
777 return
764
778
765 # always use whitespace and ellipsis options
779 # always use whitespace and ellipsis options
766 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
780 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
767
781
768 tests.sort()
782 tests.sort()
769 module_file = module.__file__
783 module_file = module.__file__
770 if module_file[-4:] in ('.pyc', '.pyo'):
784 if module_file[-4:] in ('.pyc', '.pyo'):
771 module_file = module_file[:-1]
785 module_file = module_file[:-1]
772 for test in tests:
786 for test in tests:
773 if not test.examples:
787 if not test.examples:
774 continue
788 continue
775 if not test.filename:
789 if not test.filename:
776 test.filename = module_file
790 test.filename = module_file
777
791
778 yield DocTestCase(test,
792 yield DocTestCase(test,
779 optionflags=optionflags,
793 optionflags=optionflags,
780 checker=self.checker)
794 checker=self.checker)
781
795
782
796
783 def loadTestsFromFile(self, filename):
797 def loadTestsFromFile(self, filename):
784 if is_extension_module(filename):
798 if is_extension_module(filename):
785 for t in self.loadTestsFromExtensionModule(filename):
799 for t in self.loadTestsFromExtensionModule(filename):
786 yield t
800 yield t
787 else:
801 else:
788 if self.extension and anyp(filename.endswith, self.extension):
802 if self.extension and anyp(filename.endswith, self.extension):
789 name = os.path.basename(filename)
803 name = os.path.basename(filename)
790 dh = open(filename)
804 dh = open(filename)
791 try:
805 try:
792 doc = dh.read()
806 doc = dh.read()
793 finally:
807 finally:
794 dh.close()
808 dh.close()
795 test = self.parser.get_doctest(
809 test = self.parser.get_doctest(
796 doc, globs={'__file__': filename}, name=name,
810 doc, globs={'__file__': filename}, name=name,
797 filename=filename, lineno=0)
811 filename=filename, lineno=0)
798 if test.examples:
812 if test.examples:
799 #print 'FileCase:',test.examples # dbg
813 #print 'FileCase:',test.examples # dbg
800 yield DocFileCase(test)
814 yield DocFileCase(test)
801 else:
815 else:
802 yield False # no tests to load
816 yield False # no tests to load
803
817
804 def wantFile(self,filename):
818 def wantFile(self,filename):
805 """Return whether the given filename should be scanned for tests.
819 """Return whether the given filename should be scanned for tests.
806
820
807 Modified version that accepts extension modules as valid containers for
821 Modified version that accepts extension modules as valid containers for
808 doctests.
822 doctests.
809 """
823 """
810 #print '*** ipdoctest- wantFile:',filename # dbg
824 #print '*** ipdoctest- wantFile:',filename # dbg
811
825
812 for pat in self.exclude_patterns:
826 for pat in self.exclude_patterns:
813 if pat.search(filename):
827 if pat.search(filename):
814 #print '###>>> SKIP:',filename # dbg
828 #print '###>>> SKIP:',filename # dbg
815 return False
829 return False
816
830
817 if is_extension_module(filename):
831 if is_extension_module(filename):
818 return True
832 return True
819 else:
833 else:
820 return doctests.Doctest.wantFile(self,filename)
834 return doctests.Doctest.wantFile(self,filename)
821
835
822
836
823 class IPythonDoctest(ExtensionDoctest):
837 class IPythonDoctest(ExtensionDoctest):
824 """Nose Plugin that supports doctests in extension modules.
838 """Nose Plugin that supports doctests in extension modules.
825 """
839 """
826 name = 'ipdoctest' # call nosetests with --with-ipdoctest
840 name = 'ipdoctest' # call nosetests with --with-ipdoctest
827 enabled = True
841 enabled = True
828
842
829 def makeTest(self, obj, parent):
843 def makeTest(self, obj, parent):
830 """Look for doctests in the given object, which will be a
844 """Look for doctests in the given object, which will be a
831 function, method or class.
845 function, method or class.
832 """
846 """
833 # always use whitespace and ellipsis options
847 # always use whitespace and ellipsis options
834 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
848 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
835
849
836 doctests = self.finder.find(obj, module=getmodule(parent))
850 doctests = self.finder.find(obj, module=getmodule(parent))
837 if doctests:
851 if doctests:
838 for test in doctests:
852 for test in doctests:
839 if len(test.examples) == 0:
853 if len(test.examples) == 0:
840 continue
854 continue
841
855
842 yield DocTestCase(test, obj=obj,
856 yield DocTestCase(test, obj=obj,
843 optionflags=optionflags,
857 optionflags=optionflags,
844 checker=self.checker)
858 checker=self.checker)
845
859
846 def options(self, parser, env=os.environ):
860 def options(self, parser, env=os.environ):
847 Plugin.options(self, parser, env)
861 Plugin.options(self, parser, env)
848 parser.add_option('--ipdoctest-tests', action='store_true',
862 parser.add_option('--ipdoctest-tests', action='store_true',
849 dest='ipdoctest_tests',
863 dest='ipdoctest_tests',
850 default=env.get('NOSE_IPDOCTEST_TESTS',True),
864 default=env.get('NOSE_IPDOCTEST_TESTS',True),
851 help="Also look for doctests in test modules. "
865 help="Also look for doctests in test modules. "
852 "Note that classes, methods and functions should "
866 "Note that classes, methods and functions should "
853 "have either doctests or non-doctest tests, "
867 "have either doctests or non-doctest tests, "
854 "not both. [NOSE_IPDOCTEST_TESTS]")
868 "not both. [NOSE_IPDOCTEST_TESTS]")
855 parser.add_option('--ipdoctest-extension', action="append",
869 parser.add_option('--ipdoctest-extension', action="append",
856 dest="ipdoctest_extension",
870 dest="ipdoctest_extension",
857 help="Also look for doctests in files with "
871 help="Also look for doctests in files with "
858 "this extension [NOSE_IPDOCTEST_EXTENSION]")
872 "this extension [NOSE_IPDOCTEST_EXTENSION]")
859 # Set the default as a list, if given in env; otherwise
873 # Set the default as a list, if given in env; otherwise
860 # an additional value set on the command line will cause
874 # an additional value set on the command line will cause
861 # an error.
875 # an error.
862 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
876 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
863 if env_setting is not None:
877 if env_setting is not None:
864 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
878 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
865
879
866 def configure(self, options, config):
880 def configure(self, options, config):
867 Plugin.configure(self, options, config)
881 Plugin.configure(self, options, config)
868 self.doctest_tests = options.ipdoctest_tests
882 self.doctest_tests = options.ipdoctest_tests
869 self.extension = tolist(options.ipdoctest_extension)
883 self.extension = tolist(options.ipdoctest_extension)
870
884
871 self.parser = IPDocTestParser()
885 self.parser = IPDocTestParser()
872 self.finder = DocTestFinder(parser=self.parser)
886 self.finder = DocTestFinder(parser=self.parser)
873 self.checker = IPDoctestOutputChecker()
887 self.checker = IPDoctestOutputChecker()
874 self.globs = None
888 self.globs = None
875 self.extraglobs = None
889 self.extraglobs = None
General Comments 0
You need to be logged in to leave comments. Login now