diff --git a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py index 6b5d56a4392..a9f21d11940 100644 --- a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py +++ b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py @@ -60,17 +60,45 @@ def write_peps_json(peps: list[parser.PEP], path: Path) -> None: Path(path, "api", "peps.json").write_text(json_peps, encoding="utf-8") +def build_release_peps(peps: list[parser.PEP]) -> dict[str, int]: + """Map each Python version to its release-schedule PEP number. + + Handles release PEPs that cover multiple versions jointly + (e.g. "2.6, 3.0"), so individual versions also resolve. + """ + release_peps: dict[str, int] = {} + + for pep in peps: + if pep.python_version and "release" in pep.topic: + for version in map(str.strip, pep.python_version.split(",")): + release_peps[version] = pep.number + + return release_peps + + def create_pep_zero(app: Sphinx, env: BuildEnvironment, docnames: list[str]) -> None: peps = _parse_peps(Path(app.srcdir)) - numerical_index_text = writer.PEPZeroWriter().write_numerical_index(peps) + release_peps = build_release_peps(peps) + + numerical_index_text = writer.PEPZeroWriter( + release_peps + ).write_numerical_index(peps) subindices.update_sphinx("numerical", numerical_index_text, docnames, env) - pep0_text = writer.PEPZeroWriter().write_pep0(peps, builder=env.settings["builder"]) + pep0_text = writer.PEPZeroWriter( + release_peps + ).write_pep0(peps, builder=env.settings["builder"]) pep0_path = subindices.update_sphinx("pep-0000", pep0_text, docnames, env) peps.append(parser.PEP(pep0_path)) - subindices.generate_subindices(SUBINDICES_BY_TOPIC, peps, docnames, env) + subindices.generate_subindices( + SUBINDICES_BY_TOPIC, + peps, + release_peps, + docnames, + env, + ) write_peps_json(peps, Path(app.outdir)) diff --git a/pep_sphinx_extensions/pep_zero_generator/subindices.py b/pep_sphinx_extensions/pep_zero_generator/subindices.py index 83ca7f069ff..fdf167d6049 100644 --- a/pep_sphinx_extensions/pep_zero_generator/subindices.py +++ b/pep_sphinx_extensions/pep_zero_generator/subindices.py @@ -35,6 +35,7 @@ def update_sphinx(filename: str, text: str, docnames: list[str], env: BuildEnvir def generate_subindices( subindices: dict[str, str], peps: list[PEP], + release_peps: dict[str, int], docnames: list[str], env: BuildEnvironment, ) -> None: @@ -58,8 +59,11 @@ def generate_subindices( {additional_description} """ - subindex_text = writer.PEPZeroWriter().write_pep0( - filtered_peps, header, subindex_intro, is_pep0=False, + subindex_text = writer.PEPZeroWriter(release_peps).write_pep0( + filtered_peps, + header, + subindex_intro, + is_pep0=False, ) update_sphinx(f"topic/{subindex}", subindex_text, docnames, env) diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index c00860c7a8c..a5033149bb5 100644 --- a/pep_sphinx_extensions/pep_zero_generator/writer.py +++ b/pep_sphinx_extensions/pep_zero_generator/writer.py @@ -59,8 +59,9 @@ class PEPZeroWriter: 801: "Warsaw", } - def __init__(self): + def __init__(self, release_peps: dict[str, int] | None = None): self.output: list[str] = [] + self.release_peps = release_peps or {} def emit_text(self, content: str) -> None: # Appends content argument to the output list @@ -87,7 +88,17 @@ def emit_pep_row( self.emit_text(f" - :pep:`{title.replace('`', '')} <{number}>`") self.emit_text(f" - {authors}") if python_version is not None: - self.emit_text(f" - {python_version}") + linked_versions = [] + + for version in map(str.strip, python_version.split(",")): + release_pep = self.release_peps.get(version) + + if release_pep is not None: + linked_versions.append(f":pep:`{version} <{release_pep}>`") + else: + linked_versions.append(version) + + self.emit_text(f" - {', '.join(linked_versions)}") def emit_column_headers(self, *, include_version=True) -> None: """Output the column headers for the PEP indices.""" diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py index 75c16f624b0..4c492a42af3 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py @@ -9,3 +9,13 @@ def test_create_pep_json(): out = pep_index_generator.create_pep_json(peps) assert '"url": "https://peps.python.org/pep-0008/"' in out + + +def test_build_release_peps_links_individual_versions_from_joint_release_pep(): + peps = [ + parser.PEP(PEP_ROOT / "pep-0361.rst"), # "2.6, 3.0" joint release PEP + ] + + release_peps = pep_index_generator.build_release_peps(peps) + + assert release_peps == {"2.6": 361, "3.0": 361} diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py index 3237dfb0562..f8f36e62e74 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py @@ -86,3 +86,42 @@ def test_sort_authors(): # Assert assert out == ["Aardvark, Alfred", "lowercase, laurence", "Zebra, Zoƫ"] + + +@pytest.mark.parametrize( + ("python_version", "expected"), + [ + ("3.14", " - :pep:`3.14 <745>`"), + ( + "2.4, 2.5, 2.6", + " - :pep:`2.4 <320>`, :pep:`2.5 <356>`, :pep:`2.6 <361>`", + ), + ("2.4, 2.9", " - :pep:`2.4 <320>`, 2.9"), + ("1.5.2", " - 1.5.2"), + ("", " - "), + ], +) +def test_emit_pep_row_links_python_version_to_release_pep( + python_version, + expected, +): + # Arrange + release_peps = { + "2.4": 320, + "2.5": 356, + "2.6": 361, + "3.14": 745, + } + pep0_writer = writer.PEPZeroWriter(release_peps=release_peps) + + # Act + pep0_writer.emit_pep_row( + shorthand="Active", + number=999, + title="Test PEP", + authors="Test Author", + python_version=python_version, + ) + + # Assert + assert expected in pep0_writer.output