Skip to content

Commit 555a31d

Browse files
authored
Add types with enforcement to SBOM and buildbotapi (#151)
1 parent ef58d43 commit 555a31d

File tree

4 files changed

+132
-59
lines changed

4 files changed

+132
-59
lines changed

buildbotapi.py

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
import asyncio
22
import json
33
from dataclasses import dataclass
4-
from typing import Any, Dict, List, Optional, Union
4+
from typing import Any, cast
55

66
from aiohttp.client import ClientSession
77

8+
JSON = dict[str, Any]
9+
810

911
@dataclass
1012
class Builder:
1113
builderid: int
12-
description: Optional[str]
13-
masterids: List[int]
14+
description: str | None
15+
masterids: list[int]
1416
name: str
15-
tags: List[str]
17+
tags: list[str]
1618

17-
def __init__(self, **kwargs) -> None:
19+
def __init__(self, **kwargs: Any) -> None:
1820
self.__dict__.update(**kwargs)
1921

2022
def __hash__(self) -> int:
@@ -25,15 +27,17 @@ def __hash__(self) -> int:
2527
class Build:
2628
id: int
2729
is_currently_failing: bool
30+
builderid: int
31+
builder: Builder | None
2832

29-
def __init__(self, **kwargs):
33+
def __init__(self, **kwargs: Any) -> None:
3034
self.__dict__.update(**kwargs)
31-
self.id = kwargs.get("number")
32-
self.is_currently_failing = kwargs.get("currently_failing")
35+
self.id = int(kwargs.get("number", -1))
36+
self.is_currently_failing = kwargs.get("currently_failing", False)
3337
self.builder = None
3438

35-
def __eq__(self, other):
36-
return self.id == other.id
39+
def __eq__(self, other: object) -> bool:
40+
return isinstance(other, Build) and self.id == other.id
3741

3842
def __hash__(self) -> int:
3943
return hash(self.id)
@@ -52,37 +56,30 @@ async def _fetch_text(self, url: str) -> str:
5256
async with self._session.get(url) as resp:
5357
return await resp.text()
5458

55-
async def _fetch_json(self, url: str) -> Dict[
56-
str,
57-
Union[
58-
List[Dict[str, Union[int, bool, str]]],
59-
Dict[str, int],
60-
List[Dict[str, Optional[Union[int, List[int], str, List[str]]]]],
61-
],
62-
]:
63-
return json.loads(await self._fetch_text(url))
64-
65-
async def stable_builders(self, branch: Optional[str]) -> Dict[int, Builder]:
59+
async def _fetch_json(self, url: str) -> JSON:
60+
return cast(JSON, json.loads(await self._fetch_text(url)))
61+
62+
async def stable_builders(self, branch: str | None = None) -> dict[int, Builder]:
6663
stable_builders = {
6764
id: builder
6865
for (id, builder) in (await self.all_builders(branch=branch)).items()
6966
if "stable" in builder.tags
7067
}
7168
return stable_builders
7269

73-
async def all_builders(self, branch: Optional[str] = None) -> Dict[int, Builder]:
70+
async def all_builders(self, branch: str | None = None) -> dict[int, Builder]:
7471
url = "https://buildbot.python.org/all/api/v2/builders"
7572
if branch is not None:
7673
url = f"{url}?tags__contains={branch}"
77-
_builders: Dict[str, Any] = await self._fetch_json(url)
74+
_builders: dict[str, Any] = await self._fetch_json(url)
7875
builders = _builders["builders"]
7976
all_builders = {
8077
builder["builderid"]: Builder(**builder) for builder in builders
8178
}
8279
return all_builders
8380

8481
async def is_builder_failing_currently(self, builder: Builder) -> bool:
85-
builds_: Dict[str, Any] = await self._fetch_json(
82+
builds_: dict[str, Any] = await self._fetch_json(
8683
f"https://buildbot.python.org/all/api/v2/builds?complete__eq=true"
8784
f"&&builderid__eq={builder.builderid}&&order=-complete_at"
8885
f"&&limit=1"
@@ -95,13 +92,13 @@ async def is_builder_failing_currently(self, builder: Builder) -> bool:
9592
return True
9693
return False
9794

98-
async def get_build(self, builder_id, build_id):
95+
async def get_build(self, builder_id: int, build_id: int) -> Build:
9996
data = await self._fetch_json(
10097
f"https://buildbot.python.org/all/api/v2/builders/{builder_id}"
10198
f"/builds/{build_id}"
10299
)
103100
(build_data,) = data["builds"]
104-
build = Build(**build_data)
101+
build: Build = Build(**build_data)
105102
build.builder = (await self.all_builders())[build.builderid]
106103
build.is_currently_failing = await self.is_builder_failing_currently(
107104
build.builder
@@ -126,7 +123,8 @@ async def get_recent_failures(self, limit: int = 100) -> set[Build]:
126123
for failure in all_failures:
127124
failure.builder = stable_builders[failure.builderid]
128125

129-
async def _get_missing_info(failure):
126+
async def _get_missing_info(failure: Build) -> None:
127+
assert failure.builder is not None
130128
failure.is_currently_failing = await self.is_builder_failing_currently(
131129
failure.builder
132130
)

mypy-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ pytest
44
pytest-mock
55
sigstore==1.1.2
66
types-requests
7+
types-paramiko

pyproject.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ extra_checks = true
99
warn_unreachable = true
1010

1111
exclude = [
12-
"^buildbotapi.py$",
1312
"^run_release.py$",
14-
"^sbom.py$",
1513
"^tests/test_release_tag.py$",
1614
"^tests/test_run_release.py$",
1715
"^tests/test_sbom.py$",

0 commit comments

Comments
 (0)