Commits

Anonymous committed 8c3031a

* sphinx.ext.doctest: Replace <BLANKLINE> in doctest blocks by
real blank lines for presentation output.
* sphinx.environment: Move doctest_blocks out of block_quotes to
support indented doctest blocks.

Comments (0)

Files changed (5)

 * sphinx.ext.doctest: Make the group in which doctest blocks are
   placed selectable, and default to ``'default'``.
 
+* sphinx.ext.doctest: Replace <BLANKLINE> in doctest blocks by
+  real blank lines for presentation output.
+
+* sphinx.environment: Move doctest_blocks out of block_quotes to
+  support indented doctest blocks.
+
 
 Release 0.1.61611
 =================

doc/ext/doctest.rst

      explicit flags per example, with doctest comments, but they will show up in
      other builders too.)
 
+   Note that like with standard doctests, you have to use ``<BLANKLINE>`` to
+   signal a blank line in the expected output.  The ``<BLANKLINE>`` is removed
+   when building presentation output (HTML, LaTeX etc.).
+
 
 .. directive:: .. testcode:: [group]
 

sphinx/environment.py

                 node.parent.remove(node)
 
 
+class HandleCodeBlocks(Transform):
+    """
+    Move doctest blocks out of blockquotes and connect adjacent code blocks.
+    """
+    default_priority = 210
+
+    def apply(self):
+        for node in self.document.traverse(nodes.block_quote):
+            if len(node.children) == 1 and isinstance(node.children[0],
+                                                      nodes.doctest_block):
+                node.replace_self(node.children[0])
+        for node in self.document.traverse(nodes.literal_block):
+            if not node.parent:
+                continue
+            idx = node.parent.index(node)
+            try:
+                while isinstance(node.parent[idx+1], nodes.literal_block):
+                    node.children[0] += '\n' + node.parent[idx+1].children[0]
+                    import pdb; pdb.set_trace()
+                    node.parent[idx+1].parent = None
+                    del node.parent[idx+1]
+            except IndexError:
+                continue
+
+
 class MyStandaloneReader(standalone.Reader):
     """
     Add our own transforms.
     def get_transforms(self):
         tf = standalone.Reader.get_transforms(self)
         return tf + [DefaultSubstitutions, MoveModuleTargets,
-                     FilterMessages]
+                     FilterMessages, HandleCodeBlocks]
 
 
 class MyContentsFilter(ContentsFilter):

sphinx/ext/autodoc.py

 
 
 def prepare_docstring(s):
-    """Convert a docstring into lines of parseable reST."""
+    """
+    Convert a docstring into lines of parseable reST.  Return it as a list of
+    lines usable for inserting into a docutils ViewList (used as argument
+    of nested_parse().)  An empty line is added to act as a separator between
+    this docstring and following content.
+    """
     if not s or s.isspace():
         return ['']
-    nl = s.rstrip().find('\n')
+    nl = s.expandtabs().rstrip().find('\n')
     if nl == -1:
         # Only one line...
         return [s.strip(), '']

sphinx/ext/doctest.py

     :license: BSD.
 """
 
+import re
 import sys
 import time
 import StringIO
 from sphinx.builder import Builder
 from sphinx.util.console import bold
 
+blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE)
+
 
 # set up the necessary directives
 
     # use ordinary docutils nodes for test code: they get special attributes
     # so that our builder recognizes them, and the other builders are happy.
     code = '\n'.join(content)
+    test = None
+    if name == 'doctest' and '<BLANKLINE>' in code:
+        # convert <BLANKLINE>s to ordinary blank lines for presentation
+        test = code
+        code = blankline_re.sub('', code)
     nodetype = nodes.literal_block
     if name == 'testsetup' or 'hide' in options:
         nodetype = nodes.comment
-    node = nodetype(code, code)
-    node.line = lineno
     if arguments:
         groups = [x.strip() for x in arguments[0].split(',')]
     else:
         groups = ['default']
-    node['testnodetype'] = name
-    node['groups'] = groups
+    node = nodetype(code, code, testnodetype=name, groups=groups)
+    node.line = lineno
+    if test is not None:
+        # only save if it differs from code
+        node['test'] = test
     if name == 'testoutput':
         # don't try to highlight output
         node['language'] = 'none'
                 return isinstance(node, (nodes.literal_block, nodes.comment)) \
                         and node.has_key('testnodetype')
         for node in doctree.traverse(condition):
-            code = TestCode(node.astext(),
+            code = TestCode(node.has_key('test') and node['test'] or node.astext(),
                             type=node.get('testnodetype', 'doctest'),
                             lineno=node.line, options=node.get('options'))
             node_groups = node.get('groups', ['default'])
                 self.type = 'single' # ordinary doctests
             else:
                 output = code[1] and code[1].code or ''
-                options = code[1] and code[1].options or None
+                options = code[1] and code[1].options or {}
+                # disable <BLANKLINE> processing as it is not needed
+                options[doctest.DONT_ACCEPT_BLANKLINE] = True
                 example = doctest.Example(code[0].code, output,
                                           lineno=code[0].lineno,
                                           options=options)