From c6ce9d75ade409a3bdd2377dd7bbe0a14e871efd Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Mon, 8 Jun 2026 22:19:23 +0200 Subject: [PATCH 1/9] docs: fix broken cross-references in sphinx docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix Sphinx build warnings and broken cross-references `.rst` fixes (cross-references, toctree, unused labels): - `index.rst`: fixes broken relative links (`../python_intro.html`, `../jupyter_intro.html`); added `exceptions` and `temporal_framework` to the toctree (were producing document isn't included in any toctree warnings); removed duplicate toctree entries (`grass.tools`, `grass.jupyter`, `grass.exceptions`) that were already covered by the parent `grass` entry - `gunittest_testing.rst`: renamed duplicate label `GRASS sample data` to `GRASS sample data testing` to resolve sphinx `duplicate label` conflict with `gunittest_running_tests.rst`; removed unused `test-as-scripts` and `doctest` label definitions - `pygrass_gis.rst`: removed unused `GRASSdatabase-label` and `Region-label` definitions - `pygrass_raster.rst`: removed unused `raster-label` definition `conf.py` fixes (config errors, lexer docstrings, theme options): - fixed `today` type mismatch (`date` → `str` via `.strftime()`) - added `autodoc_mock_imports = ["grass.lib", "grass.lib.gis"]` to mock C extension modules during autodoc - added `skip_member` filter to skip PLY lexer `t_*` methods in `temporal_algebra` and `temporal_operator` (their regex docstrings are not intended for RST parsing, were causing `Unknown target name` errors). - added pickleable `html_context` proxy to replace `sphinx_material` theme class objects (`TableFix`, `DerenderToc`) which sphinx cannot cache (fixes `cannot cache unpickleable configuration value` warning). - removed unsupported logo option from `html_theme_options`. Template fix (duplicate object descriptions): - `package.rst.jinja`: Added `:no-index:` to automodule directives for subpackages and submodules in the auto-generated API docs template. The root `grass` package keeps full index entries; subpackages use `:no-index:` to avoid duplicating entries already generated by the parent. --- doc/Makefile | 2 +- .../sphinx/apidoc/package.rst.jinja | 17 +++++++-- python/grass/docs/conf.py | 38 ++++++++++++++++++- python/grass/docs/src/gunittest_testing.rst | 7 +--- python/grass/docs/src/index.rst | 27 ++++++------- python/grass/docs/src/pygrass_gis.rst | 4 -- python/grass/docs/src/pygrass_raster.rst | 2 - 7 files changed, 64 insertions(+), 33 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 0cb75f02da3..7b22f4b70a1 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -6,7 +6,7 @@ SUBDIRS = \ include $(MODULE_TOPDIR)/include/Make/Dir.make FILES := $(wildcard *.html) -# So far, we disntinguished user and contributor documentation here by +# So far, we distinguished user and contributor documentation here by # extension. This is no longer possible with Markdown. MDFILES := grass_database.md \ projectionintro.md \ diff --git a/python/grass/docs/_templates/sphinx/apidoc/package.rst.jinja b/python/grass/docs/_templates/sphinx/apidoc/package.rst.jinja index ec8f567da1b..e6c17b6e0b0 100644 --- a/python/grass/docs/_templates/sphinx/apidoc/package.rst.jinja +++ b/python/grass/docs/_templates/sphinx/apidoc/package.rst.jinja @@ -1,8 +1,11 @@ -{%- macro automodule(modname, options) -%} +{%- macro automodule(modname, options, noindex=False) -%} .. automodule:: {{ modname }} {%- for option in options %} :{{ option }}: {%- endfor %} +{%- if noindex %} + :no-index: +{%- endif %} {%- endmacro %} {%- macro toctree(docnames) -%} @@ -24,7 +27,10 @@ {% endif %} {%- if modulefirst and not is_namespace %} -{{ automodule(pkgname, automodule_options) }} +{# Root grass package keeps full index; subpackages use no-index to avoid + duplicating index entries that the parent already generates recursively. #} +{%- set _pkg_noindex = pkgname != "grass" %} +{{ automodule(pkgname, automodule_options, noindex=_pkg_noindex) }} {% endif %} {%- if subpackages %} @@ -44,7 +50,7 @@ Submodules {% if show_headings %} {{- [submodule, "module"] | join(" ") | e | heading(2) }} {% endif %} -{{ automodule(submodule, automodule_options) }} +{{ automodule(submodule, automodule_options, noindex=True) }} {% endfor %} {%- endif %} {%- endif %} @@ -53,5 +59,8 @@ Submodules Module contents --------------- -{{ automodule(pkgname, automodule_options) }} +{# Root grass package keeps full index; subpackages use no-index to avoid + duplicating index entries that the parent already generates recursively. #} +{%- set _pkg_noindex = pkgname != "grass" %} +{{ automodule(pkgname, automodule_options, noindex=_pkg_noindex) }} {% endif %} diff --git a/python/grass/docs/conf.py b/python/grass/docs/conf.py index 1e35ec8aa26..dc42fe05b27 100644 --- a/python/grass/docs/conf.py +++ b/python/grass/docs/conf.py @@ -16,6 +16,8 @@ import string from shutil import copy +from _pickleable import table_fix, derender_toc + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -89,7 +91,7 @@ ) grass_version = core.version()["version"] -today = date.today() +today = date.today().strftime("%B %d, %Y") copy("_templates/layout.html.template", "_templates/layout.html") @@ -114,6 +116,31 @@ "sphinx_sitemap", ] +# When building docs, compiled GRASS extension modules (C libraries) may not +# be importable; mock them so autodoc can proceed using the pure-Python +# checkout sources. +autodoc_mock_imports = ["grass.lib", "grass.lib.gis"] + + +# Skip temporal lexer rule methods because their regex docstrings are not intended +# for reStructuredText parsing and only serve PLY token definitions. +def skip_member(app, what, name, obj, skip, options): + if name.startswith("t_"): + mod = getattr(obj, "__module__", None) + if mod in { + "grass.temporal.temporal_algebra", + "grass.temporal.temporal_operator", + "temporal.temporal_algebra", + "temporal.temporal_operator", + }: + return True + return None + + +def setup(app): + app.connect("autodoc-skip-member", skip_member) + + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -192,7 +219,6 @@ "repo_url": "https://github.com/OSGeo/grass/", "repo_name": "GRASS", "repo_type": "github", - "logo": "grass_logo.svg", # Visible levels of the global TOC; -1 means unlimited "globaltoc_depth": 1, # If False, expand all TOC entries @@ -243,6 +269,14 @@ ], } +# Make html_context cacheable by replacing theme's class objects with +# pickleable proxy instances. The theme stores class objects (type instances) +# in html_context which Sphinx's is_serializable() conservatively rejects. +html_context = { + "table_fix": table_fix, + "derender_toc": derender_toc, +} + # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] diff --git a/python/grass/docs/src/gunittest_testing.rst b/python/grass/docs/src/gunittest_testing.rst index 4650e181404..b5624a237f3 100644 --- a/python/grass/docs/src/gunittest_testing.rst +++ b/python/grass/docs/src/gunittest_testing.rst @@ -27,7 +27,7 @@ caused by C library functions does not influence the main testing process. Some tests will run without any data but many tests require the small (basic) version of GRASS sample Location for North Carolina -(see `GRASS sample data`). +(see `GRASS sample data testing`). Basic example ------------- @@ -506,8 +506,6 @@ However, do not use use doctest for tests of edge cases, for tests which require generate complex data first, etc. In these cases use `gunittest`. -.. _test-as-scripts: - Tests as general scripts ------------------------ @@ -716,9 +714,8 @@ Further reading .. _unittest: https://docs.python.org/2/library/unittest.html -.. _doctest: https://docs.python.org/2/library/doctest.html .. _Coverity Scan: https://scan.coverity.com/ .. _1038: https://scan.coverity.com/projects/1038 .. _Cppcheck: http://cppcheck.sourceforge.net/ .. _sandbox: https://svn.osgeo.org/grass/sandbox/wenzeslaus/grass_py_static_check.py -.. _GRASS sample data: https://grass.osgeo.org/download/data/ and http://fatra.cnr.ncsu.edu/data/ (nc_spm_full_v2beta1) +.. _GRASS sample data testing: https://grass.osgeo.org/download/sample-data diff --git a/python/grass/docs/src/index.rst b/python/grass/docs/src/index.rst index b1b0c2cac5a..baa8d4a5087 100644 --- a/python/grass/docs/src/index.rst +++ b/python/grass/docs/src/index.rst @@ -23,31 +23,28 @@ at various levels: * `grass.jupyter package `_ offers classes and setup functions for running GRASS in Jupyter Notebooks * `Testing GRASS source code and modules `_ using gunittest package -* `exceptions package `_ contains exceptions used by other packages +* `exceptions package `_ contains exceptions used by other packages * `imaging package `_ is a library to create animated images and films * `pydispatch package `_ is a library for signal-dispatching -------------------- Additional Resources -------------------- -* `GRASS Python introduction `_ provides a general overview of +* `GRASS Python introduction <../python_intro.html>`_ provides a general overview of the Python interface to GRASS. -* `GRASS Jupyter notebooks introduction `_ provides an overview of how to use the **grass.jupyter** module. - -.. _GRASS: https://grass.osgeo.org/ +* `GRASS Jupyter notebooks introduction <../jupyter_intro.html>`_ provides an overview of how to use the **grass.jupyter** module. -------------------- Modules and Packages -------------------- .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - index - grass.tools - script_intro - pygrass_index - grass.jupyter - exceptions - imaging - pydispatch - gunittest_testing + grass + script_intro + pygrass_index + exceptions + imaging + pydispatch + temporal_framework + gunittest_testing diff --git a/python/grass/docs/src/pygrass_gis.rst b/python/grass/docs/src/pygrass_gis.rst index 23891aab291..07644c6f226 100644 --- a/python/grass/docs/src/pygrass_gis.rst +++ b/python/grass/docs/src/pygrass_gis.rst @@ -1,5 +1,3 @@ -.. _GRASSdatabase-label: - GRASS database management ========================= @@ -16,8 +14,6 @@ database management (locations and mapsets) can be found in the `GRASS User's Manual: GRASS Quickstart `_. -.. _Region-label: - Region management ================= diff --git a/python/grass/docs/src/pygrass_raster.rst b/python/grass/docs/src/pygrass_raster.rst index d473ba48952..9a714e9e3a1 100644 --- a/python/grass/docs/src/pygrass_raster.rst +++ b/python/grass/docs/src/pygrass_raster.rst @@ -1,5 +1,3 @@ -.. _raster-label: - Introduction to Raster classes ============================== From c5b3f5efacb4a18a4a402bcbf97139fbf7d3822c Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Mon, 8 Jun 2026 23:12:26 +0200 Subject: [PATCH 2/9] fix sample data entry --- python/grass/docs/src/gunittest_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/grass/docs/src/gunittest_testing.rst b/python/grass/docs/src/gunittest_testing.rst index b5624a237f3..a6fd490e2dd 100644 --- a/python/grass/docs/src/gunittest_testing.rst +++ b/python/grass/docs/src/gunittest_testing.rst @@ -718,4 +718,4 @@ Further reading .. _1038: https://scan.coverity.com/projects/1038 .. _Cppcheck: http://cppcheck.sourceforge.net/ .. _sandbox: https://svn.osgeo.org/grass/sandbox/wenzeslaus/grass_py_static_check.py -.. _GRASS sample data testing: https://grass.osgeo.org/download/sample-data +.. _GRASS sample data: https://grass.osgeo.org/download/data/ and http://fatra.cnr.ncsu.edu/data/ (nc_spm_full_v2alpha2) From 1357dd2d1724600d820b6ad88c895816f87e29ee Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Tue, 9 Jun 2026 07:35:51 +0200 Subject: [PATCH 3/9] index.rst: restore some lost entries --- python/grass/docs/src/index.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/grass/docs/src/index.rst b/python/grass/docs/src/index.rst index baa8d4a5087..e120306b001 100644 --- a/python/grass/docs/src/index.rst +++ b/python/grass/docs/src/index.rst @@ -34,6 +34,8 @@ Additional Resources the Python interface to GRASS. * `GRASS Jupyter notebooks introduction <../jupyter_intro.html>`_ provides an overview of how to use the **grass.jupyter** module. +.. _GRASS: https://grass.osgeo.org/ + -------------------- Modules and Packages -------------------- @@ -41,8 +43,10 @@ Modules and Packages :maxdepth: 1 grass + grass.tools script_intro pygrass_index + grass.jupyter exceptions imaging pydispatch From 2c8b360ab97e27ec0869867eae782a4e78763cbb Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Tue, 9 Jun 2026 07:40:35 +0200 Subject: [PATCH 4/9] gunittest: streamline sample data title and URL --- python/grass/docs/src/gunittest_running_tests.rst | 2 +- python/grass/docs/src/gunittest_testing.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/grass/docs/src/gunittest_running_tests.rst b/python/grass/docs/src/gunittest_running_tests.rst index 26c2d269ae9..f9cf2cecd45 100644 --- a/python/grass/docs/src/gunittest_running_tests.rst +++ b/python/grass/docs/src/gunittest_running_tests.rst @@ -110,7 +110,7 @@ Currently there is full support only for running all the tests in the small (basic) version of GRASS sample Location for North Carolina (see `GRASS sample data`). -.. _GRASS sample data: https://grass.osgeo.org/download/sample-data +.. _GRASS sample data: https://grass.osgeo.org/download/data Example Bash script to run be used as a cron job diff --git a/python/grass/docs/src/gunittest_testing.rst b/python/grass/docs/src/gunittest_testing.rst index a6fd490e2dd..4503d89a52a 100644 --- a/python/grass/docs/src/gunittest_testing.rst +++ b/python/grass/docs/src/gunittest_testing.rst @@ -27,7 +27,7 @@ caused by C library functions does not influence the main testing process. Some tests will run without any data but many tests require the small (basic) version of GRASS sample Location for North Carolina -(see `GRASS sample data testing`). +(see `GRASS sample data`). Basic example ------------- From 8128a3050ded25b15954ed45fd8523b088abebd6 Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Tue, 9 Jun 2026 23:19:15 +0200 Subject: [PATCH 5/9] reverted _pickleable and -html_context stuff --- python/grass/docs/conf.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/python/grass/docs/conf.py b/python/grass/docs/conf.py index dc42fe05b27..f3150c5ae01 100644 --- a/python/grass/docs/conf.py +++ b/python/grass/docs/conf.py @@ -16,7 +16,6 @@ import string from shutil import copy -from _pickleable import table_fix, derender_toc # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -269,14 +268,6 @@ def setup(app): ], } -# Make html_context cacheable by replacing theme's class objects with -# pickleable proxy instances. The theme stores class objects (type instances) -# in html_context which Sphinx's is_serializable() conservatively rejects. -html_context = { - "table_fix": table_fix, - "derender_toc": derender_toc, -} - # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] From a0b135c7a9a6fb47628c935eb642c8d320b6e5e6 Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Wed, 10 Jun 2026 23:34:49 +0200 Subject: [PATCH 6/9] update GRASS sample data URL and dataset name --- python/grass/docs/src/gunittest_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/grass/docs/src/gunittest_testing.rst b/python/grass/docs/src/gunittest_testing.rst index 4503d89a52a..b8787fea352 100644 --- a/python/grass/docs/src/gunittest_testing.rst +++ b/python/grass/docs/src/gunittest_testing.rst @@ -718,4 +718,4 @@ Further reading .. _1038: https://scan.coverity.com/projects/1038 .. _Cppcheck: http://cppcheck.sourceforge.net/ .. _sandbox: https://svn.osgeo.org/grass/sandbox/wenzeslaus/grass_py_static_check.py -.. _GRASS sample data: https://grass.osgeo.org/download/data/ and http://fatra.cnr.ncsu.edu/data/ (nc_spm_full_v2alpha2) +.. _GRASS sample data: https://grass.osgeo.org/sampledata/north_carolina/ (nc_spm_full_v2beta1.tar.gz) From ad0013fd30ceb6bdab078179d24b3afe9f3c3a21 Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Fri, 10 Jul 2026 14:58:00 +0200 Subject: [PATCH 7/9] update https://docs.python.org/3/library/unittest.html --- python/grass/docs/src/gunittest_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/grass/docs/src/gunittest_testing.rst b/python/grass/docs/src/gunittest_testing.rst index b8787fea352..e85c2dc52db 100644 --- a/python/grass/docs/src/gunittest_testing.rst +++ b/python/grass/docs/src/gunittest_testing.rst @@ -713,7 +713,7 @@ Further reading gunittest_running_tests -.. _unittest: https://docs.python.org/2/library/unittest.html +.. _unittest: https://docs.python.org/3/library/unittest.html .. _Coverity Scan: https://scan.coverity.com/ .. _1038: https://scan.coverity.com/projects/1038 .. _Cppcheck: http://cppcheck.sourceforge.net/ From e426ab0f7635cf1857677bba78a37283557f8b58 Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Fri, 10 Jul 2026 15:01:34 +0200 Subject: [PATCH 8/9] restore labels --- python/grass/docs/src/pygrass_gis.rst | 4 ++++ python/grass/docs/src/pygrass_raster.rst | 2 ++ 2 files changed, 6 insertions(+) diff --git a/python/grass/docs/src/pygrass_gis.rst b/python/grass/docs/src/pygrass_gis.rst index 07644c6f226..23891aab291 100644 --- a/python/grass/docs/src/pygrass_gis.rst +++ b/python/grass/docs/src/pygrass_gis.rst @@ -1,3 +1,5 @@ +.. _GRASSdatabase-label: + GRASS database management ========================= @@ -14,6 +16,8 @@ database management (locations and mapsets) can be found in the `GRASS User's Manual: GRASS Quickstart `_. +.. _Region-label: + Region management ================= diff --git a/python/grass/docs/src/pygrass_raster.rst b/python/grass/docs/src/pygrass_raster.rst index 9a714e9e3a1..d473ba48952 100644 --- a/python/grass/docs/src/pygrass_raster.rst +++ b/python/grass/docs/src/pygrass_raster.rst @@ -1,3 +1,5 @@ +.. _raster-label: + Introduction to Raster classes ============================== From 25c9c335016ac77ae339fdd6df66d610073c0614 Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Fri, 10 Jul 2026 15:04:03 +0200 Subject: [PATCH 9/9] restore labels --- python/grass/docs/src/gunittest_testing.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/grass/docs/src/gunittest_testing.rst b/python/grass/docs/src/gunittest_testing.rst index e85c2dc52db..36355744a94 100644 --- a/python/grass/docs/src/gunittest_testing.rst +++ b/python/grass/docs/src/gunittest_testing.rst @@ -506,6 +506,8 @@ However, do not use use doctest for tests of edge cases, for tests which require generate complex data first, etc. In these cases use `gunittest`. +.. _test-as-scripts: + Tests as general scripts ------------------------