From 7f013bc60e80c6c5628c0c1fba1ff6115c8ebb16 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 21 Jul 2026 11:35:47 -0700 Subject: [PATCH 1/2] Release bump automatically update readme --- release.py | 24 ++++++++++++++++-------- tests/test_release.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/release.py b/release.py index b40c3ca0..0a82831d 100755 --- a/release.py +++ b/release.py @@ -450,6 +450,16 @@ def constant_replace( os.rename(filename + ".new", filename) +def get_version_suffix(tag: Tag, done: bool = False) -> str: + # 3.15+ uses "+dev" for PEP 440 local-version compliance; + # 3.14 and earlier keep the bare "+" suffix. + if done: + suffix = "+dev" if tag.as_tuple() >= (3, 15) else "+" + else: + suffix = "" + return suffix + + def tweak_patchlevel( tag: Tag, filename: str = "Include/patchlevel.h", done: bool = False ) -> None: @@ -470,12 +480,7 @@ def tweak_patchlevel( "rc": "PY_RELEASE_LEVEL_GAMMA", "f": "PY_RELEASE_LEVEL_FINAL", }[tag.level] - if done: - # 3.15+ uses "+dev" for PEP 440 local-version compliance; - # 3.14 and earlier keep the bare "+" suffix. - plus = "+dev" if tag.as_tuple() >= (3, 15) else "+" - else: - plus = "" + plus = get_version_suffix(tag, done=done) new_constants = template.format(tag=tag, level_def=level_def, plus=plus) if tag.as_tuple() >= (3, 7, 0, "a", 3): new_constants = new_constants.expandtabs() @@ -499,14 +504,16 @@ def get_pep_number(version: str) -> str: return "TODO" -def tweak_readme(tag: Tag, filename: str = "README.rst") -> None: +def tweak_readme(tag: Tag, filename: str = "README.rst", done: bool = False) -> None: print(f"Updating {filename}...", end=" ") readme = Path(filename) # Update first line: "This is Python version X.Y.Z {release_level} N" # and update length of underline in second line to match. lines = readme.read_text().split("\n") - this_is = f"This is Python version {tag.long_name}" + this_is = ( + f"This is Python version {tag.long_name}{get_version_suffix(tag, done=done)}" + ) underline = "=" * len(this_is) lines[0] = this_is lines[1] = underline @@ -858,6 +865,7 @@ def make_tag(tag: Tag, *, sign_gpg: bool = True) -> bool: def done(tag: Tag) -> None: + tweak_readme(tag, done=True) tweak_patchlevel(tag, done=True) diff --git a/tests/test_release.py b/tests/test_release.py index 2259b1b1..e7fc4d2c 100644 --- a/tests/test_release.py +++ b/tests/test_release.py @@ -204,3 +204,34 @@ def test_tweak_readme( assert expected_pep_line in new_contents assert original_contents.endswith("\n") assert new_contents.endswith("\n") + + +@pytest.mark.parametrize( + ["test_tag", "expected_version"], + [ + # 3.14 and earlier keep the bare "+" suffix. + ("3.14.2", "This is Python version 3.14.2+"), + ("3.14.0b2", "This is Python version 3.14.0 beta 2+"), + # 3.15+ uses "+dev" for PEP 440 local-version compliance. + ("3.15.1", "This is Python version 3.15.1+dev"), + ("3.15.0b1", "This is Python version 3.15.0 beta 1+dev"), + ("3.16.0a1", "This is Python version 3.16.0 alpha 1+dev"), + ], +) +def test_tweak_readme_done( + tmp_path: Path, test_tag: str, expected_version: str +) -> None: + # Arrange + tag = release.Tag(test_tag) + + original_readme_file = Path(__file__).parent / "README.rst" + readme_file = tmp_path / "README.rst" + readme_file.write_text(original_readme_file.read_text()) + + # Act + release.tweak_readme(tag, filename=str(readme_file), done=True) + + # Assert + new_lines = readme_file.read_text().split("\n") + assert new_lines[0] == expected_version + assert new_lines[1] == "=" * len(expected_version) From d5b402d2b5039553718a3344a5e498409740f925 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 21 Jul 2026 11:47:30 -0700 Subject: [PATCH 2/2] Add early return --- release.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/release.py b/release.py index 0a82831d..c3bed83a 100755 --- a/release.py +++ b/release.py @@ -519,6 +519,13 @@ def tweak_readme(tag: Tag, filename: str = "README.rst", done: bool = False) -> lines[1] = underline content = "\n".join(lines) + if done: + # Post-release only changes the version line; the substitutions below + # already ran at bump time, and skipping them avoids the PEP fetch. + readme.write_text(content) + print("done") + return + DOCS_URL = r"https://docs\.python\.org/" X_Y = r"\d+\.\d+"