From d2b6b0a7ae9f43ede91f8dcd9f7395e6fe174140 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Fri, 7 Nov 2025 14:26:50 +0100 Subject: [PATCH 1/2] BUG: Fix directives that do not have any content The `-all` directives should not take any content. Taking content is now an error. This means that someone who writes: .. ...-skipa-all:: >>> content will now fail in sphinx. Previously the content was expected and then doctestplus choked on expecting content Co-authored-by: Stuart Mumford --- pytest_doctestplus/sphinx/doctestplus.py | 23 +++++++++----- tests/docs/remotedata_all.rst | 20 +++++++++++++ tests/docs/requires_all.rst | 38 ++++++++++++++++++++++++ tests/docs/skip_some_remote_data.rst | 2 ++ tests/test_doctestplus.py | 3 ++ 5 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 tests/docs/remotedata_all.rst create mode 100644 tests/docs/requires_all.rst diff --git a/pytest_doctestplus/sphinx/doctestplus.py b/pytest_doctestplus/sphinx/doctestplus.py index 7600caa..00b80f7 100644 --- a/pytest_doctestplus/sphinx/doctestplus.py +++ b/pytest_doctestplus/sphinx/doctestplus.py @@ -14,6 +14,12 @@ from docutils.parsers.rst import Directive +class NoRunDirective(Directive): + def run(self): + # Simply do not add any content when this directive is encountered + return [] + + class DoctestSkipDirective(Directive): has_content = True @@ -26,13 +32,9 @@ def run(self): return [literal_block(code, code)] -class DoctestOmitDirective(Directive): +class DoctestOmitDirective(NoRunDirective): has_content = True - def run(self): - # Simply do not add any content when this directive is encountered - return [] - class DoctestRequiresDirective(DoctestSkipDirective): # This is silly, but we really support an unbounded number of @@ -40,15 +42,20 @@ class DoctestRequiresDirective(DoctestSkipDirective): optional_arguments = 64 +class DoctestAllDirective(NoRunDirective): + optional_arguments = 64 + has_content = False + + def setup(app): app.add_directive('doctest-requires', DoctestRequiresDirective) - app.add_directive('doctest-requires-all', DoctestRequiresDirective) + app.add_directive('doctest-requires-all', DoctestAllDirective) app.add_directive('doctest-skip', DoctestSkipDirective) - app.add_directive('doctest-skip-all', DoctestSkipDirective) + app.add_directive('doctest-skip-all', DoctestAllDirective) app.add_directive('doctest', DoctestSkipDirective, override=True) app.add_directive('doctest-remote-data', DoctestSkipDirective) - app.add_directive('doctest-remote-data-all', DoctestSkipDirective) + app.add_directive('doctest-remote-data-all', DoctestAllDirective) # 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 diff --git a/tests/docs/remotedata_all.rst b/tests/docs/remotedata_all.rst new file mode 100644 index 0000000..df79e80 --- /dev/null +++ b/tests/docs/remotedata_all.rst @@ -0,0 +1,20 @@ +:orphan: + +.. doctest-remote-data-all:: + +.. _label_to_check_that_no_content_works_probably_unnecessary2: + +Some Bad Test Cases +******************* + +All of the example code blocks in this file are going to fail if they run. So +if the directive used at the top of this file does not work, then there are +going to be test failures. + +Undefined Variables +=================== + +This one will fail because the variables haven't been defined:: + + >>> 2 + 3 + 5 diff --git a/tests/docs/requires_all.rst b/tests/docs/requires_all.rst new file mode 100644 index 0000000..e311f7d --- /dev/null +++ b/tests/docs/requires_all.rst @@ -0,0 +1,38 @@ +:orphan: + +.. doctest-requires-all:: asdfasdfasdf + +.. _label_to_check_that_no_content_works_probably_unnecessary: + +Some Bad Test Cases +******************* + +All of the example code blocks in this file are going to fail if they run. So +if the directive used at the top of this file does not work, then there are +going to be test failures. + +Undefined Variables +=================== + +This one will fail because the variables haven't been defined:: + + >>> x + y + 5 + +No Such Module +============== + +This one will fail because there's (probably) no such module:: + + >>> import foobar + >>> foobar.baz(42) + 0 + +What??? +======= + +This one will fail because it's just not valid python:: + + >>> NOT VALID PYTHON, OKAY? + >>> + 5 + 10 diff --git a/tests/docs/skip_some_remote_data.rst b/tests/docs/skip_some_remote_data.rst index c5e7399..5b9ea64 100644 --- a/tests/docs/skip_some_remote_data.rst +++ b/tests/docs/skip_some_remote_data.rst @@ -87,6 +87,8 @@ This codeblock should fail, but is skipped: .. doctest-remote-data-all:: +.. code-block:: + >>> 1 + 1 3 diff --git a/tests/test_doctestplus.py b/tests/test_doctestplus.py index 932ec94..5d070da 100644 --- a/tests/test_doctestplus.py +++ b/tests/test_doctestplus.py @@ -450,6 +450,7 @@ def test_requires_all(testdir): """ .. doctest-requires-all:: foobar + .. code-block:: >>> import foobar This is a narrative line, before another doctest snippet @@ -963,6 +964,8 @@ def test_remote_data_all(testdir): .. doctest-remote-data-all:: + .. code-block:: + >>> from contextlib import closing >>> from urllib.request import urlopen >>> with closing(urlopen('https://www.astropy.org')) as remote: From ec76b0b0fd76225961f9be8cf0061c9e52b2bae7 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Fri, 7 Nov 2025 14:43:57 +0100 Subject: [PATCH 2/2] Also fixup the docs --- README.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 48b26f6..f9df7c2 100644 --- a/README.rst +++ b/README.rst @@ -253,12 +253,14 @@ of the line here. .. code-block:: rst - .. doctest-skip-all + .. doctest-skip-all:: - >>> import non_existing - >>> non_existing.write_pseudo_code() - All the doctests are skipped in the file below + All the doctests are skipped in the file below + .. code-block:: + + >>> import non_existing + >>> non_existing.write_pseudo_code() Skip Unconditionally ^^^^^^^^^^^^^^^^^^^^