Skip to content

Commit

Permalink
Close sphinx-doc#6698: doctest: Add :trim-flags: and :no-trim-flags: …
Browse files Browse the repository at this point in the history
…options

To control trimming doctest flags manually, this adds new options
:trim-flags: and :no-trim-flags: to doctest directives.  It helps
to describes doctest module itself in python doc (see sphinx-doc#6698).
  • Loading branch information
tk0miya committed Aug 1, 2020
1 parent 2644199 commit c2dd300
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -34,6 +34,8 @@ Features added
* #7840: i18n: Optimize the dependencies check on bootstrap
* #5208: linkcheck: Support checks for local links
* #5090: setuptools: Link verbosity to distutils' -v and -q option
* #6698: doctest: Add ``:trim-flags:`` and ``:no-trim-flags:`` options to
doctest, testcode and testoutput directives
* #7052: add ``:noindexentry:`` to the Python, C, C++, and Javascript domains.
Update the documentation to better reflect the relationship between this option
and the ``:noindex:`` option.
Expand Down
21 changes: 18 additions & 3 deletions doc/usage/extensions/doctest.rst
Expand Up @@ -67,7 +67,7 @@ a comma-separated list of group names.
default set of flags is specified by the :confval:`doctest_default_flags`
configuration variable.

This directive supports three options:
This directive supports five options:

* ``hide``, a flag option, hides the doctest block in other builders. By
default it is shown as a highlighted doctest block.
Expand Down Expand Up @@ -102,6 +102,11 @@ a comma-separated list of group names.

Supported PEP-440 operands and notations

* ``trim-flags`` and ``no-trim-flags``, a flag option, doctest flags
(comments looking like ``# doctest: FLAG, ...``) at the ends of lines
and ``<BLANKLINE>`` markers are removed (or not removed) individually.
Default is ``trim-flags``.

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.).
Expand All @@ -119,11 +124,16 @@ a comma-separated list of group names.
A code block for a code-output-style test.

This directive supports one option:
This directive supports three options:

* ``hide``, a flag option, hides the code block in other builders. By
default it is shown as a highlighted code block.

* ``trim-flags`` and ``no-trim-flags``, a flag option, doctest flags
(comments looking like ``# doctest: FLAG, ...``) at the ends of lines
and ``<BLANKLINE>`` markers are removed (or not removed) individually.
Default is ``trim-flags``.

.. note::

Code in a ``testcode`` block is always executed all at once, no matter how
Expand All @@ -149,14 +159,19 @@ a comma-separated list of group names.
The corresponding output, or the exception message, for the last
:rst:dir:`testcode` block.

This directive supports two options:
This directive supports four options:

* ``hide``, a flag option, hides the output block in other builders. By
default it is shown as a literal block without highlighting.

* ``options``, a string option, can be used to give doctest flags
(comma-separated) just like in normal doctest blocks.

* ``trim-flags`` and ``no-trim-flags``, a flag option, doctest flags
(comments looking like ``# doctest: FLAG, ...``) at the ends of lines
and ``<BLANKLINE>`` markers are removed (or not removed) individually.
Default is ``trim-flags``.

Example::

.. testcode::
Expand Down
12 changes: 11 additions & 1 deletion sphinx/ext/doctest.py
Expand Up @@ -91,7 +91,7 @@ def run(self) -> List[Node]:
# convert <BLANKLINE>s to ordinary blank lines for presentation
test = code
code = blankline_re.sub('', code)
if doctestopt_re.search(code):
if doctestopt_re.search(code) and 'no-trim-flags' not in self.options:
if not test:
test = code
code = doctestopt_re.sub('', code)
Expand Down Expand Up @@ -151,6 +151,10 @@ def run(self) -> List[Node]:
line=self.lineno)
if 'skipif' in self.options:
node['skipif'] = self.options['skipif']
if 'trim-flags' in self.options:
node['trim_flags'] = True
elif 'no-trim-flags' in self.options:
node['trim_flags'] = False
return [node]


Expand All @@ -165,26 +169,32 @@ class TestcleanupDirective(TestDirective):
class DoctestDirective(TestDirective):
option_spec = {
'hide': directives.flag,
'no-trim-flags': directives.flag,
'options': directives.unchanged,
'pyversion': directives.unchanged_required,
'skipif': directives.unchanged_required,
'trim-flags': directives.flag,
}


class TestcodeDirective(TestDirective):
option_spec = {
'hide': directives.flag,
'no-trim-flags': directives.flag,
'pyversion': directives.unchanged_required,
'skipif': directives.unchanged_required,
'trim-flags': directives.flag,
}


class TestoutputDirective(TestDirective):
option_spec = {
'hide': directives.flag,
'no-trim-flags': directives.flag,
'options': directives.unchanged,
'pyversion': directives.unchanged_required,
'skipif': directives.unchanged_required,
'trim-flags': directives.flag,
}


Expand Down
13 changes: 6 additions & 7 deletions sphinx/transforms/post_transforms/code.py
Expand Up @@ -9,10 +9,10 @@
"""

import sys
from typing import Any, Dict, List, NamedTuple, Union
from typing import Any, Dict, List, NamedTuple

from docutils import nodes
from docutils.nodes import Node
from docutils.nodes import Node, TextElement
from pygments.lexers import PythonConsoleLexer, guess_lexer

from sphinx import addnodes
Expand Down Expand Up @@ -93,18 +93,17 @@ class TrimDoctestFlagsTransform(SphinxTransform):
default_priority = HighlightLanguageTransform.default_priority + 1

def apply(self, **kwargs: Any) -> None:
if not self.config.trim_doctest_flags:
return

for lbnode in self.document.traverse(nodes.literal_block): # type: nodes.literal_block
if self.is_pyconsole(lbnode):
self.strip_doctest_flags(lbnode)

for dbnode in self.document.traverse(nodes.doctest_block): # type: nodes.doctest_block
self.strip_doctest_flags(dbnode)

@staticmethod
def strip_doctest_flags(node: Union[nodes.literal_block, nodes.doctest_block]) -> None:
def strip_doctest_flags(self, node: TextElement) -> None:
if not node.get('trim_flags', self.config.trim_doctest_flags):
return

source = node.rawsource
source = doctest.blankline_re.sub('', source)
source = doctest.doctestopt_re.sub('', source)
Expand Down
14 changes: 13 additions & 1 deletion tests/roots/test-trim_doctest_flags/index.rst
Expand Up @@ -22,7 +22,19 @@ test-trim_doctest_flags
>>> datetime.date.now() # doctest: +QUX
datetime.date(2008, 1, 1)

.. doctest_block::
.. doctest::

>>> datetime.date.now() # doctest: +QUUX
datetime.date(2008, 1, 1)

.. doctest::
:trim-flags:

>>> datetime.date.now() # doctest: +CORGE
datetime.date(2008, 1, 1)

.. doctest::
:no-trim-flags:

>>> datetime.date.now() # doctest: +GRAULT
datetime.date(2008, 1, 1)
19 changes: 19 additions & 0 deletions tests/test_transforms_post_transforms_code.py
Expand Up @@ -19,6 +19,23 @@ def test_trim_doctest_flags_html(app, status, warning):
assert 'BAZ' not in result
assert 'QUX' not in result
assert 'QUUX' not in result
assert 'CORGE' not in result
assert 'GRAULT' in result


@pytest.mark.sphinx('html', testroot='trim_doctest_flags',
confoverrides={'trim_doctest_flags': False})
def test_trim_doctest_flags_disabled(app, status, warning):
app.build()

result = (app.outdir / 'index.html').read_text()
assert 'FOO' in result
assert 'BAR' in result
assert 'BAZ' in result
assert 'QUX' in result
assert 'QUUX' not in result
assert 'CORGE' not in result
assert 'GRAULT' in result


@pytest.mark.sphinx('latex', testroot='trim_doctest_flags')
Expand All @@ -31,3 +48,5 @@ def test_trim_doctest_flags_latex(app, status, warning):
assert 'BAZ' not in result
assert 'QUX' not in result
assert 'QUUX' not in result
assert 'CORGE' not in result
assert 'GRAULT' in result

0 comments on commit c2dd300

Please sign in to comment.