From ed565ceb333c128b48176cf0f8ff4c22164e9be6 Mon Sep 17 00:00:00 2001 From: Qinghua Zhou Date: Wed, 8 Apr 2026 14:59:05 -0700 Subject: [PATCH] Fix missing directory of document for new tag v0.9.0 (#776) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v0.9.0 conf.py (introduced in #775) dynamically loads the version from python/mscclpp/_version.py. This file is generated at build time by setuptools_scm and is listed in .gitignore — it is never committed to the repo. Earlier tags (v0.8.0 and below) used a hardcoded release (e.g., "v0.8.0") in conf.py, so they had no dependency on generated files. sphinx-multiversion checks out each tag using git archive, which only extracts committed files. Since _version.py is not committed, the v0.9.0 checkout is missing it, and conf.py crashes on import. All future tags will have this same problem. **Three changes:** 1. docs/build_multiversion.py (new): A wrapper around sphinx-multiversion that monkey-patches copy_tree to generate _version.py in each tag checkout after extraction. The version string is parsed from the tag name (e.g., v0.9.0 → __version__ = "0.9.0"). 2. Makefile: The multiversion target now calls build_multiversion.py instead of sphinx-multiversion directly. 3. conf.py: Added a fallback so that if _version.py doesn't exist, it reads the version from the VERSION file instead. This makes conf.py resilient for any future scenario where _version.py is missing. **Testing** Verified locally: • make multiversion now successfully builds all 11 versions (v0.4.0 through v0.9.0) • v0.9.0 docs are correctly generated under _build/html/v0.9.0/ Version selector shows v0.9.0 as latest --- docs/Makefile | 2 +- docs/build_multiversion.py | 49 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 docs/build_multiversion.py diff --git a/docs/Makefile b/docs/Makefile index 5bc7422e..bf82c03a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -5,7 +5,7 @@ # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build -SPHINXMULTIVERSION ?= sphinx-multiversion +SPHINXMULTIVERSION ?= python3 build_multiversion.py SOURCEDIR = . BUILDDIR = _build diff --git a/docs/build_multiversion.py b/docs/build_multiversion.py new file mode 100644 index 00000000..ace20fc0 --- /dev/null +++ b/docs/build_multiversion.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +"""Wrapper around sphinx-multiversion that patches copy_tree to generate +_version.py in each tag checkout. This is needed because setuptools_scm +generates _version.py at build time, but sphinx-multiversion uses +`git archive` which only contains committed files. + +Usage (called by Makefile): + python3 build_multiversion.py [sphinx-opts...] +""" + +import os +import re +import subprocess +import sys + +import sphinx_multiversion.git as smv_git +from sphinx_multiversion import main as smv_main + +# Save the original copy_tree +_original_copy_tree = smv_git.copy_tree + + +def _patched_copy_tree(gitroot, src, dst, reference, sourcepath="."): + """Call original copy_tree, then generate _version.py from the VERSION file.""" + _original_copy_tree(gitroot, src, dst, reference, sourcepath) + + # Extract version from the tag name (e.g., "v0.9.0" -> "0.9.0") + refname = getattr(reference, "refname", "") or "" + match = re.search(r"v(\d+\.\d+\.\d+)", refname) + if not match: + return + + version = match.group(1) + version_py_dir = os.path.join(dst, "python", "mscclpp") + if os.path.isdir(version_py_dir): + version_py = os.path.join(version_py_dir, "_version.py") + if not os.path.exists(version_py): + with open(version_py, "w") as f: + f.write(f'__version__ = "{version}"\n') + + +# Monkey-patch +smv_git.copy_tree = _patched_copy_tree + +if __name__ == "__main__": + sys.exit(smv_main(sys.argv[1:]))