pytest-doctestplus icon indicating copy to clipboard operation
pytest-doctestplus copied to clipboard

BUG: sphinx crashes when `doctest-remote-data-all` is at top of file

Open bsipocz opened this issue 8 months ago • 13 comments

The .. doctest-remote-data-all:: directive can be used anywhere in the file and it will skip the remaining parts unless remote-data is enabled. However when I put it at the very top of an rst file sphinx crashes.

See https://github.com/astropy/astropy/pull/17839

and https://app.readthedocs.org/projects/astropy/builds/27974431/


reading sources... [ 89%] io/votable/dataorigin
Versions
========
* Platform:         linux; (Linux-6.8.0-1021-aws-x86_64-with-glibc2.35)
* Python version:   3.13.3 (CPython)
* Sphinx version:   8.2.3
* Docutils version: 0.21.2
* Jinja2 version:   3.1.6
* Pygments version: 2.19.1
Last Messages
=============
    reading sources... [ 89%]
    io/votable/api_exceptions
    reading sources... [ 89%]
    io/votable/coosys_element
    reading sources... [ 89%]
    io/votable/dataorigin
Loaded Extensions
=================
* sphinx.ext.mathjax (8.2.3)
* alabaster (1.0.0)
* sphinxcontrib.applehelp (2.0.0)
* sphinxcontrib.devhelp (2.0.0)
* sphinxcontrib.htmlhelp (2.1.0)
* sphinxcontrib.serializinghtml (1.1.10)
* sphinxcontrib.qthelp (2.0.0)
* sphinx.ext.autodoc.preserve_defaults (8.2.3)
* sphinx.ext.autodoc.type_comment (8.2.3)
* sphinx.ext.autodoc.typehints (8.2.3)
* sphinx.ext.autodoc (8.2.3)
* sphinx.ext.coverage (8.2.3)
* sphinx.ext.graphviz (8.2.3)
* sphinx.ext.inheritance_diagram (8.2.3)
* sphinx.ext.intersphinx (8.2.3)
* sphinx.ext.todo (8.2.3)
* sphinx.ext.viewcode (8.2.3)
* sphinxcontrib.jquery (4.1)
* sphinx.ext.autosummary (8.2.3)
* numpydoc (1.8.0)
* sphinx_copybutton (0.5.2)
* pytest_doctestplus.sphinx.doctestplus (unknown version)
* sphinx_astropy.ext.changelog_links (unknown version)
* sphinx_astropy.ext.generate_config (0.1)
* sphinx_astropy.ext.intersphinx_toggle (unknown version)
* sphinx_astropy.ext.missing_static (unknown version)
* sphinx_automodapi.autodoc_enhancements (unknown version)
* sphinx_automodapi.automodsumm (unknown version)
* sphinx_automodapi.automodapi (unknown version)
* sphinx_automodapi.smart_resolver (unknown version)
* matplotlib.sphinxext.plot_directive (3.10.1)
* matplotlib.sphinxext.roles (3.10.1)
* sphinx_changelog (unknown version)
* sphinx_design (0.6.1)
* sphinxcontrib.globalsubs (0.1.0)
* pydata_sphinx_theme (unknown version)
Traceback
=========
    Traceback (most recent call last):
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/sphinx/cmd/build.py", line 432, in build_main
        app.build(args.force_all, args.filenames)
        ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/sphinx/application.py", line 426, in build
        self.builder.build_update()
        ~~~~~~~~~~~~~~~~~~~~~~~~~^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/sphinx/builders/__init__.py", line 375, in build_update
        self.build(
        ~~~~~~~~~~^
            to_build,
            ^^^^^^^^^
        ...<2 lines>...
            method='update',
            ^^^^^^^^^^^^^^^^
        )
        ^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/sphinx/builders/__init__.py", line 403, in build
        updated_docnames = set(self.read())
                               ~~~~~~~~~^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/sphinx/builders/__init__.py", line 519, in read
        self._read_serial(docnames)
        ~~~~~~~~~~~~~~~~~^^^^^^^^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/sphinx/builders/__init__.py", line 584, in _read_serial
        self.read_doc(docname)
        ~~~~~~~~~~~~~^^^^^^^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/sphinx/builders/__init__.py", line 648, in read_doc
        publisher.publish()
        ~~~~~~~~~~~~~~~~~^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/core.py", line 234, in publish
        self.document = self.reader.read(self.source, self.parser,
                        ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
                                         self.settings)
                                         ^^^^^^^^^^^^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/sphinx/io.py", line 103, in read
        self.parse()
        ~~~~~~~~~~^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/readers/__init__.py", line 76, in parse
        self.parser.parse(self.input, document)
        ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/sphinx/parsers.py", line 86, in parse
        self.statemachine.run(inputlines, document, inliner=self.inliner)
        ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/parsers/rst/states.py", line 169, in run
        results = StateMachineWS.run(self, input_lines, input_offset,
                                     input_source=document['source'])
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/statemachine.py", line 233, in run
        context, next_state, result = self.check_line(
                                      ~~~~~~~~~~~~~~~^
            context, state, transitions)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/statemachine.py", line 445, in check_line
        return method(match, context, next_state)
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/parsers/rst/states.py", line 2357, in explicit_markup
        nodelist, blank_finish = self.explicit_construct(match)
                                 ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/parsers/rst/states.py", line 2369, in explicit_construct
        return method(self, expmatch)
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/parsers/rst/states.py", line 2106, in directive
        return self.run_directive(
               ~~~~~~~~~~~~~~~~~~^
            directive_class, match, type_name, option_presets)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/parsers/rst/states.py", line 2156, in run_directive
        result = directive_instance.run()
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/pytest_doctestplus/sphinx/doctestplus.py", line 23, in run
        if re.match('win32', self.content[0]):
                             ~~~~~~~~~~~~^^^
      File "/home/docs/checkouts/readthedocs.org/user_builds/astropy/conda/17839/lib/python3.13/site-packages/docutils/statemachine.py", line 1136, in __getitem__
        return self.data[i]
               ~~~~~~~~~^^^
    IndexError: list index out of range
