mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
* 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:
parent
fa089ae583
commit
b82b162729
6
CHANGES
6
CHANGES
@ -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
|
||||||
=================
|
=================
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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(), '']
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user