[Checkins] SVN: manuel/trunk/ - many more docs updates

Benji York benji at zope.com
Fri Jun 19 17:55:17 EDT 2009


Log message for revision 101155:
  - many more docs updates
  - bug fixes
  

Changed:
  U   manuel/trunk/buildout.cfg
  A   manuel/trunk/src/getting-started.txt
  U   manuel/trunk/src/index.txt
  U   manuel/trunk/src/intro.txt
  U   manuel/trunk/src/manuel/README.txt
  U   manuel/trunk/src/manuel/__init__.py
  U   manuel/trunk/src/manuel/bugs.txt
  U   manuel/trunk/src/manuel/codeblock.py
  U   manuel/trunk/src/manuel/codeblock.txt
  A   manuel/trunk/src/manuel/doctest.txt
  U   manuel/trunk/src/manuel/footnote.txt
  A   manuel/trunk/src/manuel/ignore.py
  A   manuel/trunk/src/manuel/ignore.txt
  U   manuel/trunk/src/manuel/isolation.txt
  U   manuel/trunk/src/manuel/table-example.txt
  U   manuel/trunk/src/manuel/testing.py
  U   manuel/trunk/src/manuel/tests.py

-=-
Modified: manuel/trunk/buildout.cfg
===================================================================
--- manuel/trunk/buildout.cfg	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/buildout.cfg	2009-06-19 21:55:17 UTC (rev 101155)
@@ -58,4 +58,4 @@
 zc.recipe.egg = 1.2.2
 zc.recipe.testrunner = 1.2.0
 zope.interface = 3.5.1
-zope.testing = 3.7.4
+zope.testing = 3.7.5

Added: manuel/trunk/src/getting-started.txt
===================================================================
--- manuel/trunk/src/getting-started.txt	                        (rev 0)
+++ manuel/trunk/src/getting-started.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -0,0 +1,56 @@
+Getting Started
+===============
+
+The simplest way to get started with Manuel is to create a script to run your
+tests, like so:
+
+.. code-block:: python
+
+    import manuel.codeblock
+    import manuel.doctest
+    import manuel.testing
+    import unittest
+
+    def test_suite():
+        m = manuel.doctest.Manuel()
+        m.extend(manuel.codeblock.Manuel())
+        return manuel.testing.TestSuite(m, 'test-one.txt', 'test-two.txt')
+
+    if __name__ == '__main__':
+        unittest.TextTestRunner().run(test_suite())
+
+
+Using zope.testing
+------------------
+
+If you want to use zope.testing's test runner (usable stand-alone, it isn't
+dependent on the Zope application server), you can add Manuel tests to the
+TestSuite objects you're already creating.
+
+.. code-block:: python
+
+    import manuel.codeblock
+    import manuel.doctest
+    import manuel.testing
+
+    def test_suite():
+        suite = unittest.TestSuite()
+
+        # here you add your other tests to the suite...
+
+        # now you can add the Manuel tests
+        m = manuel.doctest.Manuel()
+        m.extend(manuel.codeblock.Manuel())
+        suite.addTest(manuel.testing.TestSuite(m,
+            'test-one.txt', 'test-two.txt'))
+
+        return suite
+
+
+Others
+------
+
+If you know how to make Manuel work with other test runners, please `send me an
+email`_.
+
+.. _send me an email: benji+manuel at benjiyork.com


Property changes on: manuel/trunk/src/getting-started.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: manuel/trunk/src/index.txt
===================================================================
--- manuel/trunk/src/index.txt	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/index.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -7,9 +7,12 @@
     :numbered:
 
     intro.txt
-    manuel/README.txt
-    manuel/table-example.txt
+    getting-started.txt
     manuel/codeblock.txt
+    manuel/doctest.txt
     manuel/footnote.txt
+    manuel/ignore.txt
     manuel/isolation.txt
+    manuel/README.txt
+    manuel/table-example.txt
     manuel/bugs.txt

Modified: manuel/trunk/src/intro.txt
===================================================================
--- manuel/trunk/src/intro.txt	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/intro.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -1,27 +1,35 @@
 Introduction
 ============
 
