Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
53 changes: 51 additions & 2 deletions release.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import datetime
import glob
import hashlib
import json
import optparse
import os
import re
Expand All @@ -19,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 @@ -442,19 +445,65 @@ def tweak_patchlevel(
print("done")


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

Returns the PEP number as a string, or "TODO" if not found.
"""
url = "https://raw.githubusercontent.com/python/devguide/main/include/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)

# Update first line: "This is Python version 3.14.0 alpha 7"
# and update length of underline in second line to match.
lines = readme.read_text().splitlines()
content = readme.read_text()
lines = content.splitlines()
this_is = f"This is Python version {tag.long_name}"
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
41 changes: 34 additions & 7 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,8 +135,10 @@ def test_tweak_readme(
release.tweak_readme(tag, filename=str(readme_file))

# Assert
original_lines = original_contents.splitlines()
new_lines = readme_file.read_text().splitlines()
new_contents = readme_file.read_text()
new_lines = new_contents.splitlines()
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