The full traceback has been saved in:
/tmp/sphinx-err-rcq50vmx.log
To report this error to the developers, please open an issue at <https://github.com/sphinx-doc/sphinx/issues/>. Thanks!
Please also report this if it was a user error, so that a better error message can be provided next time.

bsipocz avatar Apr 25 '25 20:04 bsipocz

.. doctest-skip-all works however, so I think the bug is about whether to have :: or not.

Either case, I work around this by placing the directive a little bit further down the file.

bsipocz avatar Apr 25 '25 20:04 bsipocz

Doesn't :: need the block to be indented? If you put it at the very top, did you then indent everything in the doc?

pllim avatar Apr 28 '25 15:04 pllim

Ahh, maybe. doctest-skip-all certainly doesn't have it, but also the primary intention for doctest-remote-data-all was to be able to put it anywhere in the file and skip he rest.

I can't recall if leaving the :: was intentional or just a side effect of copying the way we do doctest-requires-all. I'll look into it later this week.

bsipocz avatar Apr 28 '25 16:04 bsipocz

I get essentially the same error with .. doctest-requires-all:: h5py in any location in the file:

(astropy) MoritzAirRoseGold ~/code/astropy/docs> make html                               
sphinx-build -b html -d _build/doctrees   . _build/html
Running Sphinx v8.2.3
loading translations [en]... done
Converting `source_suffix = '.rst'` to `source_suffix = {'.rst': 'restructuredtext'}`.
loading intersphinx inventory 'python' from https://docs.python.org/3/objects.inv ...
loading intersphinx inventory 'pythonloc' from /Users/guenther/miniforge3/envs/astropy/lib/python3.13/site-packages/sphinx_astropy/local/python3_local_links.inv ...
loading intersphinx inventory 'numpy' from https://numpy.org/doc/stable/objects.inv ...
loading intersphinx inventory 'scipy' from https://docs.scipy.org/doc/scipy/objects.inv ...
loading intersphinx inventory 'matplotlib' from https://matplotlib.org/stable/objects.inv ...
loading intersphinx inventory 'astropy' from https://docs.astropy.org/en/stable/objects.inv ...
loading intersphinx inventory 'h5py' from https://docs.h5py.org/en/stable/objects.inv ...
loading intersphinx inventory 'pyerfa' from https://pyerfa.readthedocs.io/en/stable/objects.inv ...
loading intersphinx inventory 'pytest' from https://docs.pytest.org/en/stable/objects.inv ...
loading intersphinx inventory 'pandas' from https://pandas.pydata.org/pandas-docs/stable/objects.inv ...
loading intersphinx inventory 'ipython' from https://ipython.readthedocs.io/en/stable/objects.inv ...
loading intersphinx inventory 'sphinx_automodapi' from https://sphinx-automodapi.readthedocs.io/en/stable/objects.inv ...
loading intersphinx inventory 'asdf-astropy' from https://asdf-astropy.readthedocs.io/en/latest/objects.inv ...
loading intersphinx inventory 'fsspec' from https://filesystem-spec.readthedocs.io/en/latest/objects.inv ...
loading intersphinx inventory 'cycler' from https://matplotlib.org/cycler/objects.inv ...
loading intersphinx inventory 'dask' from https://docs.dask.org/en/stable/objects.inv ...
[autosummary] generating autosummary for: api/astropy.config.ConfigItem.rst, api/astropy.config.ConfigNamespace.rst, api/astropy.config.InvalidConfigurationItemWarning.rst, api/astropy.config.create_config_file.rst, api/astropy.config.generate_config.rst, api/astropy.config.get_cache_dir.rst, api/astropy.config.get_cache_dir_path.rst, api/astropy.config.get_config.rst, api/astropy.config.get_config_dir.rst, api/astropy.config.get_config_dir_path.rst, ..., whatsnew/5.0.rst, whatsnew/5.1.rst, whatsnew/5.2.rst, whatsnew/5.3.rst, whatsnew/6.0.rst, whatsnew/6.1.rst, whatsnew/7.0.rst, whatsnew/7.1.rst, whatsnew/7.2.rst, whatsnew/index.rst
[automodsumm] io/fits/api/tiled_compression.rst: found 9 automodsumm entries to generate
[automodsumm] config/ref_api.rst: found 13 automodsumm entries to generate
[automodsumm] utils/masked/index.rst: found 37 automodsumm entries to generate
[automodsumm] cosmology/units.rst: found 6 automodsumm entries to generate
[automodsumm] timeseries/ref_api.rst: found 11 automodsumm entries to generate
[automodsumm] visualization/wcsaxes/index.rst: found 15 automodsumm entries to generate
[automodsumm] modeling/reference_api.rst: found 236 automodsumm entries to generate
[automodsumm] wcs/reference_api.rst: found 53 automodsumm entries to generate
[automodsumm] cosmology/traits.rst: found 4 automodsumm entries to generate
[automodsumm] samp/ref_api.rst: found 11 automodsumm entries to generate
[automodsumm] visualization/ref_api.rst: found 35 automodsumm entries to generate
[automodsumm] io/typing.rst: found 2 automodsumm entries to generate
[automodsumm] stats/ref_api.rst: found 48 automodsumm entries to generate
[automodsumm] stats/robust.rst: found 9 automodsumm entries to generate
[automodsumm] cosmology/realizations.rst: found 9 automodsumm entries to generate
[automodsumm] io/misc_ref_api.rst: found 20 automodsumm entries to generate
[automodsumm] io/ascii/ref_api.rst: found 59 automodsumm entries to generate
[automodsumm] io/registry_ref_api.rst: found 19 automodsumm entries to generate
[automodsumm] logging.rst: found 3 automodsumm entries to generate
[automodsumm] cosmology/io/index.rst: found 4 automodsumm entries to generate
[automodsumm] uncertainty/index.rst: found 4 automodsumm entries to generate
[automodsumm] time/ref_api.rst: found 44 automodsumm entries to generate
[automodsumm] development/maintainers/testhelpers.rst: found 7 automodsumm entries to generate
[automodsumm] units/ref_api.rst: found 79 automodsumm entries to generate
[automodsumm] utils/ref_api.rst: found 117 automodsumm entries to generate
[automodsumm] constants/index.rst: found 2 automodsumm entries to generate
[automodsumm] cosmology/ref_api.rst: found 19 automodsumm entries to generate
[automodsumm] convolution/ref_api.rst: found 28 automodsumm entries to generate
[automodsumm] table/ref_api.rst: found 33 automodsumm entries to generate
[automodsumm] nddata/ref_api.rst: found 48 automodsumm entries to generate
[automodsumm] stats/circ.rst: found 8 automodsumm entries to generate
[automodsumm] coordinates/ref_api.rst: found 126 automodsumm entries to generate
[automodsumm] io/votable/ref_api.rst: found 41 automodsumm entries to generate
building [mo]: targets for 0 po files that are out of date
writing output... 
building [html]: targets for 1439 source files that are out of date
updating environment: [new config] 1439 added, 0 changed, 0 removed
/Users/guenther/miniforge3/envs/astropy/lib/python3.13/site-packages/numpydoc/docscrape.py:421: UserWarning: Unknown section Properties in the docstring of ColumnECSV in /Users/guenther/code/astropy/astropy/io/misc/ecsv.py.
  self[section] = content
