diff --git a/IPython/testing/plugin/Makefile b/IPython/testing/plugin/Makefile index 5c5d1cb..77392f5 100644 --- a/IPython/testing/plugin/Makefile +++ b/IPython/testing/plugin/Makefile @@ -4,8 +4,12 @@ PREFIX=~/tmp/local plugin: IPython_doctest_plugin.egg-info +dtest: plugin dtexample.py + nosetests -vs --with-ipdoctest --doctest-tests --doctest-extension=txt \ + dtexample.py + test: plugin dtexample.py - nosetests -s --with-ipdoctest --doctest-tests --doctest-extension=txt \ + nosetests -vs --with-ipdoctest --doctest-tests --doctest-extension=txt \ dtexample.py test*.txt deb: plugin dtexample.py diff --git a/IPython/testing/plugin/dtexample.py b/IPython/testing/plugin/dtexample.py index d4b6d01..0d69718 100644 --- a/IPython/testing/plugin/dtexample.py +++ b/IPython/testing/plugin/dtexample.py @@ -70,3 +70,38 @@ def ipfunc(): return 'ipfunc' + +def ranfunc(): + """A function with some random output. + + >>> 1+3 #random + junk goes here... + + >>> 1+3 + 4 + + >>> 1+2 #random + again, anything goes + """ + return 'ranfunc' + + +def ranf2(): + """A function whose examples are all all random + + Examples: + + #all-random + + >>> 1+3 #random + junk goes here... + + >>> 1+3 + klasdfj; + + >>> 1+2 #random + again, anything goes + + """ + return 'ranf2' + diff --git a/IPython/testing/plugin/ipdoctest.py b/IPython/testing/plugin/ipdoctest.py index cde2895..0d0ec4c 100644 --- a/IPython/testing/plugin/ipdoctest.py +++ b/IPython/testing/plugin/ipdoctest.py @@ -222,6 +222,20 @@ class DocTestCase(doctests.DocTestCase): for purposes of determining the test address, if it is provided. """ + # Note: this method was taken from numpy's nosetester module. + + # Subclass nose.plugins.doctests.DocTestCase to work around a bug in + # its constructor that blocks non-default arguments from being passed + # down into doctest.DocTestCase + ## def __init__(self, test, optionflags=0, setUp=None, tearDown=None, + ## checker=None, obj=None, result_var='_'): + ## self._result_var = result_var + ## self._nose_obj = obj + ## doctest.DocTestCase.__init__(self, test, + ## optionflags=optionflags, + ## setUp=setUp, tearDown=tearDown, + ## checker=checker) + # doctests loaded via find(obj) omit the module name # so we need to override id, __repr__ and shortDescription # bonus: this will squash a 2.3 vs 2.4 incompatiblity @@ -235,6 +249,7 @@ class DocTestCase(doctests.DocTestCase): return name + # A simple subclassing of the original with a different class name, so we can # distinguish and treat differently IPython examples from pure python ones. class IPExample(doctest.Example): pass @@ -311,7 +326,7 @@ class IPDocTestParser(doctest.DocTestParser): used for error messages. """ - #print 'Parse string:\n',string # dbg + print 'Parse string:\n',string # dbg string = string.expandtabs() # If all lines begin with the same indentation, then strip it. @@ -376,6 +391,8 @@ class IPDocTestParser(doctest.DocTestParser): # Add any remaining post-example text to `output`. output.append(string[charno:]) + #print 'OUT:',output # dbg + return output def _parse_example(self, m, name, lineno,ip2py=False): @@ -501,6 +518,8 @@ class ExtensionDoctest(doctests.Doctest): return tests def loadTestsFromFile(self, filename): + print 'lTF',filename # dbg + if is_extension_module(filename): for t in self.loadTestsFromExtensionModule(filename): yield t @@ -510,7 +529,6 @@ class ExtensionDoctest(doctests.Doctest): pass if self.extension and anyp(filename.endswith, self.extension): - #print 'lTF',filename # dbg name = os.path.basename(filename) dh = open(filename) try: @@ -532,7 +550,7 @@ class ExtensionDoctest(doctests.Doctest): Modified version that accepts extension modules as valid containers for doctests. """ - #print 'Filename:',filename # dbg + print 'Filename:',filename # dbg # temporarily hardcoded list, will move to driver later exclude = ['IPython/external/', @@ -553,14 +571,9 @@ class ExtensionDoctest(doctests.Doctest): else: return doctests.Doctest.wantFile(self,filename) - # NOTE: the method below is a *copy* of the one in the nose doctests - # plugin, but we have to replicate it here in order to have it resolve the - # DocTestCase (last line) to our local copy, since the nose plugin doesn't - # provide a public hook for what TestCase class to use. The alternative - # would be to monkeypatch doctest in the stdlib, but that's ugly and - # brittle, since a change in plugin load order can break it. So for now, - # we just paste this in here, inelegant as this may be. - + # NOTE: the method below is almost a copy of the original one in nose, with + # a few modifications to control output checking. + def loadTestsFromModule(self, module): #print 'lTM',module # dbg @@ -581,6 +594,15 @@ class ExtensionDoctest(doctests.Doctest): test.filename = module_file yield DocTestCase(test) + # always use whitespace and ellipsis options + optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS + #checker = DoctestOutputChecker() + checker = None + yield DocTestCase(test, + optionflags=optionflags, + checker=checker) + + class IPythonDoctest(ExtensionDoctest): """Nose Plugin that supports doctests in extension modules. @@ -594,5 +616,4 @@ class IPythonDoctest(ExtensionDoctest): self.doctest_tests = options.doctest_tests self.extension = tolist(options.doctestExtension) self.parser = IPDocTestParser() - #self.finder = DocTestFinder(parser=IPDocTestParser()) self.finder = DocTestFinder(parser=self.parser)