Skip to content

Commit e6e6314

Browse files
authored
Add type hints to run_release.py (#137)
1 parent db96097 commit e6e6314

File tree

4 files changed

+35
-29
lines changed

4 files changed

+35
-29
lines changed

buildbotapi.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def __init__(self, **kwargs):
3535
def __eq__(self, other):
3636
return self.id == other.id
3737

38-
def __hash__(self):
38+
def __hash__(self) -> int:
3939
return hash(self.id)
4040

4141

@@ -108,7 +108,7 @@ async def get_build(self, builder_id, build_id):
108108
)
109109
return build
110110

111-
async def get_recent_failures(self, limit=100):
111+
async def get_recent_failures(self, limit: int = 100) -> set[Build]:
112112
data = await self._fetch_json(
113113
f"https://buildbot.python.org/all/api/v2/builds?"
114114
f"complete__eq=true&&results__eq=2&&"

mypy-requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
aiohttp==3.9.4
12
mypy==1.10
23
pytest
34
pytest-mock
5+
sigstore==1.1.2

run_release.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
Original code by Pablo Galindo
66
"""
7+
from __future__ import annotations
78

89
import argparse
910
import asyncio
@@ -23,7 +24,7 @@
2324
import urllib.request
2425
from dataclasses import dataclass
2526
from shelve import DbfilenameShelf
26-
from typing import Callable, Iterator, List, Optional
27+
from typing import Any, Callable, Generator, Iterator
2728

2829
import aiohttp
2930
import gnupg
@@ -33,7 +34,7 @@
3334

3435
import release as release_mod
3536
import sbom
36-
from buildbotapi import BuildBotAPI
37+
from buildbotapi import BuildBotAPI, Builder
3738

3839
API_KEY_REGEXP = re.compile(r"(?P<major>\w+):(?P<minor>\w+)")
3940

@@ -184,7 +185,7 @@ class Task:
184185
function: Callable[[DbfilenameShelf], None]
185186
description: str
186187

187-
def __call__(self, db: DbfilenameShelf) -> None:
188+
def __call__(self, db: DbfilenameShelf) -> Any:
188189
return getattr(self, "function")(db)
189190

190191

@@ -195,13 +196,13 @@ class ReleaseException(Exception):
195196
class ReleaseDriver:
196197
def __init__(
197198
self,
198-
tasks: List[Task],
199+
tasks: list[Task],
199200
*,
200201
release_tag: release_mod.Tag,
201202
git_repo: str,
202203
api_key: str,
203204
ssh_user: str,
204-
first_state: Optional[Task] = None,
205+
first_state: Task | None = None,
205206
) -> None:
206207
self.tasks = tasks
207208
dbfile = pathlib.Path.home() / ".python_release"
@@ -212,7 +213,7 @@ def __init__(
212213
self.db.close()
213214
self.db = shelve.open(str(dbfile), "n")
214215

215-
self.current_task: Optional[Task] = first_state
216+
self.current_task: Task | None = first_state
216217
self.completed_tasks = self.db.get("completed_tasks", [])
217218
self.remaining_tasks = iter(tasks[len(self.completed_tasks) :])
218219
if self.db.get("gpg_key"):
@@ -282,7 +283,7 @@ def cd(path: str) -> Iterator[None]:
282283

283284

284285
@contextlib.contextmanager
285-
def supress_print():
286+
def supress_print() -> Generator[None, None, None]:
286287
print_func = builtins.print
287288
builtins.print = lambda *args, **kwargs: None
288289
yield
@@ -333,8 +334,10 @@ def check_ssh_connection(db: DbfilenameShelf) -> None:
333334

334335

335336
def check_buildbots(db: DbfilenameShelf) -> None:
336-
async def _check():
337-
async def _get_builder_status(buildbot_api, the_builder):
337+
async def _check() -> set[Builder]:
338+
async def _get_builder_status(
339+
buildbot_api: BuildBotAPI, the_builder: Builder
340+
) -> tuple[Builder, bool]:
338341
return the_builder, await buildbot_api.is_builder_failing_currently(
339342
the_builder
340343
)
@@ -567,7 +570,7 @@ def build_sbom_artifacts(db):
567570

568571

569572
class MySFTPClient(paramiko.SFTPClient):
570-
def put_dir(self, source, target, progress=None):
573+
def put_dir(self, source: str, target: str, progress: Any = None) -> None:
571574
for item in os.listdir(source):
572575
if os.path.isfile(os.path.join(source, item)):
573576
progress.text(item)
@@ -581,7 +584,7 @@ def put_dir(self, source, target, progress=None):
581584
progress=progress,
582585
)
583586

584-
def mkdir(self, path, mode=511, ignore_existing=False):
587+
def mkdir(self, path: str, mode: int = 511, ignore_existing: bool = False) -> None:
585588
try:
586589
super().mkdir(path, mode)
587590
except OSError:
@@ -609,7 +612,7 @@ def upload_files_to_server(db: DbfilenameShelf) -> None:
609612

610613
shutil.rmtree(artifacts_path / f"Python-{db['release']}", ignore_errors=True)
611614

612-
def upload_subdir(subdir):
615+
def upload_subdir(subdir: str) -> None:
613616
with contextlib.suppress(OSError):
614617
ftp_client.mkdir(str(destination / subdir))
615618
with alive_bar(len(tuple((artifacts_path / subdir).glob("**/*")))) as progress:
@@ -636,7 +639,7 @@ def place_files_in_download_folder(db: DbfilenameShelf) -> None:
636639
source = f"/home/psf-users/{db['ssh_user']}/{db['release']}"
637640
destination = f"/srv/www.python.org/ftp/python/{db['release'].normalized()}"
638641

639-
def execute_command(command):
642+
def execute_command(command: str) -> None:
640643
channel = client.get_transport().open_session()
641644
channel.exec_command(command)
642645
if channel.recv_exit_status() != 0:
@@ -655,7 +658,7 @@ def execute_command(command):
655658
source = f"/home/psf-users/{db['ssh_user']}/{db['release']}"
656659
destination = f"/srv/www.python.org/ftp/python/doc/{release_tag}"
657660

658-
def execute_command(command):
661+
def execute_command(command: str) -> None:
659662
channel = client.get_transport().open_session()
660663
channel.exec_command(command)
661664
if channel.recv_exit_status() != 0:
@@ -690,7 +693,7 @@ def upload_docs_to_the_docs_server(db: DbfilenameShelf) -> None:
690693

691694
shutil.rmtree(artifacts_path / f"Python-{db['release']}", ignore_errors=True)
692695

693-
def upload_subdir(subdir):
696+
def upload_subdir(subdir: str) -> None:
694697
with contextlib.suppress(OSError):
695698
ftp_client.mkdir(str(destination / subdir))
696699
with alive_bar(len(tuple((artifacts_path / subdir).glob("**/*")))) as progress:
@@ -719,7 +722,7 @@ def unpack_docs_in_the_docs_server(db: DbfilenameShelf) -> None:
719722
source = f"/home/psf-users/{db['ssh_user']}/{db['release']}"
720723
destination = f"/srv/docs.python.org/release/{release_tag}"
721724

722-
def execute_command(command):
725+
def execute_command(command: str) -> None:
723726
channel = client.get_transport().open_session()
724727
channel.exec_command(command)
725728
if channel.recv_exit_status() != 0:
@@ -926,8 +929,6 @@ def modify_the_release_to_the_prerelease_pages(db: DbfilenameShelf) -> None:
926929

927930

928931
def post_release_merge(db: DbfilenameShelf) -> None:
929-
release_tag: release_mod.Tag = db["release"]
930-
931932
subprocess.check_call(
932933
["git", "fetch", "--all"],
933934
cwd=db["git_repo"],
@@ -1031,7 +1032,7 @@ def is_mirror(repo: pathlib.Path, remote: str) -> bool:
10311032

10321033

10331034
def push_to_local_fork(db: DbfilenameShelf) -> None:
1034-
def _push_to_local(dry_run=False):
1035+
def _push_to_local(dry_run: bool = False) -> None:
10351036
git_command = ["git", "push"]
10361037
if dry_run:
10371038
git_command.append("--dry-run")
@@ -1057,7 +1058,7 @@ def _push_to_local(dry_run=False):
10571058
def push_to_upstream(db: DbfilenameShelf) -> None:
10581059
release_tag: release_mod.Tag = db["release"]
10591060

1060-
def _push_to_upstream(dry_run=False):
1061+
def _push_to_upstream(dry_run: bool = False) -> None:
10611062
branch = f"{release_tag.major}.{release_tag.minor}"
10621063
git_command = ["git", "push"]
10631064
if dry_run:
@@ -1112,7 +1113,7 @@ def main() -> None:
11121113

11131114
parser = argparse.ArgumentParser(description="Process some integers.")
11141115

1115-
def _release_type(release):
1116+
def _release_type(release: str) -> str:
11161117
if not RELEASE_REGEXP.match(release):
11171118
raise argparse.ArgumentTypeError("Invalid release string")
11181119
return release
@@ -1132,7 +1133,7 @@ def _release_type(release):
11321133
type=str,
11331134
)
11341135

1135-
def _api_key(api_key):
1136+
def _api_key(api_key: str) -> str:
11361137
if not API_KEY_REGEXP.match(api_key):
11371138
raise argparse.ArgumentTypeError(
11381139
"Invalid api key format. It must be on the form USER:API_KEY"

sbom.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import tarfile
2424
import typing
2525
import zipfile
26+
from typing import Any
2627
from urllib.request import urlopen
2728

2829

@@ -118,13 +119,13 @@ def get_release_tools_commit_sha() -> str:
118119
return stdout
119120

120121

121-
def normalize_sbom_data(sbom_data):
122+
def normalize_sbom_data(sbom_data: dict[str, Any]) -> None:
122123
"""
123124
Normalize SBOM data in-place by recursion
124125
and sorting lists by some repeatable key.
125126
"""
126127

127-
def recursive_sort_in_place(value):
128+
def recursive_sort_in_place(value: list | dict) -> None:
128129
if isinstance(value, list):
129130
# We need to recurse first so bottom-most elements are sorted first.
130131
for item in value:
@@ -338,7 +339,7 @@ def create_cpython_sbom(
338339
sbom_data: dict[str, typing.Any],
339340
cpython_version: str,
340341
artifact_path: str,
341-
):
342+
) -> None:
342343
"""Creates the top-level SBOM metadata and the CPython SBOM package."""
343344

344345
cpython_version_without_suffix = re.match(r"^([0-9.]+)", cpython_version).group(1)
@@ -412,7 +413,7 @@ def create_cpython_sbom(
412413
sbom_data["packages"].append(sbom_cpython_package)
413414

414415

415-
def create_sbom_for_source_tarball(tarball_path: str):
416+
def create_sbom_for_source_tarball(tarball_path: str) -> dict[str, Any]:
416417
"""Stitches together an SBOM for a source tarball"""
417418
tarball_name = os.path.basename(tarball_path)
418419

@@ -567,7 +568,9 @@ def create_sbom_for_source_tarball(tarball_path: str):
567568
return sbom_data
568569

569570

570-
def create_sbom_for_windows_artifact(artifact_path, cpython_source_dir: str):
571+
def create_sbom_for_windows_artifact(
572+
artifact_path: str, cpython_source_dir: str
573+
) -> dict[str, Any]:
571574
artifact_name = os.path.basename(artifact_path)
572575
cpython_version = re.match(
573576
r"^python-([0-9abrc.]+)(?:-|\.exe|\.zip)", artifact_name

0 commit comments

Comments
 (0)