##// END OF EJS Templates
Correctly implement namespace handling. Minor cleanups....
Fernando Perez -
Show More
@@ -3,7 +3,8 b' 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
@@ -31,30 +32,38 b' deb: plugin dtexample.py'
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
@@ -13,21 +13,6 b' Limitations:'
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
@@ -63,9 +48,6 b' import nose.core'
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
@@ -79,9 +61,9 b' log = logging.getLogger(__name__)'
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.
@@ -94,27 +76,34 b' def _run_ns_sync(self,arg_s,runner=None):'
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.
@@ -139,7 +128,7 b' def start_ipython():'
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)
@@ -275,85 +264,6 b' class DocTestFinder(doctest.DocTestFinder):'
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
@@ -411,12 +321,20 b' class DocTestCase(doctests.DocTestCase):'
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
@@ -426,9 +344,6 b' class DocTestCase(doctests.DocTestCase):'
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
@@ -437,8 +352,8 b' class DocTestCase(doctests.DocTestCase):'
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)
@@ -446,11 +361,18 b' class DocTestCase(doctests.DocTestCase):'
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
@@ -548,6 +470,8 b' class IPDocTestParser(doctest.DocTestParser):'
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:
@@ -715,12 +639,6 b' class IPDocTestRunner(doctest.DocTestRunner,object):'
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
@@ -745,8 +663,10 b' class ExtensionDoctest(doctests.Doctest):'
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
@@ -776,6 +696,9 b' class ExtensionDoctest(doctests.Doctest):'
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'):
@@ -785,15 +708,11 b' class ExtensionDoctest(doctests.Doctest):'
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
@@ -826,7 +745,7 b' class ExtensionDoctest(doctests.Doctest):'
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',
@@ -857,11 +776,9 b' class IPythonDoctest(ExtensionDoctest):'
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