From 040c7c58d1d28604ab12f452bd451ebf1eb4fc98 Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Tue, 1 Aug 2023 00:28:01 +0200 Subject: [PATCH] Fix non-unique heading anchors on changelog doc page --- .pre-commit-config.yaml | 1 + docs/__init__.py | 0 docs/conf.py | 13 +++++++++++++ docs/utils.py | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 docs/__init__.py create mode 100644 docs/utils.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9811b66c7..da178e75d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,6 +33,7 @@ repos: - toml==0.10.2 - pip==20.3.4 - build==0.9.0 + - types-docutils==0.20.0.1 - repo: https://github.com/PyCQA/bandit rev: 1.7.5 hooks: diff --git a/docs/__init__.py b/docs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/conf.py b/docs/conf.py index 1f8491603..d645aa5f9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,12 +3,19 @@ from __future__ import annotations +import os +import sys from importlib.metadata import version as get_version from pathlib import Path +from sphinx.application import Sphinx from sphinx.util import logging from sphinx.util.console import bold +# Add the docs/ directory to sys.path to be able to import utils +docs_dir = os.path.dirname(os.path.dirname(__file__)) +sys.path.insert(0, docs_dir) + logger = logging.getLogger(__name__) # -- Path setup -------------------------------------------------------------- @@ -57,3 +64,9 @@ ] suppress_warnings = ["myst.xref_missing"] + + +def setup(app: Sphinx) -> None: + from docs.utils import TransformSectionIdToName + + app.add_transform(TransformSectionIdToName) diff --git a/docs/utils.py b/docs/utils.py new file mode 100644 index 000000000..5777c1712 --- /dev/null +++ b/docs/utils.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +import re +from typing import Any + +from docutils import nodes +from sphinx.transforms import SortIds, SphinxTransform + +numerical_id = re.compile(r"^id[0-9]+$") + + +class TransformSectionIdToName(SphinxTransform): # type: ignore[misc] + """Transforms section ids from , , ... to id .""" + + default_priority = SortIds.default_priority + 1 + + def apply(self, **kwargs: Any) -> Any: + for node in self.document.findall(nodes.section): + if not self._has_numerical_id(node): + continue + self._transform_id_to_name(node) + + def _has_numerical_id(self, node: nodes.section) -> bool: + node_ids = node["ids"] + if not node_ids: + return False + + if len(node_ids) != 1: + return False + + return bool(numerical_id.match(node_ids[0])) + + def _transform_id_to_name(self, node: nodes.section) -> None: + node["ids"] = [nodes.make_id("id " + name) for name in node["names"]]