11import asyncio
22import json
33from dataclasses import dataclass
4- from typing import Any , Dict , List , Optional , Union
4+ from typing import Any , cast
55
66from aiohttp .client import ClientSession
77
8+ JSON = dict [str , Any ]
9+
810
911@dataclass
1012class 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:
2527class 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 )
0 commit comments