[Checkins] SVN: manuel/trunk/ fix a bug that caused instances of zope.testin.doctest.Example (and instances
Benji York
benji at zope.com
Mon Dec 7 15:15:04 EST 2009
Log message for revision 106256:
fix a bug that caused instances of zope.testin.doctest.Example (and instances
of subclasses of the same) to be silently ignored
Changed:
U manuel/trunk/CHANGES.txt
U manuel/trunk/src/manuel/__init__.py
U manuel/trunk/src/manuel/bugs.txt
U manuel/trunk/src/manuel/doctest.py
U manuel/trunk/src/manuel/testing.py
-=-
Modified: manuel/trunk/CHANGES.txt
===================================================================
--- manuel/trunk/CHANGES.txt 2009-12-07 19:35:08 UTC (rev 106255)
+++ manuel/trunk/CHANGES.txt 2009-12-07 20:15:04 UTC (rev 106256)
@@ -1,6 +1,13 @@
CHANGES
=======
+1.0.2 (2009-12-07)
+------------------
+
+- fix a bug that caused instances of zope.testin.doctest.Example (and instances
+ of subclasses of the same) to be silently ignored
+
+
1.0.1 (2009-08-31)
------------------
Modified: manuel/trunk/src/manuel/__init__.py
===================================================================
--- manuel/trunk/src/manuel/__init__.py 2009-12-07 19:35:08 UTC (rev 106255)
+++ manuel/trunk/src/manuel/__init__.py 2009-12-07 20:15:04 UTC (rev 106256)
@@ -1,5 +1,6 @@
import imp
import re
+import sys
# constants for use with "timing" decorator
EARLY = 'early'
@@ -22,7 +23,21 @@
return decorate
+def normalize_module_path(module_path):
+ if module_path.endswith('.pyc'):
+ module_path = module_path[:-1]
+ return module_path
+
def absolute_import(name):
+ module_path = normalize_module_path(imp.find_module(name)[1])
+
+ # don't create a new module object if there's already one that we can reuse
+ for module in sys.modules.values():
+ if module is None or not hasattr(module, '__file__'):
+ continue
+ if module_path == normalize_module_path(module.__file__):
+ return module
+
return imp.load_module(name, *imp.find_module(name))
Modified: manuel/trunk/src/manuel/bugs.txt
===================================================================
--- manuel/trunk/src/manuel/bugs.txt 2009-12-07 19:35:08 UTC (rev 106255)
+++ manuel/trunk/src/manuel/bugs.txt 2009-12-07 20:15:04 UTC (rev 106256)
@@ -17,7 +17,7 @@
>>> source = """\
... Blah, blah.
- ...
+ ...
... xxx
... some text
... xxx
@@ -29,3 +29,65 @@
>>> start = end = re.compile(r'^xxx$', re.MULTILINE)
>>> document.find_regions(start, end)
[<manuel.Region object at ...]
+
+
+Doctest Doppelganger
+--------------------
+
+The manuel.doctest module should be willing to run doctest Examples from either
+the standard library's doctest module, from zope.testing.doctest, or from
+subclasses of those.
+
+Here's a failing test we'll use to make sure this works::
+
+ This is my failing doctest.
+
+ >>> 1 + 1
+ 42
+
+.. -> source
+
+ >>> document = manuel.Document(source)
+
+First we'll show that it fails using the normal Manuel pieces.
+
+ >>> m = manuel.doctest.Manuel()
+ >>> document.process_with(m, globs={})
+ >>> print document.formatted(),
+ File "<memory>", line 3, in <memory>
+ Failed example:
+ 1 + 1
+ Expected:
+ 42
+ Got:
+ 2
+
+Now we'll create a subclass of zope.testing.doctest.Example, it should work too
+(but didn't at one point).
+
+.. code-block: python
+
+ import zope.testing.doctest
+
+ class MyExample(zope.testing.doctest.Example):
+ pass
+
+Now if we replace the stdlib doctest.Example in the parsed document, the
+failure is still reported.
+
+ >>> my_example = MyExample('2+2', '88')
+ >>> region = list(document)[1]
+ >>> region.parsed = my_example
+ >>> region.evaluated = None
+ >>> region.formatted = None
+ >>> manuel.doctest.evaluate(m, region, document, {})
+ >>> print region.evaluated.getvalue()
+ <BLANKLINE>
+ File "<memory>", line 3, in <memory>
+ Failed example:
+ 2+2
+ Expected:
+ 88
+ Got:
+ 4
+ <BLANKLINE>
Modified: manuel/trunk/src/manuel/doctest.py
===================================================================
--- manuel/trunk/src/manuel/doctest.py 2009-12-07 19:35:08 UTC (rev 106255)
+++ manuel/trunk/src/manuel/doctest.py 2009-12-07 20:15:04 UTC (rev 106256)
@@ -1,10 +1,11 @@
import StringIO
import manuel
import os.path
+import zope.testing.doctest
doctest = manuel.absolute_import('doctest')
-#from zope.testing import doctest
+
class DocTestResult(StringIO.StringIO):
pass
@@ -44,8 +45,12 @@
def evaluate(m, region, document, globs):
- if not isinstance(region.parsed, doctest.Example):
+ # If the parsed object is not a doctest Example (from either the stdlib
+ # doctest or zope.testing.doctest), then we don't need to handle it.
+ if not isinstance(region.parsed, doctest.Example) \
+ and not isinstance(region.parsed, zope.testing.doctest.Example):
return
+
result = DocTestResult()
test_name = os.path.split(document.location)[1]
if m.debug:
Modified: manuel/trunk/src/manuel/testing.py
===================================================================
--- manuel/trunk/src/manuel/testing.py 2009-12-07 19:35:08 UTC (rev 106255)
+++ manuel/trunk/src/manuel/testing.py 2009-12-07 20:15:04 UTC (rev 106256)
@@ -2,10 +2,8 @@
import manuel
import os.path
import unittest
+import zope.testing.doctest
-#doctest = manuel.absolute_import('doctest')
-from zope.testing import doctest
-
__all__ = ['TestSuite']
class TestCaseMarker(object):
@@ -38,7 +36,7 @@
results = [r.formatted for r in self.regions if r.formatted]
if results:
DIVIDER = '-'*70 + '\n'
- raise doctest.DocTestFailureException(
+ raise zope.testing.doctest.DocTestFailureException(
'\n' + DIVIDER + DIVIDER.join(results))
def debug(self):
@@ -132,7 +130,8 @@
# walk up the stack frame to find the module that called this function
for depth in range(2, 5):
try:
- calling_module = doctest._normalize_module(None, depth=depth)
+ calling_module = zope.testing.doctest._normalize_module(
+ None, depth=depth)
except KeyError:
continue
else:
@@ -143,7 +142,8 @@
abs_path = os.path.normpath(path)
else:
abs_path = os.path.abspath(
- doctest._module_relative_path(calling_module, path))
+ zope.testing.doctest._module_relative_path(
+ calling_module, path))
document = manuel.Document(open(abs_path).read(), location=abs_path)
document.parse_with(m)
More information about the checkins
mailing list