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/"