-Manuel lets you mix and match traditional doctests with new test syntax that
-either you create or comes bundled with Manuel.
+Manuel lets you mix and match traditional doctests with custom test syntax.
 
+Several plug-ins that provide new syntaxes are included.  You can also make
+your own.
+
 For example, if you've ever wanted to include a large chunk of Python in a
 doctest but were irritated by all the ">>>" and "..." prompts required, you'd
-like the "manuel.codeblock" module.  It lets you execute code using
-Sphinx-style "..  code-block:: python" directives, like so:
+like the :mod:`manuel.codeblock` module.  It lets you execute code using
+Sphinx-style "..  code-block:: python" directives.  The markup looks like
+this::
 
-.. code-block:: python
+    .. code-block:: python
 
-    import foo
+        import foo
 
-    def my_func(bar):
-        return foo.baz(bar)
+        def my_func(bar):
+            return foo.baz(bar)
 
-Incidentally, the implementation of manuel.codeblock is only 24 lines of code.
+Incidentally, the implementation of :mod:`manuel.codeblock` is only 22 lines of
+code.
 
-For an example of creating your own test syntax, take a look at the
+For a large example of creating test syntax, take a look at the
 :ref:`fit-table-example` or for all the details, :ref:`theory-of-operation`.
 
+Also, the plug-ins included in Manuel make good examples while being quite
+useful in their own right.  All the included plug-ins are listed in the next
+section.
 
+
 Included Functionality
 ======================
 
@@ -30,15 +38,15 @@
 :ref:`manuel.codeblock <code-blocks>`
     executes code in ".. code-block:: python" blocks
 
+:ref:`manuel.doctest <doctest>`
+    provides traditional doctest processing as a Manuel plug-in
+
 :ref:`manuel.footnote <footnotes>`
     executes code in reST-style footnodes each time they're referenced (good
     for getting incedental code out of the main flow of a document)
 
+:ref:`manuel.ignore <ignore>`
+    ignores parts of a document while running tests
+
 :ref:`manuel.isolation <isolation>`
     makes it easier to have test isolation in doctests
-
-
-Getting Started
-===============
-
-If you already have XXX

Modified: manuel/trunk/src/manuel/README.txt
===================================================================
--- manuel/trunk/src/manuel/README.txt	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/README.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -4,7 +4,7 @@
 ===================
 
 Manuel parses documents (tests), evaluates their contents, then formats the
-result of the evaluation.  The functionality is accessed via the "manuel"
+result of the evaluation.  The functionality is accessed via the :mod:`manuel`
 package.
 
     >>> import manuel
@@ -93,11 +93,6 @@
 
 .. more "whole-line" tests.
 
