Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion release.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
import subprocess
import sys
import tempfile
import urllib.request
from collections.abc import Generator, Sequence
from contextlib import contextmanager
from dataclasses import dataclass
from functools import cache
from pathlib import Path
from typing import (
Any,
Expand Down Expand Up @@ -462,6 +464,22 @@ def tweak_patchlevel(
print("done")


@cache
def get_pep_number(version: str) -> str:
"""Fetch PEP number for a Python version from peps.python.org.

Returns the PEP number as a string, or "TODO" if not found.
"""
url = "https://peps.python.org/api/release-cycle.json"
with urllib.request.urlopen(url, timeout=10) as response:
data = json.loads(response.read().decode())
if version in data:
pep = data[version].get("pep")
if pep:
return str(pep)
return "TODO"


def tweak_readme(tag: Tag, filename: str = "README.rst") -> None:
print(f"Updating {filename}...", end=" ")
readme = Path(filename)
Expand All @@ -473,8 +491,37 @@ def tweak_readme(tag: Tag, filename: str = "README.rst") -> None:
underline = "=" * len(this_is)
lines[0] = this_is
lines[1] = underline
content = "\n".join(lines)

DOCS_URL = r"https://docs\.python\.org/"
X_Y = r"\d+\.\d+"

# Replace in: 3.14 <https://docs.python.org/3.14/whatsnew/3.14.html>`_
content = re.sub(
rf"{X_Y} (<{DOCS_URL}){X_Y}(/whatsnew/){X_Y}(\.html>`_)",
rf"{tag.basic_version} \g<1>{tag.basic_version}\g<2>{tag.basic_version}\g<3>",
content,
)

# Replace in: `Documentation for Python 3.14 <https://docs.python.org/3.14/>`_
content = re.sub(
rf"(`Documentation for Python ){X_Y}( <{DOCS_URL}){X_Y}(/>`_)",
rf"\g<1>{tag.basic_version}\g<2>{tag.basic_version}\g<3>",
content,
)

# Get PEP number for this version
pep_number = get_pep_number(tag.basic_version)
pep_padded = pep_number.zfill(4) if pep_number != "TODO" else "TODO"

# Replace in: `PEP 745 <https://peps.python.org/pep-0745/>`__ for Python 3.14
content = re.sub(
rf"(`PEP )\d+( <https://peps\.python\.org/pep-)\d+(/>`__ for Python ){X_Y}",
rf"\g<1>{pep_number}\g<2>{pep_padded}\g<3>{tag.basic_version}",
content,
)

readme.write_text("\n".join(lines))
readme.write_text(content)
print("done")


Expand Down
38 changes: 32 additions & 6 deletions tests/test_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,32 +71,57 @@ def test_tweak_patchlevel(tmp_path: Path) -> None:


@pytest.mark.parametrize(
["test_tag", "expected_version", "expected_underline"],
[
"test_tag",
"expected_version",
"expected_underline",
"expected_whatsnew",
"expected_docs",
"expected_pep_line",
],
[
(
"3.14.0a6",
"This is Python version 3.14.0 alpha 6",
"=====================================",
"3.14 <https://docs.python.org/3.14/whatsnew/3.14.html>`_",
"`Documentation for Python 3.14 <https://docs.python.org/3.14/>`_",
"`PEP 745 <https://peps.python.org/pep-0745/>`__ for Python 3.14",
),
(
"3.14.0b2",
"This is Python version 3.14.0 beta 2",
"====================================",
"3.14 <https://docs.python.org/3.14/whatsnew/3.14.html>`_",
"`Documentation for Python 3.14 <https://docs.python.org/3.14/>`_",
"`PEP 745 <https://peps.python.org/pep-0745/>`__ for Python 3.14",
),
(
"3.14.0rc2",
"This is Python version 3.14.0 release candidate 2",
"=================================================",
"3.14 <https://docs.python.org/3.14/whatsnew/3.14.html>`_",
"`Documentation for Python 3.14 <https://docs.python.org/3.14/>`_",
"`PEP 745 <https://peps.python.org/pep-0745/>`__ for Python 3.14",
),
(
"3.14.1",
"This is Python version 3.14.1",
"3.15.1",
"This is Python version 3.15.1",
"=============================",
"3.15 <https://docs.python.org/3.15/whatsnew/3.15.html>`_",
"`Documentation for Python 3.15 <https://docs.python.org/3.15/>`_",
"`PEP 790 <https://peps.python.org/pep-0790/>`__ for Python 3.15",
),
],
)
def test_tweak_readme(
tmp_path: Path, test_tag: str, expected_version: str, expected_underline: str
tmp_path: Path,
test_tag: str,
expected_version: str,
expected_underline: str,
expected_whatsnew: str,
expected_docs: str,
expected_pep_line: str,
) -> None:
# Arrange
tag = release.Tag(test_tag)
Expand All @@ -110,11 +135,12 @@ def test_tweak_readme(
release.tweak_readme(tag, filename=str(readme_file))

# Assert
original_lines = original_contents.split("\n")
new_contents = readme_file.read_text()
new_lines = new_contents.split("\n")
assert new_lines[0] == expected_version
assert new_lines[1] == expected_underline
assert new_lines[2:] == original_lines[2:]
assert expected_whatsnew in new_contents
assert expected_docs in new_contents
assert expected_pep_line in new_contents
assert original_contents.endswith("\n")
assert new_contents.endswith("\n")