* 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 * sphinx.ext.doctest: Make the group in which doctest blocks are
placed selectable, and default to ``'default'``. 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 Release 0.1.61611
================= =================

View File

@ -65,6 +65,10 @@ names.
explicit flags per example, with doctest comments, but they will show up in explicit flags per example, with doctest comments, but they will show up in
other builders too.) 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] .. directive:: .. testcode:: [group]

View File

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

View File

@ -28,10 +28,15 @@ except NameError:
def prepare_docstring(s): 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(): if not s or s.isspace():
return [''] return ['']
nl = s.rstrip().find('\n') nl = s.expandtabs().rstrip().find('\n')
if nl == -1: if nl == -1:
# Only one line... # Only one line...
return [s.strip(), ''] return [s.strip(), '']

View File

@ -10,6 +10,7 @@
:license: BSD. :license: BSD.
""" """
import re
import sys import sys
import time import time
import StringIO import StringIO
@ -23,6 +24,8 @@ from docutils.parsers.rst import directives
from sphinx.builder import Builder from sphinx.builder import Builder
from sphinx.util.console import bold from sphinx.util.console import bold
blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE)
# set up the necessary directives # 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 # use ordinary docutils nodes for test code: they get special attributes
# so that our builder recognizes them, and the other builders are happy. # so that our builder recognizes them, and the other builders are happy.
code = '\n'.join(content) 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 nodetype = nodes.literal_block
if name == 'testsetup' or 'hide' in options: if name == 'testsetup' or 'hide' in options:
nodetype = nodes.comment nodetype = nodes.comment
node = nodetype(code, code)
node.line = lineno
if arguments: if arguments:
groups = [x.strip() for x in arguments[0].split(',')] groups = [x.strip() for x in arguments[0].split(',')]
else: else:
groups = ['default'] groups = ['default']
node['testnodetype'] = name node = nodetype(code, code, testnodetype=name, groups=groups)
node['groups'] = groups node.line = lineno
if test is not None:
# only save if it differs from code
node['test'] = test
if name == 'testoutput': if name == 'testoutput':
# don't try to highlight output # don't try to highlight output
node['language'] = 'none' node['language'] = 'none'
@ -215,7 +224,7 @@ Doctest summary
return isinstance(node, (nodes.literal_block, nodes.comment)) \ return isinstance(node, (nodes.literal_block, nodes.comment)) \
and node.has_key('testnodetype') and node.has_key('testnodetype')
for node in doctree.traverse(condition): 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'), type=node.get('testnodetype', 'doctest'),
lineno=node.line, options=node.get('options')) lineno=node.line, options=node.get('options'))
node_groups = node.get('groups', ['default']) node_groups = node.get('groups', ['default'])
@ -281,7 +290,9 @@ Doctest summary
self.type = 'single' # ordinary doctests self.type = 'single' # ordinary doctests
else: else:
output = code[1] and code[1].code or '' 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, example = doctest.Example(code[0].code, output,
lineno=code[0].lineno, lineno=code[0].lineno,
options=options) options=options)