/Users/guenther/miniforge3/envs/astropy/lib/python3.13/site-packages/numpydoc/docscrape.py:421: UserWarning: Unknown section Properties in the docstring of ECSVEngine in /Users/guenther/code/astropy/astropy/io/misc/ecsv.py.
  self[section] = content
Loading template...[ 81%] changelog
Finding news fragments...
Jinja rendering index_dev index_dev
Jinja rendering install%] install
/Users/guenther/miniforge3/envs/astropy/lib/python3.13/site-packages/numpydoc/docscrape.py:421: UserWarning: Unknown section Properties in the docstring of ColumnECSV in /Users/guenther/code/astropy/astropy/io/misc/ecsv.py.
  self[section] = content
/Users/guenther/miniforge3/envs/astropy/lib/python3.13/site-packages/numpydoc/docscrape.py:421: UserWarning: Unknown section Properties in the docstring of ECSVEngine in /Users/guenther/code/astropy/astropy/io/misc/ecsv.py.
  self[section] = content
/Users/guenther/code/astropy/docs/io/registry.rst:129: ERROR: Unexpected indentation. [docutils]


Versions
========

* Platform:         darwin; (macOS-15.6-arm64-arm-64bit-Mach-O)
* Python version:   3.13.5 (CPython)
* Sphinx version:   8.2.3
* Docutils version: 0.21.2
* Jinja2 version:   3.1.6
* Pygments version: 2.19.2

