diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 2b8c4c69f322..e78ce2f66d7a 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -16,7 +16,7 @@ runs: environment-file: tests/conda/build-environment.yaml auto-activate-base: false miniforge-version: latest - python-version: 3.9 + python-version: "3.10" condarc-file: tests/conda/condarc - uses: conda-incubator/setup-miniconda@fc2d68f6413eb2d87b895e92f8584b5b94a10167 # v3.3.0 if: steps.conda1.outcome == 'failure' @@ -27,7 +27,7 @@ runs: auto-activate-base: false miniforge-version: latest use-only-tar-bz2: true - python-version: 3.9 + python-version: "3.10" condarc-file: tests/conda/condarc - name: Conda info shell: pwsh diff --git a/ci/jenkins/generate.py b/ci/jenkins/generate.py index 8baafa708e13..af9dfbc92f6b 100644 --- a/ci/jenkins/generate.py +++ b/ci/jenkins/generate.py @@ -22,7 +22,6 @@ import textwrap from dataclasses import dataclass from pathlib import Path -from typing import List, Optional import jinja2 from data import data @@ -41,7 +40,7 @@ class Change: @dataclass class ChangeData: - diff: Optional[str] + diff: str | None content: str destination: Path source: Path @@ -53,7 +52,7 @@ def lines_without_generated_tag(content): ] -def change_type(lines: List[str]) -> Change: +def change_type(lines: list[str]) -> Change: """ Return True if 'line' only edits an image tag or if 'line' is not a changed line in a diff diff --git a/ci/scripts/github/github_cc_reviewers.py b/ci/scripts/github/github_cc_reviewers.py index 1bee762bf153..017878740f28 100755 --- a/ci/scripts/github/github_cc_reviewers.py +++ b/ci/scripts/github/github_cc_reviewers.py @@ -23,7 +23,6 @@ import re import sys from pathlib import Path -from typing import List from urllib import error # Hackery to enable importing of utils from ci/scripts/jenkins @@ -33,7 +32,7 @@ from git_utils import GitHubRepo, git, parse_remote -def find_reviewers(body: str) -> List[str]: +def find_reviewers(body: str) -> list[str]: print(f"Parsing body:\n{body}") matches = re.findall(r"(cc( @[-A-Za-z0-9]+)+)", body, flags=re.MULTILINE) matches = [full for full, last in matches] diff --git a/ci/scripts/github/github_commenter.py b/ci/scripts/github/github_commenter.py index 5b5893b82977..b193dc3b9525 100644 --- a/ci/scripts/github/github_commenter.py +++ b/ci/scripts/github/github_commenter.py @@ -21,7 +21,7 @@ import re import sys from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple +from typing import Any # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -36,13 +36,13 @@ class BotCommentBuilder: ALLOWLIST_USERS = {"driazati", "gigiblender", "areusch"} - def __init__(self, github: GitHubRepo, data: Dict[str, Any]): + def __init__(self, github: GitHubRepo, data: dict[str, Any]): self.github = github self.pr_number = data["number"] self.comment_data = data["comments"]["nodes"] self.author = data["author"]["login"] - def find_bot_comment(self) -> Optional[Dict[str, Any]]: + def find_bot_comment(self) -> dict[str, Any] | None: """ Return the existing bot comment or None if it does not exist """ @@ -57,7 +57,7 @@ def find_bot_comment(self) -> Optional[Dict[str, Any]]: logging.info("No existing comment found") return None - def find_existing_body(self) -> Dict[str, str]: + def find_existing_body(self) -> dict[str, str]: """ Find existing dynamic bullet point items """ @@ -84,7 +84,7 @@ def find_existing_body(self) -> Dict[str, str]: logging.info(f"Found body items: {items}") return items - def _post_comment(self, body_items: Dict[str, str]): + def _post_comment(self, body_items: dict[str, str]): comment = BOT_COMMENT_START + "\n\n" + WELCOME_TEXT + "\n\n" for key, content in body_items.items(): line = self.start_key(key) + "\n * " + content.strip() + self.end_key(key) @@ -118,7 +118,7 @@ def start_key(self, key: str) -> str: def end_key(self, key: str) -> str: return f"" - def post_items(self, items: List[Tuple[str, str]]): + def post_items(self, items: list[tuple[str, str]]): """ Update or post bullet points in the PR based on 'items' which is a list of (key, text) pairs diff --git a/ci/scripts/github/github_docs_comment.py b/ci/scripts/github/github_docs_comment.py index 9422e3c3acfa..287e73653644 100755 --- a/ci/scripts/github/github_docs_comment.py +++ b/ci/scripts/github/github_docs_comment.py @@ -16,14 +16,14 @@ # specific language governing permissions and limitations # under the License. -from typing import Any, Dict +from typing import Any def build_docs_url(base_url_docs, pr_number, build_number): return f"{base_url_docs}/PR-{pr_number!s}/{build_number!s}/docs/index.html" -def find_target_url(pr_head: Dict[str, Any]): +def find_target_url(pr_head: dict[str, Any]): for status in pr_head["statusCheckRollup"]["contexts"]["nodes"]: if status.get("context", "") == "tvm-ci/pr-head": return status["targetUrl"] @@ -39,7 +39,7 @@ def get_pr_and_build_numbers(target_url): return {"pr_number": pr_number, "build_number": build_number} -def get_doc_url(pr: Dict[str, Any], base_docs_url: str = "https://pr-docs.tlcpack.ai") -> str: +def get_doc_url(pr: dict[str, Any], base_docs_url: str = "https://pr-docs.tlcpack.ai") -> str: pr_head = pr["commits"]["nodes"][0]["commit"] target_url = find_target_url(pr_head) pr_and_build = get_pr_and_build_numbers(target_url) diff --git a/ci/scripts/github/github_skipped_tests_comment.py b/ci/scripts/github/github_skipped_tests_comment.py index 74224195c550..10789f75615b 100755 --- a/ci/scripts/github/github_skipped_tests_comment.py +++ b/ci/scripts/github/github_skipped_tests_comment.py @@ -21,7 +21,7 @@ import os import subprocess from pathlib import Path -from typing import Any, Dict, Optional +from typing import Any from xml.etree import ElementTree @@ -154,7 +154,7 @@ def build_comment( return text -def find_target_url(pr_head: Dict[str, Any]): +def find_target_url(pr_head: dict[str, Any]): for status in pr_head["statusCheckRollup"]["contexts"]["nodes"]: if status.get("context", "") == "tvm-ci/pr-head": return status["targetUrl"] @@ -163,14 +163,14 @@ def find_target_url(pr_head: Dict[str, Any]): def get_skipped_tests_comment( - pr: Dict[str, Any], + pr: dict[str, Any], github, s3_prefix: str = "tvm-jenkins-artifacts-prod", jenkins_prefix: str = "ci.tlcpack.ai", pr_test_report_dir: str = "pr-reports", main_test_report_dir: str = "main-reports", - common_commit_sha: Optional[str] = None, - common_main_build: Optional[Dict[str, Any]] = None, + common_commit_sha: str | None = None, + common_main_build: dict[str, Any] | None = None, additional_tests_to_check_file: str = "required_tests_to_run.json", ) -> str: pr_head = pr["commits"]["nodes"][0]["commit"] diff --git a/ci/scripts/github/github_tag_teams.py b/ci/scripts/github/github_tag_teams.py index 81956cedd7fe..f2c2102a93b5 100755 --- a/ci/scripts/github/github_tag_teams.py +++ b/ci/scripts/github/github_tag_teams.py @@ -24,7 +24,7 @@ import re import sys from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple +from typing import Any # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -36,7 +36,7 @@ GITHUB_NAME_REGEX = r"@[a-zA-Z0-9-]+" -def parse_line(line: str) -> Tuple[str, List[str]]: +def parse_line(line: str) -> tuple[str, list[str]]: line = line.lstrip(" -") line = line.split() @@ -86,7 +86,7 @@ def fetch_issue(github: GitHubRepo, issue_number: int): return r -def parse_teams(r: Dict[str, Any], issue_number: int) -> Dict[str, str]: +def parse_teams(r: dict[str, Any], issue_number: int) -> dict[str, str]: """ Fetch an issue and parse out series of tagged people from the issue body and comments @@ -131,11 +131,11 @@ def add_tag(tag, users): return {k.lower(): v for k, v in result.items() if k.strip()} -def tags_from_labels(labels: List[Dict[str, Any]]) -> List[str]: +def tags_from_labels(labels: list[dict[str, Any]]) -> list[str]: return [label["name"] for label in labels] -def add_ccs_to_body(body: str, to_cc: List[str]) -> str: +def add_ccs_to_body(body: str, to_cc: list[str]) -> str: lines = body.split("\n") cc_line_idx = None @@ -174,8 +174,8 @@ def gen_cc_line(users): def determine_users_to_cc( - issue: Dict[str, Any], github: GitHubRepo, team_issue: str, issue_data: Optional[Dict[str, Any]] -) -> List[str]: + issue: dict[str, Any], github: GitHubRepo, team_issue: str, issue_data: dict[str, Any] | None +) -> list[str]: if issue_data is None: issue_data = fetch_issue(github, issue_number=int(team_issue)) @@ -205,7 +205,7 @@ def determine_users_to_cc( return to_cc -def get_tags(pr_data: Dict[str, Any], github: GitHubRepo, team_issue: int) -> str: +def get_tags(pr_data: dict[str, Any], github: GitHubRepo, team_issue: int) -> str: to_cc = determine_users_to_cc( issue=pr_data, github=github, team_issue=team_issue, issue_data=None ) diff --git a/ci/scripts/github/github_tvmbot.py b/ci/scripts/github/github_tvmbot.py index 0d8981b1ba3b..24308cd77cb0 100755 --- a/ci/scripts/github/github_tvmbot.py +++ b/ci/scripts/github/github_tvmbot.py @@ -25,8 +25,9 @@ import sys import traceback import warnings +from collections.abc import Callable from pathlib import Path -from typing import Any, Callable, Dict, List, Optional, Union +from typing import Any # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -35,9 +36,9 @@ from cmd_utils import init_log from git_utils import GitHubRepo, git, parse_remote, post -Review = Dict[str, Any] -CIJob = Dict[str, Any] -Comment = Dict[str, Any] +Review = dict[str, Any] +CIJob = dict[str, Any] +Comment = dict[str, Any] CommentChecker = Callable[[Comment], bool] EXPECTED_JOBS = ["tvm-ci/pr-head"] @@ -194,7 +195,7 @@ def __init__( owner: str, repo: str, dry_run: bool = False, - raw_data: Optional[Dict[str, Any]] = None, + raw_data: dict[str, Any] | None = None, ): self.owner = owner self.number = number @@ -242,7 +243,7 @@ def checker(obj, parent_key): def __repr__(self): return json.dumps(self.raw, indent=2) - def react(self, comment: Dict[str, Any], content: str): + def react(self, comment: dict[str, Any], content: str): """ React with a thumbs up to a comment """ @@ -256,7 +257,7 @@ def react(self, comment: Dict[str, Any], content: str): def head_commit(self): return self.raw["commits"]["nodes"][0]["commit"] - def co_authors(self) -> List[str]: + def co_authors(self) -> list[str]: authors = [] for commit in self.raw["authorCommits"]["nodes"]: # Co-authors always come after the main author according to the @@ -271,7 +272,7 @@ def co_authors(self) -> List[str]: def head_oid(self): return self.head_commit()["oid"] - def ci_jobs(self) -> List[CIJob]: + def ci_jobs(self) -> list[CIJob]: """ Get a list of all CI jobs (GitHub Actions and other) in a unified format """ @@ -310,14 +311,14 @@ def ci_jobs(self) -> List[CIJob]: logging.info(f"Found CI jobs for {self.head_commit()['oid']} {to_json_str(jobs)}") return jobs - def reviews(self) -> List[Review]: + def reviews(self) -> list[Review]: return self.raw["reviews"]["nodes"] - def head_commit_reviews(self) -> List[Review]: + def head_commit_reviews(self) -> list[Review]: """ Find reviews associated with the head commit """ - commits_to_review_status: Dict[str, List[Review]] = {} + commits_to_review_status: dict[str, list[Review]] = {} for review in self.reviews(): if not review["authorCanPushToRepository"]: @@ -347,13 +348,13 @@ def fetch_data(self): }, )["data"]["repository"]["pullRequest"] - def search_collaborator(self, user: str) -> List[Dict[str, Any]]: + def search_collaborator(self, user: str) -> list[dict[str, Any]]: """ Query GitHub for collaborators matching 'user' """ return self.search_users(user, COLLABORATORS_QUERY)["collaborators"]["nodes"] - def search_users(self, user: str, query: str) -> List[Dict[str, Any]]: + def search_users(self, user: str, query: str) -> list[dict[str, Any]]: return self.github.graphql( query=query, variables={ @@ -363,7 +364,7 @@ def search_users(self, user: str, query: str) -> List[Dict[str, Any]]: }, )["data"]["repository"] - def search_mentionable_users(self, user: str) -> List[Dict[str, Any]]: + def search_mentionable_users(self, user: str) -> list[dict[str, Any]]: return self.search_users(user, MENTIONABLE_QUERY)["mentionableUsers"]["nodes"] def comment(self, text: str) -> None: @@ -449,7 +450,7 @@ def merge(self) -> None: def author(self) -> str: return self.raw["author"]["login"] - def find_failed_ci_jobs(self) -> List[CIJob]: + def find_failed_ci_jobs(self) -> list[CIJob]: # NEUTRAL is GitHub Action's way of saying cancelled return [ job @@ -457,7 +458,7 @@ def find_failed_ci_jobs(self) -> List[CIJob]: if job["status"] not in {"SUCCESS", "SUCCESSFUL", "SKIPPED"} ] - def find_missing_expected_jobs(self) -> List[str]: + def find_missing_expected_jobs(self) -> list[str]: # Map of job name: has seen in completed jobs seen_expected_jobs = {name: False for name in EXPECTED_JOBS} logging.info(f"Expected to see jobs: {seen_expected_jobs}") @@ -485,7 +486,7 @@ def trigger_gha_ci(self, sha: str) -> None: ) logging.info(f"Successful workflow_dispatch: {r}") - def merge_if_passed_checks(self) -> Optional[Dict[str, Any]]: + def merge_if_passed_checks(self) -> dict[str, Any] | None: failed_ci_jobs = self.find_failed_ci_jobs() all_ci_passed = len(failed_ci_jobs) == 0 has_one_approval = False @@ -576,7 +577,7 @@ def rerun_github_actions(self) -> None: else: raise e - def comment_failure(self, msg: str, exceptions: Union[Exception, List[Exception]]): + def comment_failure(self, msg: str, exceptions: Exception | list[Exception]): if not isinstance(exceptions, list): exceptions = [exceptions] diff --git a/ci/scripts/github/ping_reviewers.py b/ci/scripts/github/ping_reviewers.py index abe2ac06779f..bd1f434c10ba 100755 --- a/ci/scripts/github/ping_reviewers.py +++ b/ci/scripts/github/ping_reviewers.py @@ -24,7 +24,6 @@ import sys import textwrap from pathlib import Path -from typing import List, Optional # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -35,7 +34,7 @@ GIT_DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" -def prs_query(user: str, repo: str, cursor: Optional[str] = None): +def prs_query(user: str, repo: str, cursor: str | None = None): after = "" if cursor is not None: after = f', before:"{cursor}"' @@ -86,7 +85,7 @@ def prs_query(user: str, repo: str, cursor: Optional[str] = None): """ -def find_reviewers(body: str) -> List[str]: +def find_reviewers(body: str) -> list[str]: matches = re.findall(r"(cc( @[-A-Za-z0-9]+)+)", body, flags=re.MULTILINE) matches = [full for full, last in matches] diff --git a/ci/scripts/github/update_branch.py b/ci/scripts/github/update_branch.py index 62552989ae74..e5195f7c67f4 100755 --- a/ci/scripts/github/update_branch.py +++ b/ci/scripts/github/update_branch.py @@ -22,7 +22,7 @@ import os import sys from pathlib import Path -from typing import Any, Dict, Optional +from typing import Any # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -58,7 +58,7 @@ """ -def commits_query(user: str, repo: str, cursor: Optional[str] = None): +def commits_query(user: str, repo: str, cursor: str | None = None): """ Create a GraphQL query to find the last N commits along with their statuses and some metadata (paginated after 'cursor') @@ -101,7 +101,7 @@ def commits_query(user: str, repo: str, cursor: Optional[str] = None): ] -def commit_passed_ci(commit: Dict[str, Any]) -> bool: +def commit_passed_ci(commit: dict[str, Any]) -> bool: """ Returns true if all of a commit's statuses are SUCCESS """ diff --git a/ci/scripts/jenkins/check_pr.py b/ci/scripts/jenkins/check_pr.py index 445c636fea9d..683c3fdd6ddb 100755 --- a/ci/scripts/jenkins/check_pr.py +++ b/ci/scripts/jenkins/check_pr.py @@ -21,8 +21,9 @@ import os import re import textwrap +from collections.abc import Callable from dataclasses import dataclass -from typing import Any, Callable, List +from typing import Any from cmd_utils import init_log, tags_from_title from git_utils import GitHubRepo, git, parse_remote @@ -82,7 +83,7 @@ def trailing_period(s: str): ] -def run_checks(checks: List[Check], s: str, name: str) -> bool: +def run_checks(checks: list[Check], s: str, name: str) -> bool: print(f"Running checks for {name}") print(textwrap.indent(s, prefix=" ")) passed = True diff --git a/ci/scripts/jenkins/cmd_utils.py b/ci/scripts/jenkins/cmd_utils.py index 4b33ce44d261..e1cd8e9b20e9 100644 --- a/ci/scripts/jenkins/cmd_utils.py +++ b/ci/scripts/jenkins/cmd_utils.py @@ -21,7 +21,6 @@ import subprocess import sys from pathlib import Path -from typing import List REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent assert (REPO_ROOT / "Jenkinsfile").exists @@ -102,7 +101,7 @@ def _default_popen_flags(self): } -def tags_from_title(title: str) -> List[str]: +def tags_from_title(title: str) -> list[str]: tags = re.findall(r"\[(.*?)\]", title) tags = [t.strip() for t in tags] return tags diff --git a/ci/scripts/jenkins/determine_docker_images.py b/ci/scripts/jenkins/determine_docker_images.py index a0d5b633e536..fed3ab79cc0e 100755 --- a/ci/scripts/jenkins/determine_docker_images.py +++ b/ci/scripts/jenkins/determine_docker_images.py @@ -23,7 +23,7 @@ import logging import urllib.error from pathlib import Path -from typing import Any, Dict +from typing import Any from cmd_utils import REPO_ROOT, init_log from http_utils import get @@ -35,7 +35,7 @@ TVM_CI_ECR = "477529581014.dkr.ecr.us-west-2.amazonaws.com" -def docker_api(url: str, use_pagination: bool = False) -> Dict[str, Any]: +def docker_api(url: str, use_pagination: bool = False) -> dict[str, Any]: """ Run a paginated fetch from the public Docker Hub API """ diff --git a/ci/scripts/jenkins/git_skip_ci_globs.py b/ci/scripts/jenkins/git_skip_ci_globs.py index dca941e7c843..651bbeac7c55 100755 --- a/ci/scripts/jenkins/git_skip_ci_globs.py +++ b/ci/scripts/jenkins/git_skip_ci_globs.py @@ -19,7 +19,6 @@ import argparse import fnmatch -from typing import Optional from git_utils import git @@ -36,7 +35,7 @@ ] -def match_any(f: str) -> Optional[str]: +def match_any(f: str) -> str | None: for glob in globs: if fnmatch.fnmatch(f, glob): return glob diff --git a/ci/scripts/jenkins/git_utils.py b/ci/scripts/jenkins/git_utils.py index 05301a046ac0..b16e3f7aa320 100644 --- a/ci/scripts/jenkins/git_utils.py +++ b/ci/scripts/jenkins/git_utils.py @@ -23,7 +23,7 @@ import os import re import subprocess -from typing import Any, Dict, List, Optional, Tuple +from typing import Any from urllib import error, request DRY_RUN = object() @@ -35,7 +35,7 @@ def compress_query(query: str) -> str: return query -def post(url: str, body: Optional[Any] = None, auth: Optional[Tuple[str, str]] = None): +def post(url: str, body: Any | None = None, auth: tuple[str, str] | None = None): logging.info(f"Requesting POST to {url} with {body}") headers = {} req = request.Request(url, headers=headers, method="POST") @@ -80,7 +80,7 @@ def headers(self): def dry_run(self) -> bool: return self.token == DRY_RUN - def graphql(self, query: str, variables: Optional[Dict[str, str]] = None) -> Dict[str, Any]: + def graphql(self, query: str, variables: dict[str, str] | None = None) -> dict[str, Any]: query = compress_query(query) if variables is None: variables = {} @@ -106,7 +106,7 @@ def testing_response(self, method: str, url: str) -> Any: logging.info(f"Unknown URL in dry run: {key}") return {} - def _request(self, full_url: str, body: Dict[str, Any], method: str) -> Dict[str, Any]: + def _request(self, full_url: str, body: dict[str, Any], method: str) -> dict[str, Any]: if self.dry_run(): logging.info(f"Dry run, would have requested a {method} to {full_url} with {body}") return self.testing_response(method, full_url) @@ -134,16 +134,16 @@ def _request(self, full_url: str, body: Dict[str, Any], method: str) -> Dict[str return response - def put(self, url: str, data: Dict[str, Any]) -> Dict[str, Any]: + def put(self, url: str, data: dict[str, Any]) -> dict[str, Any]: return self._request(self.base + url, data, method="PUT") - def patch(self, url: str, data: Dict[str, Any]) -> Dict[str, Any]: + def patch(self, url: str, data: dict[str, Any]) -> dict[str, Any]: return self._request(self.base + url, data, method="PATCH") - def post(self, url: str, data: Dict[str, Any]) -> Dict[str, Any]: + def post(self, url: str, data: dict[str, Any]) -> dict[str, Any]: return self._request(self.base + url, data, method="POST") - def get(self, url: str) -> Dict[str, Any]: + def get(self, url: str) -> dict[str, Any]: if self.dry_run(): logging.info(f"Dry run, would have requested a GET to {url}") return self.testing_response("GET", url) @@ -154,7 +154,7 @@ def get(self, url: str) -> Dict[str, Any]: response = json.loads(response.read()) return response - def delete(self, url: str) -> Dict[str, Any]: + def delete(self, url: str) -> dict[str, Any]: if self.dry_run(): logging.info(f"Dry run, would have requested a DELETE to {url}") return self.testing_response("DELETE", url) @@ -166,7 +166,7 @@ def delete(self, url: str) -> Dict[str, Any]: return response -def parse_remote(remote: str) -> Tuple[str, str]: +def parse_remote(remote: str) -> tuple[str, str]: """ Get a GitHub (user, repo) pair out of a git remote """ @@ -197,7 +197,7 @@ def git(command, **kwargs): return proc.stdout.strip() -def find_ccs(body: str) -> List[str]: +def find_ccs(body: str) -> list[str]: matches = re.findall(r"(cc( @[-A-Za-z0-9]+)+)", body, flags=re.MULTILINE) matches = [full for full, last in matches] diff --git a/ci/scripts/jenkins/http_utils.py b/ci/scripts/jenkins/http_utils.py index e006c48d477c..05e1b71f24d6 100644 --- a/ci/scripts/jenkins/http_utils.py +++ b/ci/scripts/jenkins/http_utils.py @@ -18,11 +18,11 @@ import json import logging -from typing import Any, Dict, Optional +from typing import Any from urllib import request -def get(url: str, headers: Optional[Dict[str, str]] = None) -> Dict[str, Any]: +def get(url: str, headers: dict[str, str] | None = None) -> dict[str, Any]: logging.info(f"Requesting GET to {url}") if headers is None: headers = {} diff --git a/ci/scripts/jenkins/open_docker_update_pr.py b/ci/scripts/jenkins/open_docker_update_pr.py index 6809d2c4d916..a948750082e8 100755 --- a/ci/scripts/jenkins/open_docker_update_pr.py +++ b/ci/scripts/jenkins/open_docker_update_pr.py @@ -23,7 +23,8 @@ import os import re import shlex -from typing import Any, Callable, Dict, List, Optional +from collections.abc import Callable +from typing import Any from urllib import error from cmd_utils import REPO_ROOT, Sh, init_log @@ -37,10 +38,10 @@ BRANCH = "nightly-docker-update" -def _testing_docker_api(data: Dict[str, Any]) -> Callable[[str], Dict[str, Any]]: +def _testing_docker_api(data: dict[str, Any]) -> Callable[[str], dict[str, Any]]: """Returns a function that can be used in place of docker_api""" - def mock(url: str) -> Dict[str, Any]: + def mock(url: str) -> dict[str, Any]: if url in data: return data[url] else: @@ -54,11 +55,11 @@ def parse_docker_date(d: str) -> datetime.datetime: return datetime.datetime.strptime(d, "%Y-%m-%dT%H:%M:%S.%fZ") -def check_tag(tag: Dict[str, Any]) -> bool: +def check_tag(tag: dict[str, Any]) -> bool: return re.match(r"^[0-9]+-[0-9]+-[a-z0-9]+$", tag["name"]) is not None -def latest_tag(user: str, repo: str) -> List[Dict[str, Any]]: +def latest_tag(user: str, repo: str) -> list[dict[str, Any]]: """ Queries Docker Hub and finds the most recent tag for the specified image/repo pair """ @@ -73,7 +74,7 @@ def latest_tag(user: str, repo: str) -> List[Dict[str, Any]]: return results[-1] -def latest_tlcpackstaging_image(source: str) -> Optional[str]: +def latest_tlcpackstaging_image(source: str) -> str | None: """ Finds the latest full tag to use in the Jenkinsfile or returns None if no update is needed diff --git a/ci/scripts/jenkins/pytest_wrapper.py b/ci/scripts/jenkins/pytest_wrapper.py index fc00fc8159b8..a66781029350 100755 --- a/ci/scripts/jenkins/pytest_wrapper.py +++ b/ci/scripts/jenkins/pytest_wrapper.py @@ -22,7 +22,6 @@ import textwrap import urllib.parse from pathlib import Path -from typing import List, Optional import junitparser from cmd_utils import init_log @@ -42,7 +41,7 @@ def classname_to_file(classname: str) -> str: return classname.replace(".", "/") + ".py" -def failed_test_ids() -> List[str]: +def failed_test_ids() -> list[str]: FAILURE_TYPES = (junitparser.Failure, junitparser.Error) junit_dir = REPO_ROOT / "build" / "pytest-results" failed_node_ids = [] @@ -62,7 +61,7 @@ def failed_test_ids() -> List[str]: return list(set(failed_node_ids)) -def repro_command(build_type: str, failed_node_ids: List[str]) -> Optional[str]: +def repro_command(build_type: str, failed_node_ids: list[str]) -> str | None: """ Parse available JUnit XML files and output a command that users can run to reproduce CI failures locally @@ -72,7 +71,7 @@ def repro_command(build_type: str, failed_node_ids: List[str]) -> Optional[str]: return f"python3 tests/scripts/ci.py {build_type} {test_args_str}" -def make_issue_url(failed_node_ids: List[str]) -> str: +def make_issue_url(failed_node_ids: list[str]) -> str: names = [f"`{node_id}`" for node_id in failed_node_ids] run_url = os.getenv("RUN_DISPLAY_URL", "") test_bullets = [f" - `{node_id}`" for node_id in failed_node_ids] @@ -92,7 +91,7 @@ def make_issue_url(failed_node_ids: List[str]) -> str: return "https://github.com/apache/tvm/issues/new?" + urllib.parse.urlencode(params) -def show_failure_help(failed_suites: List[str]) -> None: +def show_failure_help(failed_suites: list[str]) -> None: failed_node_ids = failed_test_ids() if len(failed_node_ids) == 0: diff --git a/ci/scripts/jenkins/s3.py b/ci/scripts/jenkins/s3.py index 414348f9e562..dd44490b1e12 100755 --- a/ci/scripts/jenkins/s3.py +++ b/ci/scripts/jenkins/s3.py @@ -21,7 +21,6 @@ import re from enum import Enum from pathlib import Path -from typing import List from cmd_utils import REPO_ROOT, Sh, init_log @@ -40,7 +39,7 @@ def show_md5(item: str) -> None: sh.run(f"md5sum {item}") -def parse_output_files(stdout: str) -> List[str]: +def parse_output_files(stdout: str) -> list[str]: """ Grab the list of downloaded files from the output of 'aws s3 cp'. Lines look like: @@ -59,7 +58,7 @@ def parse_output_files(stdout: str) -> List[str]: return files -def chmod(files: List[str]) -> None: +def chmod(files: list[str]) -> None: """ S3 has no concept of file permissions so add them back in here to every file """ @@ -70,7 +69,7 @@ def chmod(files: List[str]) -> None: SH.run(f"chmod +x {' '.join(to_chmod)}") -def s3(source: str, destination: str, recursive: bool) -> List[str]: +def s3(source: str, destination: str, recursive: bool) -> list[str]: """ Send or download the source to the destination in S3 """ diff --git a/ci/scripts/jenkins/should_rebuild_docker.py b/ci/scripts/jenkins/should_rebuild_docker.py index 238bea04ef20..0c608dc43a80 100755 --- a/ci/scripts/jenkins/should_rebuild_docker.py +++ b/ci/scripts/jenkins/should_rebuild_docker.py @@ -21,7 +21,7 @@ import json import logging import subprocess -from typing import Any, Dict, List +from typing import Any from cmd_utils import Sh, init_log from http_utils import get @@ -31,7 +31,7 @@ TEST_DATA = None -def docker_api(url: str) -> Dict[str, Any]: +def docker_api(url: str) -> dict[str, Any]: """ Run a paginated fetch from the public Docker Hub API """ @@ -81,7 +81,7 @@ def does_commit_exist(hash: str) -> bool: raise RuntimeError(f"Unexpected failure when running: {cmd}") -def find_hash_for_tag(tag: Dict[str, Any]) -> str: +def find_hash_for_tag(tag: dict[str, Any]) -> str: """ Split the hash off of a name like -