From 84ba586e599e8b860478a743caaacc0b99e6acef Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 7 Mar 2026 23:48:45 +0000
Subject: [PATCH 1/5] Initial plan
From 1c1203138b4abc0f766e5ce84d3b8246e517e987 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 8 Mar 2026 00:39:53 +0000
Subject: [PATCH 2/5] Modernize project: pyproject.toml, fix Sphinx 9 compat,
rename master->main
Co-authored-by: vfdev-5 <2459423+vfdev-5@users.noreply.github.com>
---
.github/workflows/ignite-docs-test.yml | 2 +-
.github/workflows/tests.yml | 2 +-
pyproject.toml | 50 ++++++++++++++
sphinxcontrib_versioning/__main__.py | 14 ++--
sphinxcontrib_versioning/lib.py | 8 +--
sphinxcontrib_versioning/routines.py | 75 ++++++++++++--------
sphinxcontrib_versioning/sphinx_.py | 26 ++++++-
sphinxcontrib_versioning/versions.py | 6 +-
tests/conftest.py | 3 +-
tests/test_routines/test_build_all.py | 76 +++++++++++----------
tests/test_routines/test_gather_git_info.py | 6 +-
tests/test_routines/test_pre_build.py | 16 ++---
tests/test_routines/test_read_local_conf.py | 3 +-
tests/test_sphinx/test_read_config.py | 2 +-
14 files changed, 190 insertions(+), 99 deletions(-)
create mode 100644 pyproject.toml
diff --git a/.github/workflows/ignite-docs-test.yml b/.github/workflows/ignite-docs-test.yml
index 8a03509a..1f099f06 100644
--- a/.github/workflows/ignite-docs-test.yml
+++ b/.github/workflows/ignite-docs-test.yml
@@ -48,7 +48,7 @@ jobs:
- name: Install package
run: |
- python setup.py install
+ pip install .
- name: Run Integration test
run: |
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 8c25c743..9f0c090b 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -48,7 +48,7 @@ jobs:
- name: Install package
run: |
- python setup.py install
+ pip install .
pip install pytest
- name: Run Tests
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..33a0f9f8
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,50 @@
+[build-system]
+requires = ["setuptools>=61", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "sphinxcontrib-versioning"
+dynamic = ["version"]
+description = "Sphinx extension that allows building versioned docs for PyTorch-Ignite"
+readme = "README.rst"
+license = { text = "MIT" }
+authors = [{ name = "PyTorch-Ignite Team", email = "contact@pytorch-ignite.ai" }]
+keywords = ["sphinx", "versioning", "versions", "version", "branches", "tags"]
+classifiers = [
+ "Development Status :: 5 - Production/Stable",
+ "Environment :: Console",
+ "Framework :: Sphinx :: Extension",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: MIT License",
+ "Operating System :: MacOS",
+ "Operating System :: POSIX :: Linux",
+ "Operating System :: POSIX",
+ "Programming Language :: Python :: 3",
+ "Topic :: Documentation :: Sphinx",
+ "Topic :: Software Development :: Documentation",
+]
+requires-python = ">=3.8"
+dependencies = ["click", "colorclass", "sphinx>5"]
+
+[project.urls]
+Homepage = "https://github.com/pytorch-ignite/sphinxcontrib-versioning/"
+
+[project.scripts]
+sphinx-versioning = "sphinxcontrib_versioning.__main__:cli"
+
+[tool.setuptools.dynamic]
+version = { attr = "sphinxcontrib_versioning.__version__" }
+
+[tool.setuptools.packages.find]
+exclude = ["tests", "tests.*"]
+
+[tool.setuptools.package-data]
+"*" = [
+ "_static/banner.css",
+ "_templates/banner.html",
+ "_templates/layout.html",
+ "_templates/versions.html",
+]
+
+[tool.pytest.ini_options]
+log_level = "DEBUG"
diff --git a/sphinxcontrib_versioning/__main__.py b/sphinxcontrib_versioning/__main__.py
index 032bf04a..72d8fb65 100755
--- a/sphinxcontrib_versioning/__main__.py
+++ b/sphinxcontrib_versioning/__main__.py
@@ -141,12 +141,12 @@ def get_params(self, ctx):
is_flag=True,
)
@click.option(
- "-mc", "--use-master-conf", help="Use conf.py file from master branch", is_flag=True
+ "-mc", "--use-main-conf", help="Use conf.py file from main branch", is_flag=True
)
@click.option(
"-mt",
- "--use-master-templates",
- help="Copy _templates folder from master branch",
+ "--use-main-templates",
+ help="Copy _templates folder from main branch",
is_flag=True,
)
@click.option(
@@ -248,7 +248,7 @@ def build_options(func):
func = click.option(
"-B",
"--banner-main-ref",
- help="Don't show banner on this ref and point banner URLs to this ref. Default master.",
+ help="Don't show banner on this ref and point banner URLs to this ref. Default main.",
)(func)
func = click.option(
"-i", "--invert", help="Invert/reverse order of versions.", is_flag=True
@@ -262,7 +262,7 @@ def build_options(func):
func = click.option(
"-r",
"--root-ref",
- help="The branch/tag at the root of DESTINATION. Will also be in subdir. Default master.",
+ help="The branch/tag at the root of DESTINATION. Will also be in subdir. Default main.",
)(func)
func = click.option(
"-s",
@@ -359,8 +359,6 @@ def build(config, rel_source, destination, **options):
if "pre" in config:
config.pop("pre")(rel_source)
config.update({k: v for k, v in options.items() if v})
- if config.local_conf:
- config.update(read_local_conf(config.local_conf), ignore_set=True)
if NO_EXECUTE:
raise RuntimeError(config, rel_source, destination)
log = logging.getLogger(__name__)
@@ -424,7 +422,7 @@ def build(config, rel_source, destination, **options):
# Pre-build.
log.info("Pre-running Sphinx to collect versions' master_doc and other info.")
exported_root = pre_build(
- config.git_root, versions, config.use_master_conf, config.use_master_templates
+ config.git_root, versions, config.use_main_conf, config.use_main_templates
)
if config.banner_main_ref and config.banner_main_ref not in [
r["name"] for r in versions.remotes
diff --git a/sphinxcontrib_versioning/lib.py b/sphinxcontrib_versioning/lib.py
index 3f9e0fb6..3dadfcd1 100644
--- a/sphinxcontrib_versioning/lib.py
+++ b/sphinxcontrib_versioning/lib.py
@@ -26,19 +26,19 @@ def __init__(self):
self.invert = False
self.no_colors = False
self.no_local_conf = False
- self.use_master_conf = False
- self.use_master_templates = False
+ self.use_main_conf = False
+ self.use_main_templates = False
self.recent_tag = False
self.show_banner = False
# Strings.
- self.banner_main_ref = "master"
+ self.banner_main_ref = "main"
self.chdir = None
self.git_root = None
self.local_conf = None
self.priority = None
self.push_remote = "origin"
- self.root_ref = "master"
+ self.root_ref = "main"
# Tuples.
self.grm_exclude = tuple()
diff --git a/sphinxcontrib_versioning/routines.py b/sphinxcontrib_versioning/routines.py
index dcddb864..513c96a2 100644
--- a/sphinxcontrib_versioning/routines.py
+++ b/sphinxcontrib_versioning/routines.py
@@ -23,9 +23,11 @@
def read_local_conf(local_conf):
"""Search for conf.py in any rel_source directory in CWD and if found read it and return.
+ Only settings that differ from their defaults are returned.
+
:param str local_conf: Path to conf.py to read.
- :return: Loaded conf.py.
+ :return: Loaded conf.py settings that differ from defaults.
:rtype: dict
"""
log = logging.getLogger(__name__)
@@ -38,12 +40,23 @@ def read_local_conf(local_conf):
log.warning("Unable to read file, continuing with only CLI args.")
return dict()
- # Filter and return.
- return {
- k[4:]: v
- for k, v in config.items()
- if k.startswith("scv_") and not k[4:].startswith("_")
- }
+ # Filter to only return scv_* settings that differ from their defaults.
+ default_config = Config()
+ result = {}
+ for k, v in config.items():
+ if not k.startswith("scv_") or k[4:].startswith("_"):
+ continue
+ key = k[4:]
+ default_val = getattr(default_config, key, None)
+ try:
+ differs = v != default_val
+ except Exception:
+ differs = v is not default_val
+ if differs:
+ result[key] = v
+
+ log.debug("Read settings from conf.py: %s", result)
+ return result
def gather_git_info(root, conf_rel_paths, whitelist_branches, whitelist_tags):
@@ -124,7 +137,7 @@ def gather_git_info(root, conf_rel_paths, whitelist_branches, whitelist_tags):
return whitelisted_remotes
-def pre_build(local_root, versions, use_master_conf=False, use_master_templates=False):
+def pre_build(local_root, versions, use_main_conf=False, use_main_templates=False):
"""Build docs for all versions to determine root directory and master_doc names.
Need to build docs to (a) avoid filename collision with files from root_ref and branch/tag names and (b) determine
@@ -148,27 +161,29 @@ def pre_build(local_root, versions, use_master_conf=False, use_master_templates=
log.debug("Exporting %s to temporary directory.", sha)
export(local_root, sha, target)
- # Copy conf.py from local master to all branches and tags
- if use_master_conf:
- master_remote = [r for r in list(versions.remotes) if r["name"] == "master"]
- assert len(master_remote) == 1
- master_remote = master_remote[0]
- master_conf_file = master_remote["conf_rel_path"]
+ root_ref = Config.from_context().root_ref
+
+ # Copy conf.py from local main to all branches and tags
+ if use_main_conf:
+ main_remote = [r for r in list(versions.remotes) if r["name"] == root_ref]
+ assert len(main_remote) == 1
+ main_remote = main_remote[0]
+ main_conf_file = main_remote["conf_rel_path"]
for remote in list(versions.remotes):
import shutil
filename = os.path.join(
exported_root, remote["sha"], remote["conf_rel_path"]
)
- shutil.copy(master_conf_file, filename)
-
- if use_master_templates:
- master_remote = [r for r in list(versions.remotes) if r["name"] == "master"]
- assert len(master_remote) == 1
- master_remote = master_remote[0]
- rel_path = os.path.dirname(master_remote["conf_rel_path"])
- master_templates = os.path.join(rel_path, "_templates")
- if os.path.exists(master_templates) and os.path.isdir(master_templates):
+ shutil.copy(main_conf_file, filename)
+
+ if use_main_templates:
+ main_remote = [r for r in list(versions.remotes) if r["name"] == root_ref]
+ assert len(main_remote) == 1
+ main_remote = main_remote[0]
+ rel_path = os.path.dirname(main_remote["conf_rel_path"])
+ main_templates = os.path.join(rel_path, "_templates")
+ if os.path.exists(main_templates) and os.path.isdir(main_templates):
for remote in list(versions.remotes):
import shutil
@@ -177,10 +192,10 @@ def pre_build(local_root, versions, use_master_conf=False, use_master_templates=
)
if os.path.exists(dst_path):
shutil.rmtree(dst_path)
- shutil.copytree(master_templates, dst_path)
+ shutil.copytree(main_templates, dst_path)
# Build root.
- remote = versions[Config.from_context().root_ref]
+ remote = versions[root_ref]
with TempDir() as temp_dir:
log.debug(
"Building root (before setting root_dirs) in temporary directory: %s",
@@ -189,7 +204,7 @@ def pre_build(local_root, versions, use_master_conf=False, use_master_templates=
source = os.path.dirname(
os.path.join(exported_root, remote["sha"], remote["conf_rel_path"])
)
- code_version = f"master ({remote['sha8']})" if remote["name"] == "master" else remote["name"]
+ code_version = f"{root_ref} ({remote['sha8']})" if remote["name"] == root_ref else remote["name"]
os.environ["code_version"] = code_version
build(source, temp_dir, versions, remote["name"], True)
os.environ.pop("code_version")
@@ -234,14 +249,16 @@ def build_all(exported_root, destination, versions):
"""
log = logging.getLogger(__name__)
+ root_ref = Config.from_context().root_ref
+
while True:
# Build root.
- remote = versions[Config.from_context().root_ref]
+ remote = versions[root_ref]
log.info("Building root: %s", remote["name"])
source = os.path.dirname(
os.path.join(exported_root, remote["sha"], remote["conf_rel_path"])
)
- code_version = f"master ({remote['sha8']})" if remote["name"] == "master" else remote["name"]
+ code_version = f"{root_ref} ({remote['sha8']})" if remote["name"] == root_ref else remote["name"]
os.environ["code_version"] = code_version
build(source, destination, versions, remote["name"], True)
os.environ.pop("code_version")
@@ -254,7 +271,7 @@ def build_all(exported_root, destination, versions):
)
target = os.path.join(destination, remote["root_dir"])
try:
- code_version = f"master ({remote['sha8']})" if remote["name"] == "master" else remote["name"]
+ code_version = f"{root_ref} ({remote['sha8']})" if remote["name"] == root_ref else remote["name"]
os.environ["code_version"] = code_version
build(source, target, versions, remote["name"], False)
os.environ.pop("code_version")
diff --git a/sphinxcontrib_versioning/sphinx_.py b/sphinxcontrib_versioning/sphinx_.py
index b224c944..d217aed5 100644
--- a/sphinxcontrib_versioning/sphinx_.py
+++ b/sphinxcontrib_versioning/sphinx_.py
@@ -80,8 +80,14 @@ def env_updated(cls, app, env):
for n in (a for a in dir(app.config) if a.startswith("scv_"))
}
config["found_docs"] = tuple(str(d) for d in env.found_docs)
- config["master_doc"] = str(app.config.master_doc)
+ # Sphinx 4+ renamed master_doc to root_doc; support both.
+ master_doc = getattr(app.config, "root_doc", None) or getattr(
+ app.config, "master_doc", "index"
+ )
+ config["master_doc"] = str(master_doc)
cls.ABORT_AFTER_READ.put(config)
+ cls.ABORT_AFTER_READ.close()
+ cls.ABORT_AFTER_READ.join_thread()
sys.exit(0)
@classmethod
@@ -151,7 +157,7 @@ def html_page_context(cls, app, pagename, templatename, context, doctree):
)
mtime = datetime.datetime.fromtimestamp(os.path.getmtime(file_path))
context["last_updated"] = format_date(
- lufmt, mtime, language=app.config.language
+ lufmt, date=mtime, language=app.config.language
)
@@ -191,6 +197,22 @@ def __init__(self, *args):
super(ConfigInject, self).__init__(*args)
self.extensions.append("sphinxcontrib_versioning.sphinx_")
+ @classmethod
+ def read(cls, confdir, *, overrides, tags):
+ """Override to ensure ConfigInject is used when conf.py exists.
+
+ In Sphinx >=7, Config.read() calls _read_conf_py() which hardcodes Config()
+ instead of cls(), so subclassing alone is not sufficient.
+ """
+ import sphinx.config as _sphinx_config
+
+ _orig = _sphinx_config.Config
+ _sphinx_config.Config = cls
+ try:
+ return super().read(confdir, overrides=overrides, tags=tags)
+ finally:
+ _sphinx_config.Config = _orig
+
def _build(argv, config, versions, current_name, is_root):
"""Build Sphinx docs via multiprocessing for isolation.
diff --git a/sphinxcontrib_versioning/versions.py b/sphinxcontrib_versioning/versions.py
index 727854e7..47f42230 100644
--- a/sphinxcontrib_versioning/versions.py
+++ b/sphinxcontrib_versioning/versions.py
@@ -116,9 +116,9 @@ def __init__(self, remotes, sort=None, priority=None, invert=False):
sha=r[0], # str
name=r[1], # str
kind=r[2], # str
- sha8=r[3], # str
- date=r[4], # int
- conf_rel_path=r[5], # str
+ sha8=r[3] if len(r) > 5 else r[0][:8], # str
+ date=r[4] if len(r) > 5 else r[3], # int
+ conf_rel_path=r[5] if len(r) > 5 else r[4], # str
found_docs=tuple(), # tuple of str
master_doc="contents", # str
root_dir=r[1], # str
diff --git a/tests/conftest.py b/tests/conftest.py
index f80c4a47..f2e5d1ec 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -54,6 +54,7 @@ def pytest_configure():
:rtype: dict
"""
pytest.run = run
+ pytest.author_committer_dates = author_committer_dates
@pytest.fixture
@@ -253,7 +254,7 @@ def fx_local_docs(local):
:return: Path to repo root.
:rtype: py.path.local
"""
- local.ensure("conf.py")
+ local.join("conf.py").write('project = "Python"\nmaster_doc = "contents"\n')
local.join("contents.rst").write(
"Test\n"
"====\n"
diff --git a/tests/test_routines/test_build_all.py b/tests/test_routines/test_build_all.py
index 9cdb4add..ad63dee4 100644
--- a/tests/test_routines/test_build_all.py
+++ b/tests/test_routines/test_build_all.py
@@ -50,11 +50,11 @@ def test_single(tmpdir, local_docs, urls):
# Verify HTML links.
urls(
destination.join("contents.html"),
- ['
main'],
+ ['main'],
)
urls(
destination.join("main", "contents.html"),
- ['main'],
+ ['main'],
)
@@ -119,29 +119,29 @@ def test_multiple(tmpdir, config, local_docs, urls, triple, parallel):
# Verify root HTML links.
expected = [
- 'main',
- 'v1.0.0',
+ 'main',
+ 'v1.0.0',
]
if triple:
- expected.append('v1.0.1')
+ expected.append('v1.0.1')
urls(destination.join("contents.html"), expected)
# Verify main links.
expected = [
- 'main',
- 'v1.0.0',
+ 'main',
+ 'v1.0.0',
]
if triple:
- expected.append('v1.0.1')
+ expected.append('v1.0.1')
urls(destination.join("main", "contents.html"), expected)
# Verify v1.0.0 links.
expected = [
- 'main',
- 'v1.0.0',
+ 'main',
+ 'v1.0.0',
]
if triple:
- expected.append('v1.0.1')
+ expected.append('v1.0.1')
urls(destination.join("v1.0.0", "contents.html"), expected)
if not triple:
return
@@ -150,9 +150,9 @@ def test_multiple(tmpdir, config, local_docs, urls, triple, parallel):
urls(
destination.join("v1.0.1", "contents.html"),
[
- 'main',
- 'v1.0.0',
- 'v1.0.1',
+ 'main',
+ 'v1.0.0',
+ 'v1.0.1',
],
)
@@ -374,9 +374,7 @@ def test_last_updated(tmpdir, local_docs):
:param tmpdir: pytest fixture.
:param local_docs: conftest fixture.
"""
- local_docs.join("conf.py").write(
- 'html_last_updated_fmt = "%c"\n' 'html_theme="sphinx_rtd_theme"\n'
- )
+ local_docs.join("conf.py").write('html_last_updated_fmt = "%c"\nmaster_doc = "contents"\nhtml_theme = "basic"\n')
local_docs.join("two.rst").write("Changed\n", mode="a")
pytest.run(
local_docs,
@@ -411,18 +409,22 @@ def test_last_updated(tmpdir, local_docs):
destination = tmpdir.ensure_dir("destination")
build_all(str(exported_root), str(destination), versions)
+ # Python 3.12 uses narrow no-break space (U+202F) between time and AM/PM
+ def normalize_time(s):
+ return s.replace("\u202f", " ")
+
# Verify main.
- one = RE_LAST_UPDATED.findall(destination.join("main", "one.html").read())
- two = RE_LAST_UPDATED.findall(destination.join("main", "two.html").read())
- three = RE_LAST_UPDATED.findall(destination.join("main", "three.html").read())
+ one = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("main", "one.html").read())]
+ two = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("main", "two.html").read())]
+ three = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("main", "three.html").read())]
assert one == ["Last updated on Dec 5, 2016, 3:20:05 AM.\n"]
assert two == ["Last updated on Dec 5, 2016, 3:27:05 AM.\n"]
assert three == ["Last updated on Dec 5, 2016, 3:20:05 AM.\n"]
# Verify other.
- one = RE_LAST_UPDATED.findall(destination.join("other", "one.html").read())
- two = RE_LAST_UPDATED.findall(destination.join("other", "two.html").read())
- three = RE_LAST_UPDATED.findall(destination.join("other", "three.html").read())
+ one = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("other", "one.html").read())]
+ two = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("other", "two.html").read())]
+ three = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("other", "three.html").read())]
assert one == ["Last updated on Dec 5, 2016, 3:20:05 AM.\n"]
assert two == ["Last updated on Dec 5, 2016, 3:27:05 AM.\n"]
assert three == ["Last updated on Dec 5, 2016, 3:28:05 AM.\n"]
@@ -479,9 +481,9 @@ def test_error(tmpdir, config, local_docs, urls, parallel):
urls(
destination.join("contents.html"),
[
- 'a_good',
- 'c_good',
- 'main',
+ 'a_good',
+ 'c_good',
+ 'main',
],
)
@@ -489,9 +491,9 @@ def test_error(tmpdir, config, local_docs, urls, parallel):
urls(
destination.join("a_good", "contents.html"),
[
- 'a_good',
- 'c_good',
- 'main',
+ 'a_good',
+ 'c_good',
+ 'main',
],
)
@@ -499,9 +501,9 @@ def test_error(tmpdir, config, local_docs, urls, parallel):
urls(
destination.join("c_good", "contents.html"),
[
- 'a_good',
- 'c_good',
- 'main',
+ 'a_good',
+ 'c_good',
+ 'main',
],
)
@@ -509,9 +511,9 @@ def test_error(tmpdir, config, local_docs, urls, parallel):
urls(
destination.join("main", "contents.html"),
[
- 'a_good',
- 'c_good',
- 'main',
+ 'a_good',
+ 'c_good',
+ 'main',
],
)
@@ -551,9 +553,9 @@ def test_all_errors(tmpdir, local_docs, urls):
# Verify root HTML links.
urls(
destination.join("contents.html"),
- ['main'],
+ ['main'],
)
urls(
destination.join("main", "contents.html"),
- ['main'],
+ ['main'],
)
diff --git a/tests/test_routines/test_gather_git_info.py b/tests/test_routines/test_gather_git_info.py
index b45c2b34..710c7548 100644
--- a/tests/test_routines/test_gather_git_info.py
+++ b/tests/test_routines/test_gather_git_info.py
@@ -23,7 +23,7 @@ def test_working(local):
["annotated_tag", "tags"],
["light_tag", "tags"],
]
- assert [i[1:-2] for i in filtered_remotes] == expected
+ assert [i[1:-3] for i in filtered_remotes] == expected
@pytest.mark.parametrize("wlb", [False, True])
@@ -54,7 +54,7 @@ def test_whitelisting(local, wlb, wlt):
filtered_remotes = gather_git_info(
str(local), [os.path.join(".", "README")], whitelist_branches, whitelist_tags
)
- assert [i[1:-2] for i in filtered_remotes] == expected
+ assert [i[1:-3] for i in filtered_remotes] == expected
@pytest.mark.usefixtures("outdate_local")
@@ -84,7 +84,7 @@ def test_fetch(monkeypatch, caplog, local, skip_fetch):
["nb_tag", "tags"],
["ob_at", "tags"],
]
- assert [i[1:-2] for i in filtered_remotes] == expected
+ assert [i[1:-3] for i in filtered_remotes] == expected
records = [(r.levelname, r.message) for r in caplog.records]
assert ("INFO", "Need to fetch from remote...") in records
diff --git a/tests/test_routines/test_pre_build.py b/tests/test_routines/test_pre_build.py
index b9e3bae9..b9769fb5 100644
--- a/tests/test_routines/test_pre_build.py
+++ b/tests/test_routines/test_pre_build.py
@@ -21,12 +21,12 @@ def test_single(local_docs):
# Run and verify directory.
exported_root = py.path.local(pre_build(str(local_docs), versions))
assert len(exported_root.listdir()) == 1
- assert exported_root.join(versions["main"]["sha"], "conf.py").read() == ""
+ assert exported_root.join(versions["main"]["sha"], "conf.py").read() == 'project = "Python"\nmaster_doc = "contents"\n'
- # Verify root_dir and main_doc..
+ # Verify root_dir and master_doc.
expected = ["main/contents"]
assert (
- sorted(posixpath.join(r["root_dir"], r["main_doc"]) for r in versions.remotes)
+ sorted(posixpath.join(r["root_dir"], r["master_doc"]) for r in versions.remotes)
== expected
)
@@ -49,16 +49,16 @@ def test_dual(local_docs):
# Run and verify directory.
exported_root = py.path.local(pre_build(str(local_docs), versions))
assert len(exported_root.listdir()) == 2
- assert exported_root.join(versions["main"]["sha"], "conf.py").read() == ""
+ assert exported_root.join(versions["main"]["sha"], "conf.py").read() == 'project = "Python"\nmaster_doc = "contents"\n'
assert (
exported_root.join(versions["feature"]["sha"], "conf.py").read()
== 'main_doc = "index"\n'
)
- # Verify versions root_dirs and main_docs.
+ # Verify versions root_dirs and master_docs.
expected = ["feature/index", "main/contents"]
assert (
- sorted(posixpath.join(r["root_dir"], r["main_doc"]) for r in versions.remotes)
+ sorted(posixpath.join(r["root_dir"], r["master_doc"]) for r in versions.remotes)
== expected
)
@@ -78,7 +78,7 @@ def test_file_collision(local_docs):
pre_build(str(local_docs), versions)
expected = ["_static_/contents", "main/contents"]
assert (
- sorted(posixpath.join(r["root_dir"], r["main_doc"]) for r in versions.remotes)
+ sorted(posixpath.join(r["root_dir"], r["master_doc"]) for r in versions.remotes)
== expected
)
@@ -98,7 +98,7 @@ def test_invalid_name(local_docs):
pre_build(str(local_docs), versions)
expected = ["main/contents", "robpol86_feature/contents"]
assert (
- sorted(posixpath.join(r["root_dir"], r["main_doc"]) for r in versions.remotes)
+ sorted(posixpath.join(r["root_dir"], r["master_doc"]) for r in versions.remotes)
== expected
)
diff --git a/tests/test_routines/test_read_local_conf.py b/tests/test_routines/test_read_local_conf.py
index d5835297..cfcab7e5 100644
--- a/tests/test_routines/test_read_local_conf.py
+++ b/tests/test_routines/test_read_local_conf.py
@@ -31,7 +31,8 @@ def test_empty(tmpdir, caplog, error):
"Unable to read file, continuing with only CLI args.",
)
else:
- assert [r[0] for r in records] == ["INFO", "DEBUG"]
+ assert records[0][0] == "INFO"
+ assert any(r[0] == "DEBUG" for r in records)
assert config == dict()
diff --git a/tests/test_sphinx/test_read_config.py b/tests/test_sphinx/test_read_config.py
index 676f3200..95f59967 100644
--- a/tests/test_sphinx/test_read_config.py
+++ b/tests/test_sphinx/test_read_config.py
@@ -27,7 +27,7 @@ def test(config, local_docs, mode):
config = read_config(str(local_docs), "main")
if mode == "default":
- assert config["master_doc"] == "index"
+ assert config["master_doc"] == "contents"
else:
assert config["master_doc"] == expected
assert sorted(config["found_docs"]) == [expected, "one", "three", "two"]
From 325e6da11b8d71d656b5a60e2369c971a3c69a5b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 8 Mar 2026 00:56:43 +0000
Subject: [PATCH 3/5] Address review: revert use_master_*, restore
read_local_conf, remove setup.py, update pyproject.toml
Co-authored-by: vfdev-5 <2459423+vfdev-5@users.noreply.github.com>
---
pyproject.toml | 4 +-
setup.py | 80 ----------------------------
sphinxcontrib_versioning/__main__.py | 10 ++--
sphinxcontrib_versioning/lib.py | 4 +-
sphinxcontrib_versioning/routines.py | 34 ++++++------
tests/test__main__/test_arguments.py | 28 +++++-----
tests/test_lib.py | 4 +-
7 files changed, 43 insertions(+), 121 deletions(-)
delete mode 100755 setup.py
diff --git a/pyproject.toml b/pyproject.toml
index 33a0f9f8..a2389225 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -23,8 +23,8 @@ classifiers = [
"Topic :: Documentation :: Sphinx",
"Topic :: Software Development :: Documentation",
]
-requires-python = ">=3.8"
-dependencies = ["click", "colorclass", "sphinx>5"]
+requires-python = ">=3.10"
+dependencies = ["click", "colorclass", "sphinx>5,<10"]
[project.urls]
Homepage = "https://github.com/pytorch-ignite/sphinxcontrib-versioning/"
diff --git a/setup.py b/setup.py
deleted file mode 100755
index 9584da4e..00000000
--- a/setup.py
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env python
-"""Setup script for the project."""
-
-import io
-import os
-import re
-
-from setuptools import find_packages, setup
-
-
-INSTALL_REQUIRES = ["click", "colorclass", "sphinx>5"]
-LICENSE = "MIT"
-NAME = "sphinxcontrib-versioning"
-
-
-def read(*names, **kwargs):
- with io.open(
- os.path.join(os.path.dirname(__file__), *names),
- encoding=kwargs.get("encoding", "utf8"),
- ) as fp:
- return fp.read()
-
-
-def find_version(*file_paths):
- version_file = read(*file_paths)
- version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M)
- if version_match:
- return version_match.group(1)
- raise RuntimeError("Unable to find version string.")
-
-
-VERSION = find_version("sphinxcontrib_versioning", "__init__.py")
-readme = read("README.rst")
-
-
-if __name__ == "__main__":
- setup(
- author="PyTorch-Ignite Team",
- author_email="contact@pytorch-ignite.ai",
- classifiers=[
- "Development Status :: 5 - Production/Stable",
- "Environment :: Console",
- "Framework :: Sphinx :: Extension",
- "Intended Audience :: Developers",
- "License :: OSI Approved :: MIT License",
- "Operating System :: MacOS",
- "Operating System :: POSIX :: Linux",
- "Operating System :: POSIX",
- "Programming Language :: Python :: 2.7",
- "Programming Language :: Python :: 3.3",
- "Programming Language :: Python :: 3.4",
- "Programming Language :: Python :: 3.5",
- "Programming Language :: Python :: Implementation :: PyPy",
- "Topic :: Documentation :: Sphinx",
- "Topic :: Software Development :: Documentation",
- ],
- description="Sphinx extension that allows building versioned docs for PyTorch-Ignite",
- entry_points={
- "console_scripts": [
- "sphinx-versioning = sphinxcontrib_versioning.__main__:cli"
- ]
- },
- install_requires=INSTALL_REQUIRES,
- keywords="sphinx versioning versions version branches tags",
- license=LICENSE,
- long_description=readme,
- name=NAME,
- package_data={
- "": [
- os.path.join("_static", "banner.css"),
- os.path.join("_templates", "banner.html"),
- os.path.join("_templates", "layout.html"),
- os.path.join("_templates", "versions.html"),
- ]
- },
- packages=find_packages(exclude=("tests", "tests.*")),
- url="https://github.com/pytorch-ignite/{NAME}/",
- version=VERSION,
- zip_safe=False,
- )
diff --git a/sphinxcontrib_versioning/__main__.py b/sphinxcontrib_versioning/__main__.py
index 72d8fb65..f4defbf8 100755
--- a/sphinxcontrib_versioning/__main__.py
+++ b/sphinxcontrib_versioning/__main__.py
@@ -141,12 +141,12 @@ def get_params(self, ctx):
is_flag=True,
)
@click.option(
- "-mc", "--use-main-conf", help="Use conf.py file from main branch", is_flag=True
+ "-mc", "--use-master-conf", help="Use conf.py file from master branch", is_flag=True
)
@click.option(
"-mt",
- "--use-main-templates",
- help="Copy _templates folder from main branch",
+ "--use-master-templates",
+ help="Copy _templates folder from master branch",
is_flag=True,
)
@click.option(
@@ -359,6 +359,8 @@ def build(config, rel_source, destination, **options):
if "pre" in config:
config.pop("pre")(rel_source)
config.update({k: v for k, v in options.items() if v})
+ if config.local_conf:
+ config.update(read_local_conf(config.local_conf), ignore_set=True)
if NO_EXECUTE:
raise RuntimeError(config, rel_source, destination)
log = logging.getLogger(__name__)
@@ -422,7 +424,7 @@ def build(config, rel_source, destination, **options):
# Pre-build.
log.info("Pre-running Sphinx to collect versions' master_doc and other info.")
exported_root = pre_build(
- config.git_root, versions, config.use_main_conf, config.use_main_templates
+ config.git_root, versions, config.use_master_conf, config.use_master_templates
)
if config.banner_main_ref and config.banner_main_ref not in [
r["name"] for r in versions.remotes
diff --git a/sphinxcontrib_versioning/lib.py b/sphinxcontrib_versioning/lib.py
index 3dadfcd1..4318e02b 100644
--- a/sphinxcontrib_versioning/lib.py
+++ b/sphinxcontrib_versioning/lib.py
@@ -26,8 +26,8 @@ def __init__(self):
self.invert = False
self.no_colors = False
self.no_local_conf = False
- self.use_main_conf = False
- self.use_main_templates = False
+ self.use_master_conf = False
+ self.use_master_templates = False
self.recent_tag = False
self.show_banner = False
diff --git a/sphinxcontrib_versioning/routines.py b/sphinxcontrib_versioning/routines.py
index 513c96a2..e4a91220 100644
--- a/sphinxcontrib_versioning/routines.py
+++ b/sphinxcontrib_versioning/routines.py
@@ -137,7 +137,7 @@ def gather_git_info(root, conf_rel_paths, whitelist_branches, whitelist_tags):
return whitelisted_remotes
-def pre_build(local_root, versions, use_main_conf=False, use_main_templates=False):
+def pre_build(local_root, versions, use_master_conf=False, use_master_templates=False):
"""Build docs for all versions to determine root directory and master_doc names.
Need to build docs to (a) avoid filename collision with files from root_ref and branch/tag names and (b) determine
@@ -163,27 +163,27 @@ def pre_build(local_root, versions, use_main_conf=False, use_main_templates=Fals
root_ref = Config.from_context().root_ref
- # Copy conf.py from local main to all branches and tags
- if use_main_conf:
- main_remote = [r for r in list(versions.remotes) if r["name"] == root_ref]
- assert len(main_remote) == 1
- main_remote = main_remote[0]
- main_conf_file = main_remote["conf_rel_path"]
+ # Copy conf.py from local master to all branches and tags
+ if use_master_conf:
+ master_remote = [r for r in list(versions.remotes) if r["name"] == root_ref]
+ assert len(master_remote) == 1
+ master_remote = master_remote[0]
+ master_conf_file = master_remote["conf_rel_path"]
for remote in list(versions.remotes):
import shutil
filename = os.path.join(
exported_root, remote["sha"], remote["conf_rel_path"]
)
- shutil.copy(main_conf_file, filename)
-
- if use_main_templates:
- main_remote = [r for r in list(versions.remotes) if r["name"] == root_ref]
- assert len(main_remote) == 1
- main_remote = main_remote[0]
- rel_path = os.path.dirname(main_remote["conf_rel_path"])
- main_templates = os.path.join(rel_path, "_templates")
- if os.path.exists(main_templates) and os.path.isdir(main_templates):
+ shutil.copy(master_conf_file, filename)
+
+ if use_master_templates:
+ master_remote = [r for r in list(versions.remotes) if r["name"] == root_ref]
+ assert len(master_remote) == 1
+ master_remote = master_remote[0]
+ rel_path = os.path.dirname(master_remote["conf_rel_path"])
+ master_templates = os.path.join(rel_path, "_templates")
+ if os.path.exists(master_templates) and os.path.isdir(master_templates):
for remote in list(versions.remotes):
import shutil
@@ -192,7 +192,7 @@ def pre_build(local_root, versions, use_main_conf=False, use_main_templates=Fals
)
if os.path.exists(dst_path):
shutil.rmtree(dst_path)
- shutil.copytree(main_templates, dst_path)
+ shutil.copytree(master_templates, dst_path)
# Build root.
remote = versions[root_ref]
diff --git a/tests/test__main__/test_arguments.py b/tests/test__main__/test_arguments.py
index ba99f6fc..d4a684a3 100644
--- a/tests/test__main__/test_arguments.py
+++ b/tests/test__main__/test_arguments.py
@@ -1,5 +1,6 @@
"""Test mixing sources of arguments/settings."""
+import re
from os.path import join
import pytest
@@ -48,8 +49,7 @@ def test_overflow(local_empty, source_cli, source_conf):
if source_cli:
assert config.overflow == ("-D", "setting=value")
elif source_conf:
- # assert config.overflow == ("-D", "key=value")
- assert config.overflow == tuple()
+ assert config.overflow == ("-D", "key=value")
else:
assert config.overflow == tuple()
@@ -262,18 +262,18 @@ def test_sub_command_options(local_empty, source_cli, source_conf):
assert config.whitelist_branches == ("main",)
assert config.whitelist_tags == ("[0-9]",)
elif source_conf:
- assert config.banner_greatest_tag is False
- assert config.banner_main_ref in ("main", "master")
- assert config.banner_recent_tag is False
- assert config.greatest_tag is False
- assert config.invert is False
- assert config.priority is None
- assert config.recent_tag is False
- assert config.root_ref in ("main", "master")
- assert config.show_banner is False
- assert config.sort == ()
- assert config.whitelist_branches == ()
- assert config.whitelist_tags == ()
+ assert config.banner_greatest_tag is True
+ assert config.banner_main_ref == "y"
+ assert config.banner_recent_tag is True
+ assert config.greatest_tag is True
+ assert config.invert is True
+ assert config.priority == "tags"
+ assert config.recent_tag is True
+ assert config.root_ref == "other"
+ assert config.show_banner is True
+ assert config.sort == ("alpha",)
+ assert config.whitelist_branches == ("other",)
+ assert config.whitelist_tags == re.compile("^[0-9]$")
else:
assert config.banner_greatest_tag is False
assert config.banner_main_ref in ("main", "master")
diff --git a/tests/test_lib.py b/tests/test_lib.py
index 0020c8eb..cac6e674 100644
--- a/tests/test_lib.py
+++ b/tests/test_lib.py
@@ -45,8 +45,8 @@ def test_config():
("root_ref", "main"),
("show_banner", False),
("sort", tuple()),
- ("use_main_conf", False),
- ("use_main_templates", False),
+ ("use_master_conf", False),
+ ("use_master_templates", False),
("verbose", 1),
("whitelist_branches", tuple()),
("whitelist_tags", tuple()),
From 5fe0e75d108fe787851be83c537bf79b4fbbf12a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 8 Mar 2026 22:31:12 +0000
Subject: [PATCH 4/5] Revert all non-pyproject changes; pin Sphinx to >=7,<8
Co-authored-by: vfdev-5 <2459423+vfdev-5@users.noreply.github.com>
---
pyproject.toml | 2 +-
sphinxcontrib_versioning/__main__.py | 4 +-
sphinxcontrib_versioning/lib.py | 4 +-
sphinxcontrib_versioning/routines.py | 45 ++++--------
sphinxcontrib_versioning/sphinx_.py | 26 +------
sphinxcontrib_versioning/versions.py | 6 +-
tests/conftest.py | 3 +-
tests/test__main__/test_arguments.py | 28 ++++----
tests/test_lib.py | 4 +-
tests/test_routines/test_build_all.py | 76 ++++++++++-----------
tests/test_routines/test_gather_git_info.py | 6 +-
tests/test_routines/test_pre_build.py | 16 ++---
tests/test_routines/test_read_local_conf.py | 3 +-
tests/test_sphinx/test_read_config.py | 2 +-
14 files changed, 91 insertions(+), 134 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index a2389225..98737826 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,7 @@ classifiers = [
"Topic :: Software Development :: Documentation",
]
requires-python = ">=3.10"
-dependencies = ["click", "colorclass", "sphinx>5,<10"]
+dependencies = ["click", "colorclass", "sphinx>=7,<8"]
[project.urls]
Homepage = "https://github.com/pytorch-ignite/sphinxcontrib-versioning/"
diff --git a/sphinxcontrib_versioning/__main__.py b/sphinxcontrib_versioning/__main__.py
index f4defbf8..032bf04a 100755
--- a/sphinxcontrib_versioning/__main__.py
+++ b/sphinxcontrib_versioning/__main__.py
@@ -248,7 +248,7 @@ def build_options(func):
func = click.option(
"-B",
"--banner-main-ref",
- help="Don't show banner on this ref and point banner URLs to this ref. Default main.",
+ help="Don't show banner on this ref and point banner URLs to this ref. Default master.",
)(func)
func = click.option(
"-i", "--invert", help="Invert/reverse order of versions.", is_flag=True
@@ -262,7 +262,7 @@ def build_options(func):
func = click.option(
"-r",
"--root-ref",
- help="The branch/tag at the root of DESTINATION. Will also be in subdir. Default main.",
+ help="The branch/tag at the root of DESTINATION. Will also be in subdir. Default master.",
)(func)
func = click.option(
"-s",
diff --git a/sphinxcontrib_versioning/lib.py b/sphinxcontrib_versioning/lib.py
index 4318e02b..3f9e0fb6 100644
--- a/sphinxcontrib_versioning/lib.py
+++ b/sphinxcontrib_versioning/lib.py
@@ -32,13 +32,13 @@ def __init__(self):
self.show_banner = False
# Strings.
- self.banner_main_ref = "main"
+ self.banner_main_ref = "master"
self.chdir = None
self.git_root = None
self.local_conf = None
self.priority = None
self.push_remote = "origin"
- self.root_ref = "main"
+ self.root_ref = "master"
# Tuples.
self.grm_exclude = tuple()
diff --git a/sphinxcontrib_versioning/routines.py b/sphinxcontrib_versioning/routines.py
index e4a91220..dcddb864 100644
--- a/sphinxcontrib_versioning/routines.py
+++ b/sphinxcontrib_versioning/routines.py
@@ -23,11 +23,9 @@
def read_local_conf(local_conf):
"""Search for conf.py in any rel_source directory in CWD and if found read it and return.
- Only settings that differ from their defaults are returned.
-
:param str local_conf: Path to conf.py to read.
- :return: Loaded conf.py settings that differ from defaults.
+ :return: Loaded conf.py.
:rtype: dict
"""
log = logging.getLogger(__name__)
@@ -40,23 +38,12 @@ def read_local_conf(local_conf):
log.warning("Unable to read file, continuing with only CLI args.")
return dict()
- # Filter to only return scv_* settings that differ from their defaults.
- default_config = Config()
- result = {}
- for k, v in config.items():
- if not k.startswith("scv_") or k[4:].startswith("_"):
- continue
- key = k[4:]
- default_val = getattr(default_config, key, None)
- try:
- differs = v != default_val
- except Exception:
- differs = v is not default_val
- if differs:
- result[key] = v
-
- log.debug("Read settings from conf.py: %s", result)
- return result
+ # Filter and return.
+ return {
+ k[4:]: v
+ for k, v in config.items()
+ if k.startswith("scv_") and not k[4:].startswith("_")
+ }
def gather_git_info(root, conf_rel_paths, whitelist_branches, whitelist_tags):
@@ -161,11 +148,9 @@ def pre_build(local_root, versions, use_master_conf=False, use_master_templates=
log.debug("Exporting %s to temporary directory.", sha)
export(local_root, sha, target)
- root_ref = Config.from_context().root_ref
-
# Copy conf.py from local master to all branches and tags
if use_master_conf:
- master_remote = [r for r in list(versions.remotes) if r["name"] == root_ref]
+ master_remote = [r for r in list(versions.remotes) if r["name"] == "master"]
assert len(master_remote) == 1
master_remote = master_remote[0]
master_conf_file = master_remote["conf_rel_path"]
@@ -178,7 +163,7 @@ def pre_build(local_root, versions, use_master_conf=False, use_master_templates=
shutil.copy(master_conf_file, filename)
if use_master_templates:
- master_remote = [r for r in list(versions.remotes) if r["name"] == root_ref]
+ master_remote = [r for r in list(versions.remotes) if r["name"] == "master"]
assert len(master_remote) == 1
master_remote = master_remote[0]
rel_path = os.path.dirname(master_remote["conf_rel_path"])
@@ -195,7 +180,7 @@ def pre_build(local_root, versions, use_master_conf=False, use_master_templates=
shutil.copytree(master_templates, dst_path)
# Build root.
- remote = versions[root_ref]
+ remote = versions[Config.from_context().root_ref]
with TempDir() as temp_dir:
log.debug(
"Building root (before setting root_dirs) in temporary directory: %s",
@@ -204,7 +189,7 @@ def pre_build(local_root, versions, use_master_conf=False, use_master_templates=
source = os.path.dirname(
os.path.join(exported_root, remote["sha"], remote["conf_rel_path"])
)
- code_version = f"{root_ref} ({remote['sha8']})" if remote["name"] == root_ref else remote["name"]
+ code_version = f"master ({remote['sha8']})" if remote["name"] == "master" else remote["name"]
os.environ["code_version"] = code_version
build(source, temp_dir, versions, remote["name"], True)
os.environ.pop("code_version")
@@ -249,16 +234,14 @@ def build_all(exported_root, destination, versions):
"""
log = logging.getLogger(__name__)
- root_ref = Config.from_context().root_ref
-
while True:
# Build root.
- remote = versions[root_ref]
+ remote = versions[Config.from_context().root_ref]
log.info("Building root: %s", remote["name"])
source = os.path.dirname(
os.path.join(exported_root, remote["sha"], remote["conf_rel_path"])
)
- code_version = f"{root_ref} ({remote['sha8']})" if remote["name"] == root_ref else remote["name"]
+ code_version = f"master ({remote['sha8']})" if remote["name"] == "master" else remote["name"]
os.environ["code_version"] = code_version
build(source, destination, versions, remote["name"], True)
os.environ.pop("code_version")
@@ -271,7 +254,7 @@ def build_all(exported_root, destination, versions):
)
target = os.path.join(destination, remote["root_dir"])
try:
- code_version = f"{root_ref} ({remote['sha8']})" if remote["name"] == root_ref else remote["name"]
+ code_version = f"master ({remote['sha8']})" if remote["name"] == "master" else remote["name"]
os.environ["code_version"] = code_version
build(source, target, versions, remote["name"], False)
os.environ.pop("code_version")
diff --git a/sphinxcontrib_versioning/sphinx_.py b/sphinxcontrib_versioning/sphinx_.py
index d217aed5..b224c944 100644
--- a/sphinxcontrib_versioning/sphinx_.py
+++ b/sphinxcontrib_versioning/sphinx_.py
@@ -80,14 +80,8 @@ def env_updated(cls, app, env):
for n in (a for a in dir(app.config) if a.startswith("scv_"))
}
config["found_docs"] = tuple(str(d) for d in env.found_docs)
- # Sphinx 4+ renamed master_doc to root_doc; support both.
- master_doc = getattr(app.config, "root_doc", None) or getattr(
- app.config, "master_doc", "index"
- )
- config["master_doc"] = str(master_doc)
+ config["master_doc"] = str(app.config.master_doc)
cls.ABORT_AFTER_READ.put(config)
- cls.ABORT_AFTER_READ.close()
- cls.ABORT_AFTER_READ.join_thread()
sys.exit(0)
@classmethod
@@ -157,7 +151,7 @@ def html_page_context(cls, app, pagename, templatename, context, doctree):
)
mtime = datetime.datetime.fromtimestamp(os.path.getmtime(file_path))
context["last_updated"] = format_date(
- lufmt, date=mtime, language=app.config.language
+ lufmt, mtime, language=app.config.language
)
@@ -197,22 +191,6 @@ def __init__(self, *args):
super(ConfigInject, self).__init__(*args)
self.extensions.append("sphinxcontrib_versioning.sphinx_")
- @classmethod
- def read(cls, confdir, *, overrides, tags):
- """Override to ensure ConfigInject is used when conf.py exists.
-
- In Sphinx >=7, Config.read() calls _read_conf_py() which hardcodes Config()
- instead of cls(), so subclassing alone is not sufficient.
- """
- import sphinx.config as _sphinx_config
-
- _orig = _sphinx_config.Config
- _sphinx_config.Config = cls
- try:
- return super().read(confdir, overrides=overrides, tags=tags)
- finally:
- _sphinx_config.Config = _orig
-
def _build(argv, config, versions, current_name, is_root):
"""Build Sphinx docs via multiprocessing for isolation.
diff --git a/sphinxcontrib_versioning/versions.py b/sphinxcontrib_versioning/versions.py
index 47f42230..727854e7 100644
--- a/sphinxcontrib_versioning/versions.py
+++ b/sphinxcontrib_versioning/versions.py
@@ -116,9 +116,9 @@ def __init__(self, remotes, sort=None, priority=None, invert=False):
sha=r[0], # str
name=r[1], # str
kind=r[2], # str
- sha8=r[3] if len(r) > 5 else r[0][:8], # str
- date=r[4] if len(r) > 5 else r[3], # int
- conf_rel_path=r[5] if len(r) > 5 else r[4], # str
+ sha8=r[3], # str
+ date=r[4], # int
+ conf_rel_path=r[5], # str
found_docs=tuple(), # tuple of str
master_doc="contents", # str
root_dir=r[1], # str
diff --git a/tests/conftest.py b/tests/conftest.py
index f2e5d1ec..f80c4a47 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -54,7 +54,6 @@ def pytest_configure():
:rtype: dict
"""
pytest.run = run
- pytest.author_committer_dates = author_committer_dates
@pytest.fixture
@@ -254,7 +253,7 @@ def fx_local_docs(local):
:return: Path to repo root.
:rtype: py.path.local
"""
- local.join("conf.py").write('project = "Python"\nmaster_doc = "contents"\n')
+ local.ensure("conf.py")
local.join("contents.rst").write(
"Test\n"
"====\n"
diff --git a/tests/test__main__/test_arguments.py b/tests/test__main__/test_arguments.py
index d4a684a3..ba99f6fc 100644
--- a/tests/test__main__/test_arguments.py
+++ b/tests/test__main__/test_arguments.py
@@ -1,6 +1,5 @@
"""Test mixing sources of arguments/settings."""
-import re
from os.path import join
import pytest
@@ -49,7 +48,8 @@ def test_overflow(local_empty, source_cli, source_conf):
if source_cli:
assert config.overflow == ("-D", "setting=value")
elif source_conf:
- assert config.overflow == ("-D", "key=value")
+ # assert config.overflow == ("-D", "key=value")
+ assert config.overflow == tuple()
else:
assert config.overflow == tuple()
@@ -262,18 +262,18 @@ def test_sub_command_options(local_empty, source_cli, source_conf):
assert config.whitelist_branches == ("main",)
assert config.whitelist_tags == ("[0-9]",)
elif source_conf:
- assert config.banner_greatest_tag is True
- assert config.banner_main_ref == "y"
- assert config.banner_recent_tag is True
- assert config.greatest_tag is True
- assert config.invert is True
- assert config.priority == "tags"
- assert config.recent_tag is True
- assert config.root_ref == "other"
- assert config.show_banner is True
- assert config.sort == ("alpha",)
- assert config.whitelist_branches == ("other",)
- assert config.whitelist_tags == re.compile("^[0-9]$")
+ assert config.banner_greatest_tag is False
+ assert config.banner_main_ref in ("main", "master")
+ assert config.banner_recent_tag is False
+ assert config.greatest_tag is False
+ assert config.invert is False
+ assert config.priority is None
+ assert config.recent_tag is False
+ assert config.root_ref in ("main", "master")
+ assert config.show_banner is False
+ assert config.sort == ()
+ assert config.whitelist_branches == ()
+ assert config.whitelist_tags == ()
else:
assert config.banner_greatest_tag is False
assert config.banner_main_ref in ("main", "master")
diff --git a/tests/test_lib.py b/tests/test_lib.py
index cac6e674..0020c8eb 100644
--- a/tests/test_lib.py
+++ b/tests/test_lib.py
@@ -45,8 +45,8 @@ def test_config():
("root_ref", "main"),
("show_banner", False),
("sort", tuple()),
- ("use_master_conf", False),
- ("use_master_templates", False),
+ ("use_main_conf", False),
+ ("use_main_templates", False),
("verbose", 1),
("whitelist_branches", tuple()),
("whitelist_tags", tuple()),
diff --git a/tests/test_routines/test_build_all.py b/tests/test_routines/test_build_all.py
index ad63dee4..9cdb4add 100644
--- a/tests/test_routines/test_build_all.py
+++ b/tests/test_routines/test_build_all.py
@@ -50,11 +50,11 @@ def test_single(tmpdir, local_docs, urls):
# Verify HTML links.
urls(
destination.join("contents.html"),
- ['main'],
+ ['main'],
)
urls(
destination.join("main", "contents.html"),
- ['main'],
+ ['main'],
)
@@ -119,29 +119,29 @@ def test_multiple(tmpdir, config, local_docs, urls, triple, parallel):
# Verify root HTML links.
expected = [
- 'main',
- 'v1.0.0',
+ 'main',
+ 'v1.0.0',
]
if triple:
- expected.append('v1.0.1')
+ expected.append('v1.0.1')
urls(destination.join("contents.html"), expected)
# Verify main links.
expected = [
- 'main',
- 'v1.0.0',
+ 'main',
+ 'v1.0.0',
]
if triple:
- expected.append('v1.0.1')
+ expected.append('v1.0.1')
urls(destination.join("main", "contents.html"), expected)
# Verify v1.0.0 links.
expected = [
- 'main',
- 'v1.0.0',
+ 'main',
+ 'v1.0.0',
]
if triple:
- expected.append('v1.0.1')
+ expected.append('v1.0.1')
urls(destination.join("v1.0.0", "contents.html"), expected)
if not triple:
return
@@ -150,9 +150,9 @@ def test_multiple(tmpdir, config, local_docs, urls, triple, parallel):
urls(
destination.join("v1.0.1", "contents.html"),
[
- 'main',
- 'v1.0.0',
- 'v1.0.1',
+ 'main',
+ 'v1.0.0',
+ 'v1.0.1',
],
)
@@ -374,7 +374,9 @@ def test_last_updated(tmpdir, local_docs):
:param tmpdir: pytest fixture.
:param local_docs: conftest fixture.
"""
- local_docs.join("conf.py").write('html_last_updated_fmt = "%c"\nmaster_doc = "contents"\nhtml_theme = "basic"\n')
+ local_docs.join("conf.py").write(
+ 'html_last_updated_fmt = "%c"\n' 'html_theme="sphinx_rtd_theme"\n'
+ )
local_docs.join("two.rst").write("Changed\n", mode="a")
pytest.run(
local_docs,
@@ -409,22 +411,18 @@ def test_last_updated(tmpdir, local_docs):
destination = tmpdir.ensure_dir("destination")
build_all(str(exported_root), str(destination), versions)
- # Python 3.12 uses narrow no-break space (U+202F) between time and AM/PM
- def normalize_time(s):
- return s.replace("\u202f", " ")
-
# Verify main.
- one = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("main", "one.html").read())]
- two = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("main", "two.html").read())]
- three = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("main", "three.html").read())]
+ one = RE_LAST_UPDATED.findall(destination.join("main", "one.html").read())
+ two = RE_LAST_UPDATED.findall(destination.join("main", "two.html").read())
+ three = RE_LAST_UPDATED.findall(destination.join("main", "three.html").read())
assert one == ["Last updated on Dec 5, 2016, 3:20:05 AM.\n"]
assert two == ["Last updated on Dec 5, 2016, 3:27:05 AM.\n"]
assert three == ["Last updated on Dec 5, 2016, 3:20:05 AM.\n"]
# Verify other.
- one = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("other", "one.html").read())]
- two = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("other", "two.html").read())]
- three = [normalize_time(s) for s in RE_LAST_UPDATED.findall(destination.join("other", "three.html").read())]
+ one = RE_LAST_UPDATED.findall(destination.join("other", "one.html").read())
+ two = RE_LAST_UPDATED.findall(destination.join("other", "two.html").read())
+ three = RE_LAST_UPDATED.findall(destination.join("other", "three.html").read())
assert one == ["Last updated on Dec 5, 2016, 3:20:05 AM.\n"]
assert two == ["Last updated on Dec 5, 2016, 3:27:05 AM.\n"]
assert three == ["Last updated on Dec 5, 2016, 3:28:05 AM.\n"]
@@ -481,9 +479,9 @@ def test_error(tmpdir, config, local_docs, urls, parallel):
urls(
destination.join("contents.html"),
[
- 'a_good',
- 'c_good',
- 'main',
+ 'a_good',
+ 'c_good',
+ 'main',
],
)
@@ -491,9 +489,9 @@ def test_error(tmpdir, config, local_docs, urls, parallel):
urls(
destination.join("a_good", "contents.html"),
[
- 'a_good',
- 'c_good',
- 'main',
+ 'a_good',
+ 'c_good',
+ 'main',
],
)
@@ -501,9 +499,9 @@ def test_error(tmpdir, config, local_docs, urls, parallel):
urls(
destination.join("c_good", "contents.html"),
[
- 'a_good',
- 'c_good',
- 'main',
+ 'a_good',
+ 'c_good',
+ 'main',
],
)
@@ -511,9 +509,9 @@ def test_error(tmpdir, config, local_docs, urls, parallel):
urls(
destination.join("main", "contents.html"),
[
- 'a_good',
- 'c_good',
- 'main',
+ 'a_good',
+ 'c_good',
+ 'main',
],
)
@@ -553,9 +551,9 @@ def test_all_errors(tmpdir, local_docs, urls):
# Verify root HTML links.
urls(
destination.join("contents.html"),
- ['main'],
+ ['main'],
)
urls(
destination.join("main", "contents.html"),
- ['main'],
+ ['main'],
)
diff --git a/tests/test_routines/test_gather_git_info.py b/tests/test_routines/test_gather_git_info.py
index 710c7548..b45c2b34 100644
--- a/tests/test_routines/test_gather_git_info.py
+++ b/tests/test_routines/test_gather_git_info.py
@@ -23,7 +23,7 @@ def test_working(local):
["annotated_tag", "tags"],
["light_tag", "tags"],
]
- assert [i[1:-3] for i in filtered_remotes] == expected
+ assert [i[1:-2] for i in filtered_remotes] == expected
@pytest.mark.parametrize("wlb", [False, True])
@@ -54,7 +54,7 @@ def test_whitelisting(local, wlb, wlt):
filtered_remotes = gather_git_info(
str(local), [os.path.join(".", "README")], whitelist_branches, whitelist_tags
)
- assert [i[1:-3] for i in filtered_remotes] == expected
+ assert [i[1:-2] for i in filtered_remotes] == expected
@pytest.mark.usefixtures("outdate_local")
@@ -84,7 +84,7 @@ def test_fetch(monkeypatch, caplog, local, skip_fetch):
["nb_tag", "tags"],
["ob_at", "tags"],
]
- assert [i[1:-3] for i in filtered_remotes] == expected
+ assert [i[1:-2] for i in filtered_remotes] == expected
records = [(r.levelname, r.message) for r in caplog.records]
assert ("INFO", "Need to fetch from remote...") in records
diff --git a/tests/test_routines/test_pre_build.py b/tests/test_routines/test_pre_build.py
index b9769fb5..b9e3bae9 100644
--- a/tests/test_routines/test_pre_build.py
+++ b/tests/test_routines/test_pre_build.py
@@ -21,12 +21,12 @@ def test_single(local_docs):
# Run and verify directory.
exported_root = py.path.local(pre_build(str(local_docs), versions))
assert len(exported_root.listdir()) == 1
- assert exported_root.join(versions["main"]["sha"], "conf.py").read() == 'project = "Python"\nmaster_doc = "contents"\n'
+ assert exported_root.join(versions["main"]["sha"], "conf.py").read() == ""
- # Verify root_dir and master_doc.
+ # Verify root_dir and main_doc..
expected = ["main/contents"]
assert (
- sorted(posixpath.join(r["root_dir"], r["master_doc"]) for r in versions.remotes)
+ sorted(posixpath.join(r["root_dir"], r["main_doc"]) for r in versions.remotes)
== expected
)
@@ -49,16 +49,16 @@ def test_dual(local_docs):
# Run and verify directory.
exported_root = py.path.local(pre_build(str(local_docs), versions))
assert len(exported_root.listdir()) == 2
- assert exported_root.join(versions["main"]["sha"], "conf.py").read() == 'project = "Python"\nmaster_doc = "contents"\n'
+ assert exported_root.join(versions["main"]["sha"], "conf.py").read() == ""
assert (
exported_root.join(versions["feature"]["sha"], "conf.py").read()
== 'main_doc = "index"\n'
)
- # Verify versions root_dirs and master_docs.
+ # Verify versions root_dirs and main_docs.
expected = ["feature/index", "main/contents"]
assert (
- sorted(posixpath.join(r["root_dir"], r["master_doc"]) for r in versions.remotes)
+ sorted(posixpath.join(r["root_dir"], r["main_doc"]) for r in versions.remotes)
== expected
)
@@ -78,7 +78,7 @@ def test_file_collision(local_docs):
pre_build(str(local_docs), versions)
expected = ["_static_/contents", "main/contents"]
assert (
- sorted(posixpath.join(r["root_dir"], r["master_doc"]) for r in versions.remotes)
+ sorted(posixpath.join(r["root_dir"], r["main_doc"]) for r in versions.remotes)
== expected
)
@@ -98,7 +98,7 @@ def test_invalid_name(local_docs):
pre_build(str(local_docs), versions)
expected = ["main/contents", "robpol86_feature/contents"]
assert (
- sorted(posixpath.join(r["root_dir"], r["master_doc"]) for r in versions.remotes)
+ sorted(posixpath.join(r["root_dir"], r["main_doc"]) for r in versions.remotes)
== expected
)
diff --git a/tests/test_routines/test_read_local_conf.py b/tests/test_routines/test_read_local_conf.py
index cfcab7e5..d5835297 100644
--- a/tests/test_routines/test_read_local_conf.py
+++ b/tests/test_routines/test_read_local_conf.py
@@ -31,8 +31,7 @@ def test_empty(tmpdir, caplog, error):
"Unable to read file, continuing with only CLI args.",
)
else:
- assert records[0][0] == "INFO"
- assert any(r[0] == "DEBUG" for r in records)
+ assert [r[0] for r in records] == ["INFO", "DEBUG"]
assert config == dict()
diff --git a/tests/test_sphinx/test_read_config.py b/tests/test_sphinx/test_read_config.py
index 95f59967..676f3200 100644
--- a/tests/test_sphinx/test_read_config.py
+++ b/tests/test_sphinx/test_read_config.py
@@ -27,7 +27,7 @@ def test(config, local_docs, mode):
config = read_config(str(local_docs), "main")
if mode == "default":
- assert config["master_doc"] == "contents"
+ assert config["master_doc"] == "index"
else:
assert config["master_doc"] == expected
assert sorted(config["found_docs"]) == [expected, "one", "three", "two"]
From 2552b7479b0fb987b972ef22fc58d464278bbf52 Mon Sep 17 00:00:00 2001
From: vfdev
Date: Sun, 8 Mar 2026 23:36:27 +0100
Subject: [PATCH 5/5] Update sphinx dependency version range
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 98737826..2b672ffb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,7 @@ classifiers = [
"Topic :: Software Development :: Documentation",
]
requires-python = ">=3.10"
-dependencies = ["click", "colorclass", "sphinx>=7,<8"]
+dependencies = ["click", "colorclass", "sphinx>=5,<6"]
[project.urls]
Homepage = "https://github.com/pytorch-ignite/sphinxcontrib-versioning/"