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