1919import tempfile
2020import time
2121from collections import namedtuple
22+ from collections .abc import Generator , Sequence
2223from contextlib import contextmanager
2324from datetime import datetime , timedelta , timezone
2425from email .mime .application import MIMEApplication
2728from enum import Enum
2829from pathlib import Path
2930from subprocess import PIPE
30- from typing import Any , Dict , Final , Generator , IO , List , Optional , Sequence , Tuple
31+ from typing import Any , Dict , Final , IO , List , Optional , Tuple
3132
3233import dateutil .parser
3334import git
@@ -160,7 +161,7 @@ def __str__(self):
160161 )
161162
162163
163- def get_ci_base (series : Series ) -> Dict :
164+ def get_ci_base (series : Series ) -> dict :
164165 """Retrieve the object (cover letter or patch) that we use as the base for
165166 sending emails in response to.
166167 """
@@ -259,7 +260,7 @@ def build_email(
259260 msg_id : str ,
260261 body : str ,
261262 boundary : str = "" ,
262- ) -> Tuple [ List [str ], str ]:
263+ ) -> tuple [ list [str ], str ]:
263264 """
264265 Builds complete email (including headers) to be sent along with curl command
265266 necessary to send it.
@@ -353,13 +354,11 @@ def execute_command(cmd: str) -> None:
353354 os .system (cmd )
354355
355356
356- def _uniq_tmp_folder (
357- url : Optional [str ], branch : Optional [str ], base_directory : str
358- ) -> str :
357+ def _uniq_tmp_folder (url : str | None , branch : str | None , base_directory : str ) -> str :
359358 # use same folder for multiple invocation to avoid cloning whole tree every time
360359 # but use different folder for different workers identified by url and branch name
361360 sha = hashlib .sha256 ()
362- sha .update (f"{ url } /{ branch } " .encode ("utf-8" ))
361+ sha .update (f"{ url } /{ branch } " .encode ())
363362 # pyre-fixme[6]: For 1st argument expected `PathLike[Variable[AnyStr <: [str,
364363 # bytes]]]` but got `Optional[str]`.
365364 repo_name = remove_unsafe_chars (os .path .basename (url ))
@@ -380,9 +379,9 @@ def temporary_patch_file(content: bytes) -> Generator[IO, None, None]:
380379 tmp_patch_file .close ()
381380
382381
383- def create_color_labels (labels_cfg : Dict [str , str ], repo : Repository ) -> None :
384- repo_labels : Dict [str , GithubLabel ] = {x .name .lower (): x for x in repo .get_labels ()}
385- labels_cfg : Dict [str , str ] = {k .lower (): v for k , v in labels_cfg .items ()}
382+ def create_color_labels (labels_cfg : dict [str , str ], repo : Repository ) -> None :
383+ repo_labels : dict [str , GithubLabel ] = {x .name .lower (): x for x in repo .get_labels ()}
384+ labels_cfg : dict [str , str ] = {k .lower (): v for k , v in labels_cfg .items ()}
386385
387386 for label , color in labels_cfg .items ():
388387 if repo_label := repo_labels .get (label ):
@@ -504,7 +503,7 @@ def slugify_context(s: str):
504503 def __init__ (
505504 self ,
506505 patchwork : Patchwork ,
507- labels_cfg : Dict [str , Any ],
506+ labels_cfg : dict [str , Any ],
508507 repo_branch : str ,
509508 repo_url : str ,
510509 upstream_url : str ,
@@ -513,10 +512,10 @@ def __init__(
513512 ci_repo_url : str ,
514513 ci_branch : str ,
515514 log_extractor : GithubLogExtractor ,
516- github_oauth_token : Optional [ str ] = None ,
517- app_auth : Optional [ Auth .AppInstallationAuth ] = None ,
518- email : Optional [ EmailConfig ] = None ,
519- http_retries : Optional [ int ] = None ,
515+ github_oauth_token : str | None = None ,
516+ app_auth : Auth .AppInstallationAuth | None = None ,
517+ email : EmailConfig | None = None ,
518+ http_retries : int | None = None ,
520519 ) -> None :
521520 super ().__init__ (
522521 repo_url = repo_url ,
@@ -548,7 +547,7 @@ def __init__(
548547 create_color_labels (labels_cfg , self .repo )
549548 # member variables
550549 self .branches = {}
551- self .prs : Dict [str , PullRequest ] = {}
550+ self .prs : dict [str , PullRequest ] = {}
552551 self .all_prs = {}
553552 self ._closed_prs = None
554553
@@ -565,7 +564,7 @@ def _add_pull_request_comment(self, pr: PullRequest, message: str) -> None:
565564 try :
566565 pr .create_issue_comment (message )
567566 except GithubException as e :
568- if not isinstance (e .data , Dict ):
567+ if not isinstance (e .data , dict ):
569568 raise e
570569 emsg = e .data .get ("message" )
571570 if emsg is not None and emsg in KNOWN_OK_COMMENT_EXCEPTIONS :
@@ -577,7 +576,7 @@ def _add_pull_request_comment(self, pr: PullRequest, message: str) -> None:
577576
578577 def _update_e2e_pr (
579578 self , title : str , base_branch : str , branch : str , has_codechange : bool
580- ) -> Optional [ PullRequest ] :
579+ ) -> PullRequest | None :
581580 """Check if there is open PR on e2e branch, reopen if necessary."""
582581 pr = None
583582
@@ -598,9 +597,7 @@ def _update_e2e_pr(
598597
599598 return pr
600599
601- def update_e2e_test_branch_and_update_pr (
602- self , branch : str
603- ) -> Optional [PullRequest ]:
600+ def update_e2e_test_branch_and_update_pr (self , branch : str ) -> PullRequest | None :
604601 base_branch = branch + "_base"
605602 branch_name = branch + "_test"
606603
@@ -724,8 +721,8 @@ def _close_pr(self, pr: PullRequest) -> None:
724721 pr .edit (state = "closed" )
725722
726723 async def _guess_pr (
727- self , series : Series , branch : Optional [ str ] = None
728- ) -> Optional [ PullRequest ] :
724+ self , series : Series , branch : str | None = None
725+ ) -> PullRequest | None :
729726 """
730727 Series could change name
731728 first series in a subject could be changed as well
@@ -757,11 +754,11 @@ async def _comment_series_pr(
757754 self ,
758755 series : Series ,
759756 branch_name : str ,
760- message : Optional [ str ] = None ,
757+ message : str | None = None ,
761758 can_create : bool = False ,
762759 close : bool = False ,
763760 has_merge_conflict : bool = False ,
764- ) -> Optional [ PullRequest ] :
761+ ) -> PullRequest | None :
765762 """
766763 Appends comment to a PR.
767764 """
@@ -897,7 +894,7 @@ def _add_ci_files(self) -> None:
897894
898895 async def try_apply_mailbox_series (
899896 self , branch_name : str , series : Series
900- ) -> Tuple [bool , Optional [ Exception ], Optional [ Any ] ]:
897+ ) -> tuple [bool , Exception | None , Any | None ]:
901898 """Try to apply a mailbox series and return (True, None, None) if successful"""
902899 # The pull request will be created against `repo_pr_base_branch`. So
903900 # prepare it for that.
@@ -919,7 +916,7 @@ async def try_apply_mailbox_series(
919916
920917 async def apply_push_comment (
921918 self , branch_name : str , series : Series
922- ) -> Optional [ PullRequest ] :
919+ ) -> PullRequest | None :
923920 comment = (
924921 f"Upstream branch: { self .upstream_sha } \n series: { series .web_url } \n "
925922 f"version: { series .version } \n "
@@ -1002,7 +999,7 @@ async def apply_push_comment(
1002999
10031000 async def checkout_and_patch (
10041001 self , branch_name : str , series_to_apply : Series
1005- ) -> Optional [ PullRequest ] :
1002+ ) -> PullRequest | None :
10061003 """
10071004 Patch in place and push.
10081005 Returns true if whole series applied.
@@ -1052,7 +1049,7 @@ def _is_relevant_pr(self, pr: PullRequest) -> bool:
10521049 return True
10531050 return False
10541051
1055- def closed_prs (self ) -> List [Any ]:
1052+ def closed_prs (self ) -> list [Any ]:
10561053 # GH api is not working: https://github.community/t/is-api-head-filter-even-working/135530
10571054 # so i have to implement local cache
10581055 # and local search
@@ -1064,7 +1061,7 @@ def closed_prs(self) -> List[Any]:
10641061 )
10651062 return self ._closed_prs
10661063
1067- def filter_closed_pr (self , head : str ) -> Optional [ PullRequest ] :
1064+ def filter_closed_pr (self , head : str ) -> PullRequest | None :
10681065 # this assumes only the most recent one closed PR per head
10691066 res = None
10701067 for pr in self .closed_prs ():
@@ -1095,7 +1092,7 @@ async def sync_checks(self, pr: PullRequest, series: Series) -> None:
10951092
10961093 logger .info (f"Fetching workflow runs for { pr } : { pr .head .ref } (@ { pr .head .sha } )" )
10971094
1098- statuses : List [Status ] = []
1095+ statuses : list [Status ] = []
10991096 jobs = []
11001097
11011098 # Note that we are interested in listing *all* runs and not just, say,
@@ -1165,7 +1162,7 @@ async def sync_checks(self, pr: PullRequest, series: Series) -> None:
11651162 await self .evaluate_ci_result (status , series , pr , jobs )
11661163
11671164 async def evaluate_ci_result (
1168- self , status : Status , series : Series , pr : PullRequest , jobs : List [WorkflowJob ]
1165+ self , status : Status , series : Series , pr : PullRequest , jobs : list [WorkflowJob ]
11691166 ) -> None :
11701167 """Evaluate the result of a CI run and send an email as necessary."""
11711168 email = self .email
0 commit comments