From bfc2b3522bf050db95a9c3dfd0d990749391aaae Mon Sep 17 00:00:00 2001 From: Bhuvansh855 Date: Sat, 25 Jul 2026 20:41:08 +0530 Subject: [PATCH 1/7] gh-4379: Link target release to release PEP in PEP 0 --- .../pep_zero_generator/pep_index_generator.py | 15 +++++++++++++-- .../pep_zero_generator/writer.py | 12 ++++++++++-- .../tests/pep_zero_generator/test_writer.py | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) 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..ac3e51e9ff4 100644 --- a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py +++ b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py @@ -63,10 +63,21 @@ def write_peps_json(peps: list[parser.PEP], path: Path) -> None: 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 = { + pep.python_version: pep.number + for pep in peps + if pep.python_version + and "release" in pep.topic + } + + 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)) diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index c00860c7a8c..8289474c161 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,14 @@ 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}") + pep_number = self.release_peps.get(python_version) + + if pep_number is not None: + self.emit_text( + f" - :pep:`{python_version} <{pep_number}>`" + ) + else: + self.emit_text(f" - {python_version}") 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_writer.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py index 3237dfb0562..4407f8f8224 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,20 @@ def test_sort_authors(): # Assert assert out == ["Aardvark, Alfred", "lowercase, laurence", "Zebra, Zoë"] + + +def test_emit_pep_row_links_python_version_to_release_pep(): + # Arrange + pep0_writer = writer.PEPZeroWriter(release_peps={"3.14": 745}) + + # Act + pep0_writer.emit_pep_row( + shorthand="Active", + number=999, + title="Test PEP", + authors="Test Author", + python_version="3.14", + ) + + # Assert + assert " - :pep:`3.14 <745>`" in pep0_writer.output From 5291550a38c395768c30d2b760ff19914706a612 Mon Sep 17 00:00:00 2001 From: Bhuvansh855 Date: Sun, 26 Jul 2026 23:04:46 +0530 Subject: [PATCH 2/7] gh-4379: Link release PEPs in topic pages --- .../pep_zero_generator/pep_index_generator.py | 8 +++++- .../pep_zero_generator/subindices.py | 8 ++++-- .../tests/pep_zero_generator/test_writer.py | 25 ++++++++++++++++--- 3 files changed, 34 insertions(+), 7 deletions(-) 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 ac3e51e9ff4..00cc8a5d489 100644 --- a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py +++ b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py @@ -81,7 +81,13 @@ def create_pep_zero(app: Sphinx, env: BuildEnvironment, docnames: list[str]) -> 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/tests/pep_zero_generator/test_writer.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py index 4407f8f8224..04f45397340 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py @@ -88,9 +88,26 @@ def test_sort_authors(): assert out == ["Aardvark, Alfred", "lowercase, laurence", "Zebra, Zoë"] -def test_emit_pep_row_links_python_version_to_release_pep(): +@pytest.mark.parametrize( + ("python_version", "release_peps", "expected"), + [ + ("3.14", {"3.14": 745}, " - :pep:`3.14 <745>`"), + ("2.6, 3.0", {"2.6, 3.0": 361}, " - :pep:`2.6, 3.0 <361>`"), + ("2.7, 3.1", {"2.7, 3.1": 375}, " - :pep:`2.7, 3.1 <375>`"), + ( + "2.4, 2.5, 2.6", + {"2.4, 2.5, 2.6": 320}, + " - :pep:`2.4, 2.5, 2.6 <320>`", + ), + ], +) +def test_emit_pep_row_links_python_version_to_release_pep( + python_version, + release_peps, + expected, +): # Arrange - pep0_writer = writer.PEPZeroWriter(release_peps={"3.14": 745}) + pep0_writer = writer.PEPZeroWriter(release_peps=release_peps) # Act pep0_writer.emit_pep_row( @@ -98,8 +115,8 @@ def test_emit_pep_row_links_python_version_to_release_pep(): number=999, title="Test PEP", authors="Test Author", - python_version="3.14", + python_version=python_version, ) # Assert - assert " - :pep:`3.14 <745>`" in pep0_writer.output + assert expected in pep0_writer.output From 23fee339b234f83780794660580001249ca666a1 Mon Sep 17 00:00:00 2001 From: Bhuvansh855 Date: Sun, 26 Jul 2026 23:21:21 +0530 Subject: [PATCH 3/7] gh-4379: Link release PEPs individually when needed --- pep_sphinx_extensions/pep_zero_generator/writer.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index 8289474c161..168a69595bf 100644 --- a/pep_sphinx_extensions/pep_zero_generator/writer.py +++ b/pep_sphinx_extensions/pep_zero_generator/writer.py @@ -95,7 +95,19 @@ def emit_pep_row( f" - :pep:`{python_version} <{pep_number}>`" ) else: - self.emit_text(f" - {python_version}") + versions = [version.strip() for version in python_version.split(",")] + + linked_versions = [] + for version in versions: + 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.""" From 4cd910376f91edf793efc5fc287b29fa1b75d2d6 Mon Sep 17 00:00:00 2001 From: Bhuvansh855 Date: Mon, 27 Jul 2026 12:53:19 +0530 Subject: [PATCH 4/7] gh-4379: Fix release_peps mapping to link individual versions from joint release PEPs --- .../pep_zero_generator/pep_index_generator.py | 34 +++++++++++++++---- .../test_pep_index_generator.py | 12 +++++++ 2 files changed, 40 insertions(+), 6 deletions(-) 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 00cc8a5d489..46acc79ba10 100644 --- a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py +++ b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py @@ -60,15 +60,37 @@ 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] = {} + release_versions = { + pep.python_version + for pep in peps + if pep.python_version and "release" in pep.topic + } + + for pep in peps: + if not pep.python_version or "release" not in pep.topic: + continue + + release_peps[pep.python_version] = pep.number + + if "," in pep.python_version: + for version in map(str.strip, pep.python_version.split(",")): + if version not in release_versions: + 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)) - release_peps = { - pep.python_version: pep.number - for pep in peps - if pep.python_version - and "release" in pep.topic - } + release_peps = build_release_peps(peps) numerical_index_text = writer.PEPZeroWriter( release_peps 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..1467e595f2a 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,15 @@ 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, 3.0"] == 361 + assert release_peps["2.6"] == 361 + assert release_peps["3.0"] == 361 From 7a2b1eeff090160789cbb34091b6a4be3d0a0bd2 Mon Sep 17 00:00:00 2001 From: Bhuvansh855 Date: Mon, 27 Jul 2026 19:36:35 +0530 Subject: [PATCH 5/7] Link standalone versions from joint release PEPs --- .../pep_zero_generator/pep_index_generator.py | 15 ++------- .../pep_zero_generator/writer.py | 31 +++++++------------ .../test_pep_index_generator.py | 1 - .../tests/pep_zero_generator/test_writer.py | 21 ++++++++----- 4 files changed, 28 insertions(+), 40 deletions(-) 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 46acc79ba10..a9f21d11940 100644 --- a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py +++ b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py @@ -67,22 +67,11 @@ def build_release_peps(peps: list[parser.PEP]) -> dict[str, int]: (e.g. "2.6, 3.0"), so individual versions also resolve. """ release_peps: dict[str, int] = {} - release_versions = { - pep.python_version - for pep in peps - if pep.python_version and "release" in pep.topic - } for pep in peps: - if not pep.python_version or "release" not in pep.topic: - continue - - release_peps[pep.python_version] = pep.number - - if "," in pep.python_version: + if pep.python_version and "release" in pep.topic: for version in map(str.strip, pep.python_version.split(",")): - if version not in release_versions: - release_peps[version] = pep.number + release_peps[version] = pep.number return release_peps diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index 168a69595bf..99dc551296d 100644 --- a/pep_sphinx_extensions/pep_zero_generator/writer.py +++ b/pep_sphinx_extensions/pep_zero_generator/writer.py @@ -88,26 +88,19 @@ def emit_pep_row( self.emit_text(f" - :pep:`{title.replace('`', '')} <{number}>`") self.emit_text(f" - {authors}") if python_version is not None: - pep_number = self.release_peps.get(python_version) + linked_versions = [] - if pep_number is not None: - self.emit_text( - f" - :pep:`{python_version} <{pep_number}>`" - ) - else: - versions = [version.strip() for version in python_version.split(",")] - - linked_versions = [] - for version in versions: - 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)}") + 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 1467e595f2a..1ff79e6ce55 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 @@ -18,6 +18,5 @@ def test_build_release_peps_links_individual_versions_from_joint_release_pep(): release_peps = pep_index_generator.build_release_peps(peps) - assert release_peps["2.6, 3.0"] == 361 assert release_peps["2.6"] == 361 assert release_peps["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 04f45397340..9da87e9eea4 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py @@ -88,22 +88,29 @@ def test_sort_authors(): assert out == ["Aardvark, Alfred", "lowercase, laurence", "Zebra, Zoë"] +release_peps = { + "2.4": 320, + "2.5": 356, + "2.6": 361, +} + + @pytest.mark.parametrize( - ("python_version", "release_peps", "expected"), + ("python_version", "expected"), [ - ("3.14", {"3.14": 745}, " - :pep:`3.14 <745>`"), - ("2.6, 3.0", {"2.6, 3.0": 361}, " - :pep:`2.6, 3.0 <361>`"), - ("2.7, 3.1", {"2.7, 3.1": 375}, " - :pep:`2.7, 3.1 <375>`"), + ("3.14", " - 3.14"), ( "2.4, 2.5, 2.6", - {"2.4, 2.5, 2.6": 320}, - " - :pep:`2.4, 2.5, 2.6 <320>`", + " - :pep:`2.4 <320>`, :pep:`2.5 <356>`, :pep:`2.6 <361>`", + ), + ( + "2.4, 2.9", + " - :pep:`2.4 <320>`, 2.9", ), ], ) def test_emit_pep_row_links_python_version_to_release_pep( python_version, - release_peps, expected, ): # Arrange From 6bb3cc5b6afa80d16137056d06db3dd25e970aaa Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 27 Jul 2026 17:43:22 +0300 Subject: [PATCH 6/7] Update tests, unwrap formatting Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- .../pep_zero_generator/writer.py | 4 +--- .../test_pep_index_generator.py | 3 +-- .../tests/pep_zero_generator/test_writer.py | 21 +++++++++---------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py index 99dc551296d..a5033149bb5 100644 --- a/pep_sphinx_extensions/pep_zero_generator/writer.py +++ b/pep_sphinx_extensions/pep_zero_generator/writer.py @@ -94,9 +94,7 @@ def emit_pep_row( release_pep = self.release_peps.get(version) if release_pep is not None: - linked_versions.append( - f":pep:`{version} <{release_pep}>`" - ) + linked_versions.append(f":pep:`{version} <{release_pep}>`") else: linked_versions.append(version) 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 1ff79e6ce55..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 @@ -18,5 +18,4 @@ def test_build_release_peps_links_individual_versions_from_joint_release_pep(): release_peps = pep_index_generator.build_release_peps(peps) - assert release_peps["2.6"] == 361 - assert release_peps["3.0"] == 361 + 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 9da87e9eea4..0a98e482b4d 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py @@ -88,25 +88,18 @@ def test_sort_authors(): assert out == ["Aardvark, Alfred", "lowercase, laurence", "Zebra, Zoë"] -release_peps = { - "2.4": 320, - "2.5": 356, - "2.6": 361, -} - - @pytest.mark.parametrize( ("python_version", "expected"), [ - ("3.14", " - 3.14"), + ("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", - ), + ("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( @@ -114,6 +107,12 @@ def test_emit_pep_row_links_python_version_to_release_pep( 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 From 16a3eacc1fa6fdfe5da4d1b8c156afe99197c51c Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 27 Jul 2026 17:45:21 +0300 Subject: [PATCH 7/7] Remove extra parenthesis --- pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py | 1 - 1 file changed, 1 deletion(-) 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 0a98e482b4d..f8f36e62e74 100644 --- a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py +++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py @@ -96,7 +96,6 @@ def test_sort_authors(): "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"), ("", " - "),