Skip to content

Commit

Permalink
Merge pull request #281 from bsipocz/doctest-remote-data-all
Browse files Browse the repository at this point in the history
ENH: adding doctest-remote-data-all directive
  • Loading branch information
pllim authored Jan 24, 2025
2 parents d620c96 + a7213fb commit 5e1a479
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
doctests in narrative documentations based on availability of
dependencies. [#280]

- Adding new directive ``doctest-remote-data-all`` to conditionally skip all
doctests in narrative documentations based on availability of
remote-data. [#281]

- Versions of Python <3.9 are no longer supported. [#274]

1.3.0 (2024-11-25)
Expand Down
20 changes: 16 additions & 4 deletions pytest_doctestplus/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,9 @@ class DocTestParserPlus(doctest.DocTestParser):
- ``.. doctest-remote-data::``: Skip the next doctest chunk if
--remote-data is not passed.
- ``.. doctest-remote-data-all::``: Skip all subsequent doctest
chunks if --remote-data is not passed.
"""

def parse(self, s, name=None):
Expand Down Expand Up @@ -429,15 +432,24 @@ def parse(self, s, name=None):
required_all = []
skip_next = False
lines = entry.strip().splitlines()

requires_all_match = [re.match(
fr'{comment_char}\s+doctest-requires-all\s*::\s+(.*)', x) for x in lines]
if any(requires_all_match):
required_all = [re.split(r'\s*[,\s]\s*', match.group(1)) for match in requires_all_match if match][0]

required_all = [re.split(r'\s*[,\s]\s*', match.group(1))
for match in requires_all_match if match][0]
required_modules_all = DocTestFinderPlus.check_required_modules(required_all)
if not required_modules_all:
skip_all = True
continue

if config.getoption('remote_data', 'none') != 'any':
if any(re.match(fr'{comment_char}\s+doctest-remote-data-all\s*::', x.strip())
for x in lines):
skip_all = True
continue

if any(re.match(
f'{comment_char} doctest-skip-all', x.strip()) for x in lines) or not required_modules_all:
if any(re.match(f'{comment_char} doctest-skip-all', x.strip()) for x in lines):
skip_all = True
continue

Expand Down
1 change: 1 addition & 0 deletions pytest_doctestplus/sphinx/doctestplus.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def setup(app):
app.add_directive('doctest-skip-all', DoctestSkipDirective)
app.add_directive('doctest', DoctestSkipDirective, override=True)
app.add_directive('doctest-remote-data', DoctestSkipDirective)
app.add_directive('doctest-remote-data-all', DoctestSkipDirective)
# Code blocks that use this directive will not appear in the generated
# documentation. This is intended to hide boilerplate code that is only
# useful for testing documentation using doctest, but does not actually
Expand Down
17 changes: 17 additions & 0 deletions tests/docs/skip_some_remote_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,20 @@ This should be skipped otherwise the test should fail::
3
>>> import warnings
>>> warnings.warn('A warning occurred', UserWarning) # doctest: +IGNORE_WARNINGS


Remote data all followed by code cell
=====================================

This codeblock should fail, but is skipped:

.. doctest-remote-data-all::

>>> 1 + 1
3

The this following block should be executed with the simple remote data, but
should be skipped with the all version.

>>> 1 + 2
5
35 changes: 35 additions & 0 deletions tests/test_doctestplus.py
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,41 @@ def test_doctest_skip(testdir):
testdir.inline_run(p, '--doctest-plus', '--doctest-rst').assertoutcome(skipped=1)


def test_remote_data_all(testdir):
testdir.makeini(
"""
[pytest]
doctestplus = enabled
""")

p = testdir.makefile(
'.rst',
"""
This is a narrative docs, which some of the lines requiring remote-data access.
The first code block always passes, the second is skipped without remote data and the
last section is skipped due to the all option.
>>> print("Test")
Test
.. doctest-remote-data-all::
>>> from contextlib import closing
>>> from urllib.request import urlopen
>>> with closing(urlopen('https://www.astropy.org')) as remote:
... remote.read() # doctest: +IGNORE_OUTPUT
Narrative before a codeblock that should fail normally but with the all option in the
directive it is skipped over thus producing a passing status.
>>> print(123)
"""
)

testdir.inline_run(p, '--doctest-plus', '--doctest-rst', '--remote-data').assertoutcome(failed=1)
testdir.inline_run(p, '--doctest-plus', '--doctest-rst').assertoutcome(passed=1)


# We repeat all testst including remote data with and without it opted in
def test_remote_data_url(testdir):
testdir.makeini(
Expand Down

0 comments on commit 5e1a479

Please sign in to comment.