* 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.
This commit is contained in:
Georg Brandl 2008-03-22 21:10:35 +00:00
parent fa089ae583
commit b82b162729
5 changed files with 60 additions and 9 deletions

View File

@ -4,6 +4,12 @@ Changes in trunk
* 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
=================

View File

@ -65,6 +65,10 @@ names.
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]

View File

@ -129,6 +129,31 @@ class MoveModuleTargets(Transform):
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.
@ -136,7 +161,7 @@ class MyStandaloneReader(standalone.Reader):
def get_transforms(self):
tf = standalone.Reader.get_transforms(self)
return tf + [DefaultSubstitutions, MoveModuleTargets,
FilterMessages]
FilterMessages, HandleCodeBlocks]
class MyContentsFilter(ContentsFilter):

View File

@ -28,10 +28,15 @@ except NameError:
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(), '']

View File

@ -10,6 +10,7 @@
:license: BSD.
"""
import re
import sys
import time
import StringIO
@ -23,6 +24,8 @@ from docutils.parsers.rst import directives
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
@ -31,17 +34,23 @@ def test_directive(name, arguments, options, content, lineno,
# 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'
@ -215,7 +224,7 @@ Doctest summary
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'])
@ -281,7 +290,9 @@ Doctest summary
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)