From 86ddf84d7e6f21dabb15f2cab27e0573fe88ede8 Mon Sep 17 00:00:00 2001 From: Norman Rzepka Date: Wed, 9 Sep 2026 12:22:37 +0200 Subject: [PATCH] Namespace generated example/schema labels per spec version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each version submodule's pre_build.py generates its examples and schemas pages with identical MyST label names (examples:multiscales_strict:..., schemas:image, ...). Sphinx reads all six versions into a single project, so those labels collide: it keeps one instance and drops the rest, and every [...](#examples:...) link in every version resolved to the surviving one — dev. Clicking an example link on the 0.5 examples index silently took you to the dev spec. The hand-written spec prose does not have this problem because its labels are already namespaced (version0.5:intro, version0.5:multiscale-md). Do the same for the generated ones: rewrite them to version{version}: right after pre_build.py runs. Kept in the superproject, like the boilerplate injection above it, so we do not have to edit, commit, and bump every ngff-spec version submodule. Co-Authored-By: Claude Opus 5 --- conf.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/conf.py b/conf.py index 156a7529d..24b99bb8a 100644 --- a/conf.py +++ b/conf.py @@ -95,6 +95,35 @@ html_show_sourcelink = False +def namespace_generated_labels(spec_dir, version): + """Prefix the labels generated by ``pre_build.py`` with the spec version. + + ``pre_build.py`` emits targets such as ``(examples:multiscales_strict:...)=`` + and ``(schemas:image)=``. Every version submodule uses the exact same names, + so once Sphinx reads them all into a single project the duplicates collapse + and *all* of them resolve to whichever version happened to be read first + (``dev``). Links on the 0.5 examples/schemas pages then silently pointed at + the dev spec. + + Hand-written spec labels already namespace themselves as ``version0.5:...``; + do the same for the generated ones. This is done here in the superproject so + we do not have to edit, commit, and bump every ngff-spec version submodule. + """ + import re + from pathlib import Path + + prefix = f"version{version}:" + # target definition at the start of a line, and MyST link to such a target + target_re = re.compile(r"^\((examples|schemas):", re.MULTILINE) + link_re = re.compile(r"\]\(#(examples|schemas):") + + for md_file in Path(spec_dir).rglob("*.md"): + text = md_file.read_text(encoding="utf-8") + patched = link_re.sub(rf"](#{prefix}\1:", target_re.sub(rf"({prefix}\1:", text)) + if patched != text: + md_file.write_text(patched, encoding="utf-8") + + def build_served_html(): import glob import subprocess @@ -143,6 +172,9 @@ def build_served_html(): subprocess.check_call([sys.executable, script]) print("✅ Built rendered examples/schemas for version", version) + namespace_generated_labels(spec_dir, version) + print(f"✅ Namespaced generated labels for version {version}") + # build jupyter-book docs in specification submodules myst_file = glob.glob(f"specifications/{version}/**/myst.yml", recursive=True)[ 0