-    >>> document.find_regions('three')
-    Traceback (most recent call last):
-        ...
-    ValueError: Regions must end at the ending of a line.
-
     >>> document.find_regions(
     ...     re.compile('ne:.*$', re.MULTILINE),
     ...     re.compile('^one:.*$', re.MULTILINE),
@@ -106,14 +101,6 @@
         ...
     ValueError: Regions must start at the begining of a line.
 
-    >>> document.find_regions(
-    ...     re.compile('^one:.*$', re.MULTILINE),
-    ...     re.compile('^three:', re.MULTILINE),
-    ...     )
-    Traceback (most recent call last):
-        ...
-    ValueError: Regions must end at the ending of a line.
-
 Now we can register a parser that will identify the regions we're interested in
 and create NumbersTest objects from the source text.
 
@@ -176,7 +163,7 @@
 ----------
 
 Once the evaluation phase is completed the results are formatted.  You guessed
-it: manuel provides a method for formatting results.  We'll build one to format
+it: Manuel provides a method for formatting results.  We'll build one to format
 a message about whether or not our lists of numbers are sorted properly.  A
 formatting function returns None when it has no output, or a string otherwise.
 
@@ -224,8 +211,8 @@
     ... """
     >>> document = manuel.Document(source)
 
-The manuel.doctest module has handlers for the various phases.  First we'll
-look at parsing.
+The :mod:`manuel.doctest` module has handlers for the various phases.  First
+we'll look at parsing.
 
     >>> import manuel.doctest
     >>> m = manuel.doctest.Manuel()
@@ -309,7 +296,7 @@
 Combining Test Types
 --------------------
 
-Now that we have both doctests and the silly "sorted numbers" tests, lets
+Now that we have both doctests and the silly "sorted numbers" tests, let's
 create a single document that has both.
 
     >>> document = manuel.Document("""
@@ -453,8 +440,8 @@
                 region.evaluated.write('Additional Information:')
                 region.evaluated.write(info)
 
-To do that we'll start with an instance of manuel.doctest.Manuel and add in our
-additional functionality.
+To do that we'll start with an instance of :mod:`manuel.doctest.Manuel` and add
+in our additional functionality.
 
     >>> m = manuel.doctest.Manuel()
     >>> m.add_evaluater(informative_evaluater)
@@ -522,7 +509,7 @@
         b = 2
         c = 3
 
-Instead of a text-based apprach, lets use the built-in tokenize module to more
+Instead of a text-based apprach, let's use the built-in tokenize module to more
 robustly identify referenced variables.
 
     >>> import StringIO

Modified: manuel/trunk/src/manuel/__init__.py
===================================================================
--- manuel/trunk/src/manuel/__init__.py	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/__init__.py	2009-06-19 21:55:17 UTC (rev 101155)
@@ -70,7 +70,7 @@
 
 def check_region_end(region, match):
     if match.end() != len(region.source) \
-    and region.source[match.end()] != '\n':
+    and region.source[match.end()-1] != '\n':
         raise ValueError(
             'Regions must end at the ending of a line.')
 
@@ -124,6 +124,12 @@
     return sorted(handlers, key=key)
 
 
+def find_end_of_line(s):
+    end = 0
+    while len(s) < end and s[end] != '\n':
+        end += 1
+    return end
+
 class Document(object):
 
     def __init__(self, source, location='<memory>'):
@@ -155,7 +161,7 @@
 
                 if end is None:
                     end_match = None
-                    check_region_end(region, start_match)
+
                     text = start_match.group()
                 else:
                     end_match = end.search(region.source, start_match.end())
@@ -163,8 +169,9 @@
                     # couldn't find a match for the end re, try again
                     if end_match is None:
                         continue
-                    check_region_end(region, end_match)
-                    text = region.source[start_match.start():end_match.end()]
+                    end_position = end_match.end() + \
+                        find_end_of_line(region.source[end_match.end():])
+                    text = region.source[start_match.start():end_position]
 
                 if text[-1] != '\n':
                     text += '\n'

Modified: manuel/trunk/src/manuel/bugs.txt
===================================================================
--- manuel/trunk/src/manuel/bugs.txt	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/bugs.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -1,6 +1,17 @@
 Fixed Bugs
 ==========
 
+Here are demonstrations of various bugs that have been fixed in Manuel.  If you
+encounter a bug in a previous version of Manuel, check here in the newest
+version to see if your bug has been addressed.
+
+This document is likely only interesting to people using creating their own
+plug-ins.
+
+
+Start and End Coinciding
+------------------------
+
 If a line of text matches both a "start" and "end" regular expression, no
 exception should be raised.
 

Modified: manuel/trunk/src/manuel/codeblock.py
===================================================================
--- manuel/trunk/src/manuel/codeblock.py	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/codeblock.py	2009-06-19 21:55:17 UTC (rev 101155)
@@ -2,16 +2,13 @@
 import manuel
 import textwrap
 
-CODEBLOCK_START = re.compile(
-    r'(?<=\n\n)\.\.\s*code-block::?\s*python\s*\n', re.DOTALL)
+# XXX document code-blocks that are really comments but get executed anyway
+# (perhaps with better syntax)
 
-# XXX document code-blocks that don't get executed and code-blocks that are
-# really comments but get executed anyway (perhaps with better syntax for both)
+CODEBLOCK_START = re.compile(r'^\.\.\s*code-block::?\s*python\b', re.MULTILINE)
+CODEBLOCK_END = re.compile(r'(\n\Z|\n(?=\S))')
 
-# XXX should probably take end-of-file into account
-CODEBLOCK_END = re.compile(r'^\S.*$', re.MULTILINE)
 
-
 class CodeBlock(object):
     def __init__(self, code):
         self.code = code
@@ -19,7 +16,7 @@
 
 def find_code_blocks(document):
     for region in document.find_regions(CODEBLOCK_START, CODEBLOCK_END):
-        source = textwrap.dedent('\n'.join(region.source.splitlines()[1:-1]))
+        source = textwrap.dedent('\n'.join(region.source.splitlines()[1:]))
         source_location = '%s:%d' % (document.location, region.lineno)
         code = compile(source, source_location, 'exec', 0, True)
         document.replace_region(region, CodeBlock(code))
@@ -29,8 +26,7 @@
     if not isinstance(region.parsed, CodeBlock):
         return
 
-    code = region.parsed.code
-    exec code in globs
+    exec region.parsed.code in globs
     del globs['__builtins__'] # exec adds __builtins__, we don't want it
 
 

Modified: manuel/trunk/src/manuel/codeblock.txt
===================================================================
--- manuel/trunk/src/manuel/codeblock.txt	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/codeblock.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -15,13 +15,13 @@
 
         print 'hello'
 
-The manuel.codeblock module provides the ability to execute the contents of
-Python code-blocks.
+The :mod:`manuel.codeblock` module provides the ability to execute the contents
+of Python code-blocks.
 
     >>> import manuel.codeblock
     >>> m = manuel.codeblock.Manuel()
 
-Let's create a reST document with a code block.
+.. Let's create a reST document with a code block.
 
     >>> document = manuel.Document("""
     ... Here is a code-block:
@@ -34,13 +34,83 @@
     ...
     ...     >>> print x
     ...     hello
-    ...     
+    ...
     ... """)
 
-Since the above document mixes code-blocks and doctests, we'll mix in the
-doctest handler.
+.. Since the above document mixes code-blocks and doctests, we'll mix in the
+   doctest handler.
 
     >>> import manuel.doctest
     >>> m.extend(manuel.doctest.Manuel())
     >>> document.process_with(m, globs={})
+
+..  Both code blocks were found (for a total of five regions -- text, block,
+    text, block, and text):
+
+    >>> len(list(document))
+    5
+
+.. We can see that none of the tests in the document failed:
+
     >>> print document.formatted(),
+
+If the code-block generates some sort of error...
+
+    >>> document = manuel.Document("""\
+    ... .. code-block:: python
+    ...
+    ...     print does_not_exist
+    ... """)
+
+.. the document above was specially formulated to have nothing before or after
+   the code-block
+
+    >>> document.source.startswith('.. code-block')
+    True
+    >>> document.source.endswith('print does_not_exist\n')
+    True
+
+...that error will be reported:
+
+    >>> document.process_with(m, globs={})
+    Traceback (most recent call last):
+        ...
+    NameError: name 'does_not_exist' is not defined
+
+If you find that you want to include a code-block in a document but don't want
+Manuel to execute it, use :ref:`manuel.ignore <ignore>` to ignore that
+particular block.
+
+
+Commented-out Blocks
+--------------------
+
+At times you'll want to have a block of code that is executed but not displayed
+in the rendered document (like some setup for later examples).
+
+When using doctest's native format (">>>") that's easy to do, you just put the
+code in a reST comment, like so:
+
+.. ignore-next-block
+
+::
+
+    .. this is some setup, it is hidden in a reST comment
+
+         >>> do_something()
+         >>> do_something_else()
+
+However, if you want to include a relatively large chunk of Python, you'd
+rather use a code-block, but that means that it will be included in the
+rendered document.  Instead, :mod:`manuel.codeblock` also understands a variant
+of the code-block directive (".. code-block:: python") that is actually a reST
+comment: ".. code-block:python" (note the single colon)::
+
+    .. code-block: python
+
+       do_something()
+       do_something_else()
+
+.. warning:: It would be very easy to confuse the "real" code-block directive
+   with the it's-really-a-reSt-comment form.  Perhaps a more distinct syntax
+   will be introduced in the future.

Added: manuel/trunk/src/manuel/doctest.txt
===================================================================
--- manuel/trunk/src/manuel/doctest.txt	                        (rev 0)
+++ manuel/trunk/src/manuel/doctest.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -0,0 +1,50 @@
+.. _doctest:
+
+Doctests
+========
+
+Manuel is all about making testable documents and well-documented tests.  Of
+course, Python's doctest module is a long-standing fixture in that space, so it
+only makes sense for Manuel to support doctest syntax.
+
+Handling doctests is easy:
+
+.. code-block:: python
+
+    import manuel.doctest
+
+    m = manuel.doctest.Manuel()
+    suite = manuel.testing.TestSuite(m, 'my-doctest.txt')
+
+Of course you can mix in other Manuel syntax plug-ins as well (including ones
+you write yourself).
+
+.. code-block:: python
+
+    import manuel.doctest
+    import manuel.codeblock
+
+    m = manuel.doctest.Manuel()
+    m.extend(manuel.codeblock.Manuel())
+    suite = manuel.testing.TestSuite(m, 'my-doctest-with-code-blocks.txt')
+
+The :class:`manuel.doctest.Manuel` constructor also takes :data:`optionflags`
+and :data:`checker` arguments.
+
+.. code-block:: python
+
+    m = manuel.doctest.Manuel(optionflags=optionflags, checker=checker)
+
+See the `doctest documentation <http://docs.python.org/library/doctest.html>`_
+for more information about the `available options
+<http://docs.python.org/library/doctest.html#doctest-options>`_  and `output
+checkers <http://docs.python.org/library/doctest.html#outputchecker-objects>`_
+
+
+.. note:: :mod:`zope.testing.renormalizing` provides an :class:`OutputChecker`
+   for smoothing out differences between actual and expected output for things
+   that are hard to control (like memory addresses and time) using regular
+   expressions.  See the `module's doctests
+   <http://svn.zope.org/zope.testing/trunk/src/zope/testing/renormalizing.py?view=markup>`_
+   for more information on how it works.
+


Property changes on: manuel/trunk/src/manuel/doctest.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: manuel/trunk/src/manuel/footnote.txt
===================================================================
--- manuel/trunk/src/manuel/footnote.txt	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/footnote.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -4,7 +4,7 @@
 Footnotes
 =========
 
-The manuel.footnote module provides an implementation of reST footnote
+The :mod:`manuel.footnote` module provides an implementation of reST footnote
 handling.
 
     >>> import manuel.footnote
@@ -38,17 +38,12 @@
     ...
     ...     >>> raise RuntimeError('nooooo!')
     ... """)
-
     >>> document.process_with(m, globs={})
 
 Since all the examples in the doctest above are correct, we expect no errors.
 
-    >>> for region in document:
-    ...     if region.formatted:
-    ...         print '-'*70
-    ...         print region.formatted,
+    >>> print document.formatted(),
 
-
 The order of examples in footnotes is preserved.  If not, the document below
 will generate an error because "a" won't be defined when "b = a + 1" is
 evaluated.

Added: manuel/trunk/src/manuel/ignore.py
===================================================================
--- manuel/trunk/src/manuel/ignore.py	                        (rev 0)
+++ manuel/trunk/src/manuel/ignore.py	2009-06-19 21:55:17 UTC (rev 101155)
@@ -0,0 +1,17 @@
+import re
+import manuel
+import textwrap
+
+IGNORE_START = re.compile(r'^\.\.\s*ignore-next-block\s*$', re.MULTILINE)
+IGNORE_END = re.compile(r'(?<!ignore-next-block)\n\n(?=\S)|\Z')
+
+baseline = {}
+
+def find_ignores(document):
+    for region in document.find_regions(IGNORE_START, IGNORE_END):
+        document.replace_region(region, None)
+        document.remove_region(region)
+
+class Manuel(manuel.Manuel):
+    def __init__(self):
+        manuel.Manuel.__init__(self, [find_ignores])


Property changes on: manuel/trunk/src/manuel/ignore.py
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native

Added: manuel/trunk/src/manuel/ignore.txt
===================================================================
--- manuel/trunk/src/manuel/ignore.txt	                        (rev 0)
+++ manuel/trunk/src/manuel/ignore.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -0,0 +1,104 @@
+.. _ignore:
+
+Ignoring Blocks
+===============
+
+Occasionally the need arrises to ignore a block of markup that would otherwise
+be parsed by a Manuel plug-in.
+
+For example, this document has a code-block will generate a Syntax error:
+
+    >>> import manuel
+    >>> document = manuel.Document("""
+    ... The following is invalid Python.
+    ...
+    ... .. code-block:: python
+    ...
+    ...     def foo:
+    ...         pass
+    ...
+    ... """)
+
+We can see that when executed, the SyntaxError escapes.
+
+    >>> import manuel.codeblock
+    >>> m = manuel.codeblock.Manuel()
+    >>> document.process_with(m, globs={})
+    Traceback (most recent call last):
+      ...
+      File "<memory>:4", line 2
+         def foo:
+                ^
+    SyntaxError: invalid syntax
+
+The :mod:`manuel.ignore` module provides a way to ignore parts of a document
+using a directive ".. ignore-next-block".
+
+Because Manuel plug-ins are executed in the order they are accumulated, we want
+:mod:`manuel.ignore` to be the base Manuel object, with any others added to it.
+
+.. code-block:: python
+
+    import manuel.ignore
+    import manuel.doctest
+    m = manuel.ignore.Manuel()
+    m.extend(manuel.codeblock.Manuel())
+    m.extend(manuel.doctest.Manuel())
+
+If we add an ignore marker to the block we don't want processed...
+
+.. code-block:: python
+
+    >>> document = manuel.Document("""
+    ... The following is invalid Python.
+    ... 
+    ... .. ignore-next-block
+    ... .. code-block:: python
+    ... 
+    ...     def foo:
+    ...         pass
+    ... """)
+
+...the error goes away.
+
+    >>> document.process_with(m, globs={})
+    >>> print document.formatted(),
+
+
+Ignoring Literal Blocks
+-----------------------
+
+Ignoring literal blocks is a little more involved:
+
+    >>> document = manuel.Document("""
+    ... Here is some invalid Python:
+    ... 
+    ... .. ignore-next-block
+    ... 
+    ... ::
+    ... 
+    ...    >>> lambda: print 'hi'
+    ... """)
+
+.. no need for this bit to be visible in the docs
+
+    >>> document.process_with(m, globs={})
+    >>> print document.formatted(),
+
+.. we want to be very sure that the above example without the ignore actually
+   generates an error:
+
+    >>> document = manuel.Document(document.source.replace(
+    ...     '.. ignore-next-block', ''))
+    >>> document.process_with(m, globs={})
+    >>> print document.formatted(),
+    File "<memory>", line 8, in <memory>
+    Failed example:
+        lambda: print 'hi'
+    Exception raised:
+          ...
+          File "<doctest <memory>[0]>", line 1
+             lambda: print 'hi'
+                         ^
+         SyntaxError: invalid syntax
+


Property changes on: manuel/trunk/src/manuel/ignore.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: manuel/trunk/src/manuel/isolation.txt
===================================================================
--- manuel/trunk/src/manuel/isolation.txt	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/isolation.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -9,21 +9,14 @@
 In large doctests the later tests often depend on incedental details of earlier
 tests, making the tests more brittle and harder to change.
 
-Test isolation is one approach to reducing this intra-doctest coupling.
+Test isolation is one approach to reducing this intra-doctest coupling.  The
+:mod:`manuel.isolation` module provides a plug-in to help.
 
-Because many doctests are also `reST
-<http://docutils.sourceforge.net/rst.html>`_ documents, we'll use the reST
-comment syntax to hide our isolation indicator from any reST renderers::
-
-    .. isolate
-
-The "manuel.isolation" module provides the implementation.
-
     >>> import manuel.isolation
     >>> m = manuel.isolation.Manuel()
 
-All the "isolate" directive does is reset the globals in the test to an
-original setting.  Lets create a Manuel document to test isolation with:
+The ".. reset-globs" directive resets the globals in the test.  Let's create a
+Manuel document to test isolation with:
 
     >>> document = manuel.Document("""
     ... We define a variable.
@@ -47,6 +40,10 @@
 
     >>> import manuel.doctest
     >>> m.extend(manuel.doctest.Manuel())
+
+We can see that after the globals have been reset, the "print x" line raises an
+error.
+
     >>> document.process_with(m, globs={})
     >>> print document.formatted(),
     File "<memory>", line 2, in <memory>
@@ -57,7 +54,7 @@
         NameError: name 'x' is not defined
 
 Of course, resetting to an empty set of global variables isn't always what's
-wanted.  In that case there is a ".. capture-globs" directive that defines a
+wanted.  In that case there is a ".. capture-globs" directive that saves a
 baseline set of globals that will be restored at each reset.
 
 
@@ -91,6 +88,9 @@
     ... ...it will disappear after a reset.
     ...
     ...     >>> print y
+    ...     Traceback (most recent call last):
+    ...         ...
+    ...     NameError: name 'y' is not defined
     ...     
     ... But the captured globals will still be defined.
     ...
@@ -100,9 +100,3 @@
     ... """)
     >>> document.process_with(m, globs={})
     >>> print document.formatted(),
-    File "<memory>", line 4, in <memory>
-    Failed example:
-        print y
-    Exception raised:
-        ...
-        NameError: name 'y' is not defined

Modified: manuel/trunk/src/manuel/table-example.txt
===================================================================
--- manuel/trunk/src/manuel/table-example.txt	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/table-example.txt	2009-06-19 21:55:17 UTC (rev 101155)
@@ -3,6 +3,8 @@
 FIT Table Example
 =================
 
+Here is an example of writing a relatively complex Manuel plug-in.
+
 Occasionally when writing a doctest, you want a better way to express a test
 than doctest by itself provides.
 
@@ -307,7 +309,7 @@
 file named "my-table-tests.txt" we can create a file named tests.py and build a
 TestSuite like so:
 
-.. this next chunk isn't actually executed by tests, so watch out
+.. ignore-next-block
 .. code-block:: python
 
     import unittest

Modified: manuel/trunk/src/manuel/testing.py
===================================================================
--- manuel/trunk/src/manuel/testing.py	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/testing.py	2009-06-19 21:55:17 UTC (rev 101155)
@@ -8,8 +8,6 @@
 
 class TestCase(unittest.TestCase):
 
-    __test__ = False # tell nose not to treat this as a test case
-
     # XXX this is broken, see the unittest.TestCase docstring
     def __init__(self, m, document, setUp=None, tearDown=None, globs=None):
         unittest.TestCase.__init__(self)
@@ -105,5 +103,3 @@
         suite.addTest(TestCase(m, document, **kws))
 
     return suite
-
-TestSuite.__test__ = False # tell nose not to treat this as a test case

Modified: manuel/trunk/src/manuel/tests.py
===================================================================
--- manuel/trunk/src/manuel/tests.py	2009-06-19 20:56:53 UTC (rev 101154)
+++ manuel/trunk/src/manuel/tests.py	2009-06-19 21:55:17 UTC (rev 101155)
@@ -2,6 +2,7 @@
 import manuel
 import manuel.codeblock
 import manuel.doctest
+import manuel.ignore
 import manuel.testing
 import os.path
 import re
@@ -30,23 +31,18 @@
     suite = unittest.TestSuite()
 
     tests = ['README.txt', 'footnote.txt', 'bugs.txt', 'codeblock.txt',
-        'isolation.txt', 'table-example.txt']
+        'isolation.txt', 'table-example.txt', '../getting-started.txt',
+        'ignore.txt']
 
     tests = map(get_abs_path, tests)
 
-    # run the tests with Manuel's doctest support
-    m = manuel.doctest.Manuel(optionflags=optionflags, checker=checker)
-    # add in the codeblock extension
+    m = manuel.ignore.Manuel()
+    m.extend(manuel.doctest.Manuel(optionflags=optionflags, checker=checker))
     m.extend(manuel.codeblock.Manuel())
-    # build the test suite
     suite.addTest(manuel.testing.TestSuite(m, *tests))
 
     return suite
 
-test_suite.__test__ = False # tell nose not to treat this as a test case
 
-def run_tests():
-    unittest.TextTestRunner().run(test_suite())
-
 if __name__ == '__main__':
-    run_tests()
+    unittest.TextTestRunner().run(test_suite())



More information about the Checkins mailing list