Skip to content

Commit b49cb95

Browse files
committed
ci: typecheck with pyrefly
pyrefly [1] is a modern type checker, suggested as a successor of pyre-check [2]. Add pyrefly configuration to pyproject.toml Add pyrefly check run in main ci workflow. Following the recommendation from the docs, annotate existing errors detected by pyrefly [3]. We'll be removing them incrementally with new code changes. [1] https://github.com/facebook/pyrefly [2] https://github.com/facebook/pyre-check [3] https://pyrefly.org/en/docs/error-suppressions/#upgrading-pyrefly-and-other-changes-that-introduce-new-type-errors Signed-off-by: Ihor Solodrai <[email protected]>
1 parent 74641ab commit b49cb95

File tree

13 files changed

+143
-4
lines changed

13 files changed

+143
-4
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ jobs:
4545
run: |
4646
python -m poetry install
4747
48+
- name: Run typecheck
49+
run: |
50+
python -m poetry run pyrefly check
51+
4852
- name: Run tests
4953
run: |
5054
python -m poetry run python -m unittest

kernel_patches_daemon/branch_worker.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,10 @@ def reply_email_recipients(
392392
"""
393393
tos = msg.get_all("To", [])
394394
ccs = msg.get_all("Cc", [])
395+
# pyrefly: ignore # implicit-import
395396
cc_list = [a for (_, a) in email.utils.getaddresses(tos + ccs)]
396397

398+
# pyrefly: ignore # implicit-import, bad-argument-type
397399
(_, sender_address) = email.utils.parseaddr(msg.get("From"))
398400
to_list = [sender_address]
399401

@@ -438,6 +440,7 @@ async def send_pr_comment_email(
438440
if not to_list and not cc_list:
439441
return
440442

443+
# pyrefly: ignore # unsupported-operation
441444
subject = "Re: " + msg.get("Subject")
442445
in_reply_to = msg.get("Message-Id")
443446

@@ -465,6 +468,7 @@ def _uniq_tmp_folder(
465468
sha.update(f"{url}/{branch}".encode("utf-8"))
466469
# pyre-fixme[6]: For 1st argument expected `PathLike[Variable[AnyStr <: [str,
467470
# bytes]]]` but got `Optional[str]`.
471+
# pyrefly: ignore # no-matching-overload
468472
repo_name = remove_unsafe_chars(os.path.basename(url))
469473
return os.path.join(base_directory, f"pw_sync_{repo_name}_{sha.hexdigest()}")
470474

@@ -510,6 +514,7 @@ def parse_pr_ref(ref: str) -> Dict[str, Any]:
510514

511515
tmp = res["series"].split("/", maxsplit=1)
512516
if len(tmp) >= 2 and tmp[1].isdigit():
517+
# pyrefly: ignore # unsupported-operation
513518
res["series_id"] = int(tmp[1])
514519

515520
return res
@@ -610,6 +615,7 @@ def _is_outdated_pr(pr: PullRequest) -> bool:
610615
# that have it as a parent will also be changed.
611616
commit = commits[commits.totalCount - 1]
612617
last_modified = dateutil.parser.parse(commit.stats.last_modified)
618+
# pyrefly: ignore # unsupported-operation
613619
age = datetime.now(timezone.utc) - last_modified
614620
logger.info(f"Pull request {pr} has age {age}")
615621
return age > PULL_REQUEST_TTL
@@ -733,16 +739,20 @@ def update_e2e_test_branch_and_update_pr(
733739
# Now that we have an updated base branch, create a dummy commit on top
734740
# so that we can actually create a pull request (this path tests
735741
# upstream directly, without any mailbox patches applied).
742+
# pyrefly: ignore # missing-attribute
736743
self.repo_local.git.checkout("-B", branch_name)
744+
# pyrefly: ignore # missing-attribute
737745
self.repo_local.git.commit("--allow-empty", "--message", "Dummy commit")
738746

739747
title = f"[test] {branch_name}"
740748

741749
# Force push only if there is no branch or code changes.
742750
pushed = False
751+
# pyrefly: ignore # missing-attribute
743752
if branch_name not in self.branches or self.repo_local.git.diff(
744753
branch_name, f"remotes/origin/{branch_name}"
745754
):
755+
# pyrefly: ignore # missing-attribute
746756
self.repo_local.git.push("--force", "origin", branch_name)
747757
pushed = True
748758

@@ -756,18 +766,25 @@ def can_do_sync(self) -> bool:
756766

757767
def do_sync(self) -> None:
758768
# fetch most recent upstream
769+
# pyrefly: ignore # missing-attribute
759770
if UPSTREAM_REMOTE_NAME in [x.name for x in self.repo_local.remotes]:
771+
# pyrefly: ignore # missing-attribute
760772
urls = list(self.repo_local.remote(UPSTREAM_REMOTE_NAME).urls)
761773
if urls != [self.upstream_url]:
762774
logger.warning(f"remote upstream set to track {urls}, re-creating")
775+
# pyrefly: ignore # missing-attribute
763776
self.repo_local.delete_remote(UPSTREAM_REMOTE_NAME)
777+
# pyrefly: ignore # missing-attribute
764778
self.repo_local.create_remote(UPSTREAM_REMOTE_NAME, self.upstream_url)
765779
else:
780+
# pyrefly: ignore # missing-attribute
766781
self.repo_local.create_remote(UPSTREAM_REMOTE_NAME, self.upstream_url)
782+
# pyrefly: ignore # missing-attribute
767783
upstream_repo = self.repo_local.remote(UPSTREAM_REMOTE_NAME)
768784
upstream_repo.fetch(self.upstream_branch)
769785
upstream_branch = getattr(upstream_repo.refs, self.upstream_branch)
770786
_reset_repo(self.repo_local, f"{UPSTREAM_REMOTE_NAME}/{self.upstream_branch}")
787+
# pyrefly: ignore # missing-attribute
771788
self.repo_local.git.push(
772789
"--force", "origin", f"{upstream_branch}:refs/heads/{self.repo_branch}"
773790
)
@@ -807,6 +824,7 @@ def fetch_repo_branch(self) -> None:
807824
"""
808825
Fetch the repository branch of interest only once
809826
"""
827+
# pyrefly: ignore # bad-assignment
810828
self.repo_local = self.fetch_repo(
811829
self.repo_dir, self.repo_url, self.repo_branch
812830
)
@@ -830,24 +848,31 @@ def _update_pr_base_branch(self, base_branch: str):
830848
self._add_ci_files()
831849

832850
try:
851+
# pyrefly: ignore # missing-attribute
833852
diff = self.repo_local.git.diff(f"remotes/origin/{base_branch}")
834853
except git.exc.GitCommandError:
835854
# The remote may not exist, in which case we want to push.
836855
diff = True
837856

838857
if diff:
858+
# pyrefly: ignore # missing-attribute
839859
self.repo_local.git.checkout("-B", base_branch)
860+
# pyrefly: ignore # missing-attribute
840861
self.repo_local.git.push("--force", "origin", f"refs/heads/{base_branch}")
841862
else:
863+
# pyrefly: ignore # missing-attribute
842864
self.repo_local.git.checkout("-B", base_branch, f"origin/{base_branch}")
843865

844866
def _create_dummy_commit(self, branch_name: str) -> None:
845867
"""
846868
Reset branch, create dummy commit
847869
"""
848870
_reset_repo(self.repo_local, f"{UPSTREAM_REMOTE_NAME}/{self.upstream_branch}")
871+
# pyrefly: ignore # missing-attribute
849872
self.repo_local.git.checkout("-B", branch_name)
873+
# pyrefly: ignore # missing-attribute
850874
self.repo_local.git.commit("--allow-empty", "--message", "Dummy commit")
875+
# pyrefly: ignore # missing-attribute
851876
self.repo_local.git.push("--force", "origin", branch_name)
852877

853878
def _close_pr(self, pr: PullRequest) -> None:
@@ -920,6 +945,7 @@ async def _comment_series_pr(
920945

921946
if not pr and can_create and not close:
922947
# If there is no merge conflict and no change, ignore the series
948+
# pyrefly: ignore # missing-attribute
923949
if not has_merge_conflict and not self.repo_local.git.diff(
924950
self.repo_pr_base_branch, branch_name
925951
):
@@ -1016,9 +1042,12 @@ def _add_ci_files(self) -> None:
10161042
"""
10171043
if Path(f"{self.ci_repo_dir}/.github").exists():
10181044
execute_command(f"cp --archive {self.ci_repo_dir}/.github {self.repo_dir}")
1045+
# pyrefly: ignore # missing-attribute
10191046
self.repo_local.git.add("--force", ".github")
10201047
execute_command(f"cp --archive {self.ci_repo_dir}/* {self.repo_dir}")
1048+
# pyrefly: ignore # missing-attribute
10211049
self.repo_local.git.add("--all", "--force")
1050+
# pyrefly: ignore # missing-attribute
10221051
self.repo_local.git.commit("--all", "--message", "adding ci files")
10231052

10241053
async def try_apply_mailbox_series(
@@ -1028,17 +1057,20 @@ async def try_apply_mailbox_series(
10281057
# The pull request will be created against `repo_pr_base_branch`. So
10291058
# prepare it for that.
10301059
self._update_pr_base_branch(self.repo_pr_base_branch)
1060+
# pyrefly: ignore # missing-attribute
10311061
self.repo_local.git.checkout("-B", branch_name)
10321062

10331063
# Apply series
10341064
patch_content = await series.get_patch_binary_content()
10351065
with temporary_patch_file(patch_content) as tmp_patch_file:
10361066
try:
1067+
# pyrefly: ignore # missing-attribute
10371068
self.repo_local.git.am("--3way", istream=tmp_patch_file)
10381069
except git.exc.GitCommandError as e:
10391070
logger.warning(
10401071
f"Failed complete 3-way merge series {series.id} patch into {branch_name} branch: {e}"
10411072
)
1073+
# pyrefly: ignore # missing-attribute
10421074
conflict = self.repo_local.git.diff()
10431075
return (False, e, conflict)
10441076
return (True, None, None)
@@ -1057,6 +1089,7 @@ async def apply_push_comment(
10571089
# In other words, patchwork could be reporting a relevant
10581090
# status (ie. !accepted) while the series has already been
10591091
# merged and pushed.
1092+
# pyrefly: ignore # bad-argument-type
10601093
if await _series_already_applied(self.repo_local, series):
10611094
logger.info(f"Series {series.url} already applied to tree")
10621095
raise NewPRWithNoChangeException(self.repo_pr_base_branch, branch_name)
@@ -1080,6 +1113,7 @@ async def apply_push_comment(
10801113
if branch_name in self.branches and (
10811114
branch_name not in self.all_prs # NO PR yet
10821115
or _is_branch_changed(
1116+
# pyrefly: ignore # bad-argument-type
10831117
self.repo_local,
10841118
f"remotes/origin/{self.repo_pr_base_branch}",
10851119
f"remotes/origin/{branch_name}",
@@ -1095,10 +1129,12 @@ async def apply_push_comment(
10951129
can_create=True,
10961130
)
10971131
assert pr
1132+
# pyrefly: ignore # missing-attribute
10981133
self.repo_local.git.push("--force", "origin", branch_name)
10991134

11001135
# Metadata inside `pr` may be stale from the force push; refresh it
11011136
pr.update()
1137+
# pyrefly: ignore # missing-attribute
11021138
wanted_sha = self.repo_local.head.commit.hexsha
11031139
for _ in range(30):
11041140
if pr.head.sha == wanted_sha:
@@ -1112,9 +1148,11 @@ async def apply_push_comment(
11121148
return pr
11131149
# we don't have a branch, also means no PR, push first then create PR
11141150
elif branch_name not in self.branches:
1151+
# pyrefly: ignore # missing-attribute
11151152
if not self.repo_local.git.diff(self.repo_pr_base_branch, branch_name):
11161153
# raise an exception so it bubbles up to the caller.
11171154
raise NewPRWithNoChangeException(self.repo_pr_base_branch, branch_name)
1155+
# pyrefly: ignore # missing-attribute
11181156
self.repo_local.git.push("--force", "origin", branch_name)
11191157
return await self._comment_series_pr(
11201158
series,
@@ -1185,9 +1223,11 @@ def closed_prs(self) -> List[Any]:
11851223
# closed prs are last resort to re-open expired PRs
11861224
# and also required for branch expiration
11871225
if not self._closed_prs:
1226+
# pyrefly: ignore # bad-assignment
11881227
self._closed_prs = list(
11891228
self.repo.get_pulls(state="closed", base=self.repo_pr_base_branch)
11901229
)
1230+
# pyrefly: ignore # bad-return
11911231
return self._closed_prs
11921232

11931233
def filter_closed_pr(self, head: str) -> Optional[PullRequest]:
@@ -1229,6 +1269,7 @@ async def sync_checks(self, pr: PullRequest, series: Series) -> None:
12291269
# completed ones. The reason being that the information that pending
12301270
# ones are present is very much relevant for status reporting.
12311271
for run in self.repo.get_workflow_runs(
1272+
# pyrefly: ignore # bad-argument-type
12321273
actor=self.user_login,
12331274
head_sha=pr.head.sha,
12341275
):
@@ -1432,6 +1473,7 @@ async def forward_pr_comments(self, pr: PullRequest, series: Series):
14321473
subject = match.group(1)
14331474
patch = series.patch_by_subject(subject)
14341475
if not patch:
1476+
# pyrefly: ignore # deprecated
14351477
logger.warn(
14361478
f"Ignoring PR comment {comment.html_url}, could not find relevant patch on patchwork"
14371479
)
@@ -1459,6 +1501,7 @@ async def forward_pr_comments(self, pr: PullRequest, series: Series):
14591501
f"Forwarded PR comment {comment.html_url} via email, Message-Id: {sent_msg_id}"
14601502
)
14611503
else:
1504+
# pyrefly: ignore # deprecated
14621505
logger.warn(
14631506
f"Failed to forward PR comment in reply to {msg_id}, no recipients"
14641507
)

kernel_patches_daemon/daemon.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def reset_github_sync(self) -> bool:
5353

5454
async def submit_metrics(self) -> None:
5555
if self.metrics_logger is None:
56+
# pyrefly: ignore # deprecated
5657
logger.warn(
5758
"Not submitting run metrics because metrics logger is not configured"
5859
)
@@ -119,7 +120,9 @@ async def start_async(self) -> None:
119120

120121
loop = asyncio.get_event_loop()
121122

123+
# pyrefly: ignore # bad-argument-type
122124
loop.add_signal_handler(signal.SIGTERM, self.stop)
125+
# pyrefly: ignore # bad-argument-type
123126
loop.add_signal_handler(signal.SIGINT, self.stop)
124127

125128
self._task = asyncio.create_task(self.worker.run())

kernel_patches_daemon/github_connector.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def __init__(
8989
self.github_account_name = gh_user.login
9090
else:
9191
self.auth_type = AuthType.APP_AUTH
92+
# pyrefly: ignore # missing-attribute
9293
app = GithubIntegration(
9394
auth=Auth.AppAuth(
9495
app_id=app_auth.app_id, private_key=app_auth.private_key
@@ -144,6 +145,7 @@ def __init__(
144145
def __get_new_auth_token(self) -> str:
145146
# refresh token if needed
146147
# pyre-fixme[16]: `github.MainClass.Github` has no attribute `__requester`.
148+
# pyrefly: ignore # missing-attribute
147149
gh_requester = self.git._Github__requester
148150
return gh_requester.auth.token
149151

kernel_patches_daemon/github_logs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ def _parse_out_test_progs_failure(self, log: str) -> str:
186186
if not line:
187187
continue
188188

189+
# pyrefly: ignore # bad-argument-type
189190
error_log.append(line)
190191

191192
return "\n".join(error_log)

kernel_patches_daemon/github_sync.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ async def sync_patches(self) -> None:
292292
if worker.can_do_sync()
293293
]
294294
if not sync_workers:
295+
# pyrefly: ignore # deprecated
295296
logger.warn("No branch workers that can_do_sync(), skipping sync_patches()")
296297
return
297298

@@ -303,11 +304,15 @@ async def sync_patches(self) -> None:
303304

304305
for branch, worker in sync_workers:
305306
logging.info(f"Refreshing repo info for {branch}.")
307+
# pyrefly: ignore # bad-argument-type
306308
await loop.run_in_executor(None, worker.fetch_repo_branch)
309+
# pyrefly: ignore # bad-argument-type
307310
await loop.run_in_executor(None, worker.get_pulls)
311+
# pyrefly: ignore # bad-argument-type
308312
await loop.run_in_executor(None, worker.do_sync)
309313
worker._closed_prs = None
310314
branches = worker.repo.get_branches()
315+
# pyrefly: ignore # bad-assignment
311316
worker.branches = [b.name for b in branches]
312317

313318
mirror_done = time.time()
@@ -329,10 +334,12 @@ async def sync_patches(self) -> None:
329334
# sync old subjects
330335
subject_names = {x.subject for x in self.subjects}
331336
for _, worker in sync_workers:
337+
# pyrefly: ignore # bad-assignment
332338
for subject_name, pr in worker.prs.items():
333339
if subject_name in subject_names:
334340
continue
335341

342+
# pyrefly: ignore # bad-argument-type
336343
if worker._is_relevant_pr(pr):
337344
parsed_ref = parse_pr_ref(pr.head.ref)
338345
# ignore unknown format branch/PRs.
@@ -373,7 +380,9 @@ async def sync_patches(self) -> None:
373380
continue
374381
await worker.sync_checks(pr, latest_series)
375382

383+
# pyrefly: ignore # bad-argument-type
376384
await loop.run_in_executor(None, worker.expire_branches)
385+
# pyrefly: ignore # bad-argument-type
377386
await loop.run_in_executor(None, worker.expire_user_prs)
378387

379388
rate_limit = worker.git.get_rate_limit()

0 commit comments

Comments
 (0)