Last Messages
=============

    io/unified_table_fits


    reading sources... [ 89%]
    io/unified_table_hdf5


    reading sources... [ 89%]
    io/unified_table_parquet

Loaded Extensions
=================

* sphinx.ext.mathjax (8.2.3)
* alabaster (1.0.0)
* sphinxcontrib.applehelp (2.0.0)
* sphinxcontrib.devhelp (2.0.0)
* sphinxcontrib.htmlhelp (2.1.0)
* sphinxcontrib.serializinghtml (2.0.0)
* sphinxcontrib.qthelp (2.0.0)
* sphinx.ext.autodoc.preserve_defaults (8.2.3)
* sphinx.ext.autodoc.type_comment (8.2.3)
* sphinx.ext.autodoc.typehints (8.2.3)
* sphinx.ext.autodoc (8.2.3)
* sphinx.ext.coverage (8.2.3)
* sphinx.ext.graphviz (8.2.3)
* sphinx.ext.inheritance_diagram (8.2.3)
* sphinx.ext.intersphinx (8.2.3)
* sphinx.ext.todo (8.2.3)
* sphinx.ext.viewcode (8.2.3)
* sphinxcontrib.jquery (4.1)
* sphinx.ext.autosummary (8.2.3)
* numpydoc (1.8.0)
* sphinx_copybutton (0.5.2)
* pytest_doctestplus.sphinx.doctestplus (unknown version)
* sphinx_astropy.ext.changelog_links (unknown version)
* sphinx_astropy.ext.generate_config (0.1)
* sphinx_astropy.ext.intersphinx_toggle (unknown version)
* sphinx_astropy.ext.missing_static (unknown version)
* sphinx_automodapi.autodoc_enhancements (unknown version)
* sphinx_automodapi.automodsumm (unknown version)
* sphinx_automodapi.automodapi (unknown version)
* sphinx_automodapi.smart_resolver (unknown version)
* matplotlib.sphinxext.plot_directive (3.10.3)
* matplotlib.sphinxext.roles (3.10.3)
* sphinx_changelog (unknown version)
* sphinx_design (0.6.1)
* sphinxcontrib.globalsubs (0.1.0)
* pydata_sphinx_theme (unknown version)

Traceback
=========

      File "/Users/guenther/miniforge3/envs/astropy/lib/python3.13/site-packages/docutils/statemachine.py", line 1136, in __getitem__
        return self.data[i]
               ~~~~~~~~~^^^
    IndexError: list index out of range


The full traceback has been saved in:
/var/folders/r7/f0qh27rn207bwwvt3s7v5gh40000gn/T/sphinx-err-0q3bdbe3.log

To report this error to the developers, please open an issue at <https://github.com/sphinx-doc/sphinx/issues/>. Thanks!
Please also report this if it was a user error, so that a better error message can be provided next time.
make: *** [html] Error 2

My file looks like this:

.. doctest-requires-all:: h5py

.. _table_io_hdf5:

HDF5
----

Reading/writing from/to |HDF5| files is supported with ``format='hdf5'`` (this
requires |h5py| to be installed). However, the ``.hdf5`` file extension is
automatically recognized when writing files, and HDF5 files are automatically
identified (even with a different extension) when reading in (using the first
few bytes of the file to identify the format), so in most cases you will not
need to explicitly specify ``format='hdf5'``.

Since HDF5 files can contain multiple tables, the full path to the table
should be specified via the ``path=`` argument when reading and writing.

Examples
^^^^^^^^

..
  EXAMPLE START
  Reading from and Writing to HDF5 Files

To read a table called ``data`` from an HDF5 file named ``observations.hdf5``,
you can do::

...

hamogu avatar Aug 16 '25 22:08 hamogu

As @pllim suggested, it builds if the entire page below the .. doctest-requires-all:: h5py line is indented, but the build does not actually render the page as we want it to look, so that's not really a workable work-around:

Image

hamogu avatar Aug 16 '25 22:08 hamogu

See https://github.com/astropy/astropy/pull/18524 which could be cleaned up a bit if this worked, but it's not a show-stopper. (There is less than a dozen doctests in each effected file, so they can be individually guarded with doctest-requires

hamogu avatar Aug 16 '25 22:08 hamogu

Would you try to add the line under the heading? I mean it's just a workaround for now, but I expect it to work just as it did for my use case above

bsipocz avatar Aug 17 '25 00:08 bsipocz

I get the same error message that I also get when I put it on the top of the file.

hamogu avatar Aug 17 '25 01:08 hamogu

Perhaps this test was not well designed, then:

https://github.com/scientific-python/pytest-doctestplus/blob/57d68bed411af7c644d37bb570ead31cf8c00d9a/tests/test_doctestplus.py#L451

@hamogu , for https://github.com/astropy/astropy/pull/18524 , I will suggest a possible alternative on that PR as well.

pllim avatar Aug 18 '25 16:08 pllim

yeap, that's what I remembered that we actually test that scenario (but didn't have keyboard access to check the code when commented).

The skip-all came later and I based it on the requires-all implementation, so I'm very much puzzled.

bsipocz avatar Aug 18 '25 19:08 bsipocz

Either case, I would say it feels to be a different bug, so would you mind opening a new issue for it? The one in this issue is really easily workaroundable so has a rather low priority, while the requires-all was something that is expected to work for a while.

Also, counter check: does it work with v1.3.0?

bsipocz avatar Aug 18 '25 19:08 bsipocz

The changelog lists this as a new feature in 1.4, so I didn't see any use in trying out older versions.

hamogu avatar Aug 18 '25 19:08 hamogu

The changelog lists this as a new feature in 1.4, so I didn't see any use in trying out older versions.

Ahh, you're right, never mind it then.

bsipocz avatar Aug 18 '25 19:08 bsipocz