pyrefly: initial support

This suppresses a lot of findings in most files so we can run pyrefly
by default and prevent new findings from showing up.  This will need
time to slowly chip away file by file.

Concretely, it's enabled for ~60% of files, and disabled for the other
~40% files.  Not the worst start.

I've opted for disabling files completely at this point rather than
using a baseline because the generated baseline is >200KiB in size.
I think we need to get through a good chunk of that before we switch.

We're going with pyrefly because it's what Google has adopted, and it
evaluated alternatives including mypy, pyright, and its own pytype.

Change-Id: Ib73752dd240a9a84ce0f56059a82292141b6af66
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/656364
Commit-Queue: Mike Frysinger <vapier@google.com>
Reviewed-by: Gavin Mak <gavinmak@google.com>
Tested-by: Mike Frysinger <vapier@google.com>
This commit is contained in:
Mike Frysinger authored and gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com committed 2026-11-12 11:33:10 -08:00
1 parent ba7bc573ad
commit c85e5ff8a5
10 files changed
+145 -24

No files matched your search

+2
View File
@@ -98,6 +98,8 @@ class BaseEventLog:
try:
env[KEY] = self._full_sid
except UnicodeEncodeError:
# This is a specific fallback for Windows for string-vs-bytes.
# pyrefly: ignore
env[KEY] = self._full_sid.encode()
if repo_source_version is not None:
+2
View File
@@ -37,6 +37,8 @@ import repo_logging
try:
# Optional third-party module.
# pyrefly: ignore
import kerberos
except ImportError:
kerberos = None
+12 -2
View File
@@ -17,6 +17,8 @@ from ctypes import wintypes
import errno
# Windows-only ctypes APIs are not in typeshed when checking on non-Windows.
# pyrefly: ignore
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
UCHAR = ctypes.c_ubyte
@@ -164,7 +166,9 @@ def _create_symlink(source, link_name, dwFlags):
# "the unprivileged create flag is unsupported below Windows 10 (1703,
# v10.0.14972). retry without it."
if not CreateSymbolicLinkW(link_name, source, dwFlags):
# pyrefly: ignore
code = ctypes.get_last_error()
# pyrefly: ignore
error_desc = ctypes.FormatError(code).strip()
if code == ERROR_PRIVILEGE_NOT_HELD:
raise OSError(errno.EPERM, error_desc, link_name)
@@ -190,7 +194,9 @@ def readlink(path):
)
if reparse_point_handle == INVALID_HANDLE_VALUE:
_raise_winerror(
ctypes.get_last_error(), f'Error opening symbolic link "{path}"'
# pyrefly: ignore
ctypes.get_last_error(),
f'Error opening symbolic link "{path}"',
)
target_buffer = ctypes.c_buffer(MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
n_bytes_returned = wintypes.DWORD()
@@ -207,7 +213,9 @@ def readlink(path):
CloseHandle(reparse_point_handle)
if not io_result:
_raise_winerror(
ctypes.get_last_error(), f'Error reading symbolic link "{path}"'
# pyrefly: ignore
ctypes.get_last_error(),
f'Error reading symbolic link "{path}"',
)
rdb = REPARSE_DATA_BUFFER.from_buffer(target_buffer)
if rdb.ReparseTag == IO_REPARSE_TAG_SYMLINK:
@@ -221,6 +229,8 @@ def readlink(path):
def _raise_winerror(code, error_desc):
# pyrefly: ignore
win_error_desc = ctypes.FormatError(code).strip()
error_desc = f"{error_desc}: {win_error_desc}"
# pyrefly: ignore
raise ctypes.WinError(code, error_desc)
+2
View File
@@ -20,6 +20,8 @@ import time
try:
import threading as _threading
except ImportError:
# This module was removed in Python 3.9, but we still support Python 3.6.
# pyrefly: ignore
import dummy_threading as _threading
import repo_trace
+60
View File
@@ -58,3 +58,63 @@ markers = """
# dirs of all tests for the last 3 runs, and each e2e test has its own checkout.
# Use `-o tmp_path_retention_policy=all` to inspect the dirs of passing tests.
tmp_path_retention_policy = "failed"
# https://pyrefly.org/en/docs/configuration/
[tool.pyrefly]
project-includes = [
# go/keep-sorted start
"**/*.py*",
"release/update-hooks",
"release/update-manpages",
"repo",
"run_tests",
# go/keep-sorted end
]
# We use relative module imports for our own modules.
enable-fallback-search-path = true
# NB: Do not add more modules here. We need to shrink this list.
project-excludes = [
"command.py",
"git_command.py",
"git_config.py",
"git_refs.py",
"git_status.py",
"git_superproject.py",
"main.py",
"manifest_xml.py",
"project.py",
"subcmds/branches.py",
"subcmds/cherry_pick.py",
"subcmds/config.py",
"subcmds/diffmanifests.py",
"subcmds/forall.py",
"subcmds/gc.py",
"subcmds/grep.py",
"subcmds/help.py",
"subcmds/info.py",
"subcmds/init.py",
"subcmds/manifest.py",
"subcmds/rebase.py",
"subcmds/selfupdate.py",
"subcmds/smartsync.py",
"subcmds/stage.py",
"subcmds/start.py",
"subcmds/status.py",
"subcmds/sync.py",
"subcmds/upload.py",
"subcmds/version.py",
"subcmds/wipe.py",
"tests/e2e/harness.py",
"tests/e2e/test_groups.py",
"tests/test_command.py",
"tests/test_git_command.py",
"tests/test_git_config.py",
"tests/test_git_superproject.py",
"tests/test_git_trace2_event_log.py",
"tests/test_manifest_xml.py",
"tests/test_project.py",
"tests/test_subcmds_info.py",
"tests/test_subcmds_sync.py",
"tests/test_subcmds_wipe.py",
"tests/test_wrapper.py",
]
Symlink
+1
View File
@@ -0,0 +1 @@
run_tests
+36 -1
View File
@@ -25,7 +25,8 @@
# 'flake8-bugbear==26.9.30',
# 'flake8-comprehensions==3.17.0',
# 'flake8-import-restrictions==2.1',
# 'isort==5.10.1'
# 'isort==5.10.1',
# 'pyrefly==1.4.0',
# ]
# ///
@@ -40,6 +41,7 @@ import sys
import black
import flake8.main.cli
import isort.main
import pyrefly.__main__
import pytest
@@ -169,6 +171,30 @@ def run_isort():
).returncode
def run_pyrefly() -> int:
"""Returns the exit code from pyrefly."""
argv = ["--version"]
log_cmd("pyrefly", argv)
subprocess.run(
[pyrefly.__main__.get_pyrefly_bin()] + argv,
check=True,
cwd=ROOT_DIR,
)
argv = [
"check",
"--verbose",
"--output-format=full-text",
"--progress-bar=simple",
]
log_cmd("pyrefly", argv)
return subprocess.run(
[pyrefly.__main__.get_pyrefly_bin()] + argv,
check=False,
cwd=ROOT_DIR,
).returncode
def run_check_metadata():
"""Returns the exit code from check-metadata."""
argv = []
@@ -215,6 +241,7 @@ def main_run_tests(argv: list[str]) -> int:
run_black,
run_flake8,
run_isort,
run_pyrefly,
run_check_metadata,
run_update_manpages,
)
@@ -223,6 +250,14 @@ def main_run_tests(argv: list[str]) -> int:
return 1 if sum(c() for c in checks) else 0
def main_pyrefly(argv: list[str]) -> int:
"""The pyrefly program."""
result = subprocess.run(
[pyrefly.__main__.get_pyrefly_bin()] + argv, check=False
)
return result.returncode
main_black = black.main
main_flake8 = flake8.main.cli.main
main_isort = isort.main.main
+26 -21
View File
@@ -1,46 +1,46 @@
attrs==25.4.0 ; python_full_version < '3.12' \
attrs==25.4.0 \
--hash=sha256:3e2be3ccc931d6c0cda7d37122b992d6d4b905968a437da7843cff016e2c41e8 \
--hash=sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373
# via flake8-bugbear
black==25.1.0 ; python_full_version < '3.12' \
black==25.1.0 \
--hash=sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717 \
--hash=sha256:c9ed033e41998dd45d6f19bf9923e2444cb401185ccb26d1a2101a9049637c1f
click==8.4.1 ; python_full_version < '3.12' \
click==8.4.1 \
--hash=sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2
# via black
colorama==0.4.6 ; python_full_version < '3.12' and sys_platform == 'win32' \
colorama==0.4.6 ; sys_platform == 'win32' \
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 \
--hash=sha256:8a5a9494346d7ae2d8f599e4661738007d2df56dbbf4ccbbf7a6a23679a3a302
# via
# click
# pytest
execnet==2.1.1 ; python_full_version < '3.12' \
execnet==2.1.1 \
--hash=sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc \
--hash=sha256:58d6d58362e52bfab78f40ebfed9575a3334c41593bee4eb5fcda518290018dc
# via pytest-xdist
flake8==7.4.1 ; python_full_version < '3.12' \
flake8==7.4.1 \
--hash=sha256:7ff3b14668bfec70da5ce3eeaf1756098330598a9a69f1ee312ed315d27c6508
# via
# flake8-bugbear
# flake8-comprehensions
flake8-bugbear==26.9.30 ; python_full_version < '3.12' \
flake8-bugbear==26.9.30 \
--hash=sha256:d0fec65b92eb79adde488515c925c33afabbf85d194bd881e845c71444960fc5
flake8-comprehensions==3.17.0 ; python_full_version < '3.12' \
flake8-comprehensions==3.17.0 \
--hash=sha256:3943a9c6f2593c3bc5cc64106c2f89d63c6ecd49c8343597f8257b8fcfc8b0a2
flake8-import-restrictions==2.1 ; python_full_version < '3.12' \
flake8-import-restrictions==2.1 \
--hash=sha256:77522e76b82a6ccb25820b1e195825a695094ceded23a18c1b5ce026c23e1071
iniconfig==2.3.0 ; python_full_version < '3.12' \
iniconfig==2.3.0 \
--hash=sha256:e6ae3625a739878eeb4baf25f17a0b4e9d985421e45b897d1332ed7478f822d9 \
--hash=sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12
# via pytest
isort==5.10.1 ; python_full_version < '3.12' \
isort==5.10.1 \
--hash=sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7 \
--hash=sha256:ec0da0d88470e89ade75bf1e2ea7b4349ec906f95c84aff08e4d41dea6864d25
mccabe==0.7.0 ; python_full_version < '3.12' \
mccabe==0.7.0 \
--hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e \
--hash=sha256:b85abd0a321cdd357d0be34adbf49cf01453a857a23e94d44612ec6f159cb261
# via flake8
mypy-extensions==1.1.0 ; python_full_version < '3.12' \
mypy-extensions==1.1.0 \
--hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505 \
--hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505 \
--hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505 \
@@ -51,33 +51,38 @@ mypy-extensions==1.1.0 ; python_full_version < '3.12' \
--hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505 \
--hash=sha256:4ec363d206d93f233330fa7f08eefe9a382dd1e326112a94244f95ec2f22f10e
# via black
packaging==26.2 ; python_full_version < '3.12' \
packaging==26.2 \
--hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e
# via
# black
# pytest
pathspec==1.0.4 ; python_full_version < '3.12' \
pathspec==1.0.4 \
--hash=sha256:eeaf9fc7cbc0a4492b666be276f38956baa67cd3faca745462db83d98f1cef87 \
--hash=sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723
# via black
platformdirs==4.9.2 ; python_full_version < '3.12' \
platformdirs==4.9.2 \
--hash=sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd \
--hash=sha256:ef245e78eb7a2ba57599bdb39c4ff323cfae3de356a47207b58bb29e7f479f46
# via black
pluggy==1.6.0 ; python_full_version < '3.12' \
pluggy==1.6.0 \
--hash=sha256:88349c39e440567519b15b27a781bcd3430de6bae17c44c37e758795be96dc5a \
--hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746
# via pytest
pycodestyle==2.15.0 ; python_full_version < '3.12' \
pycodestyle==2.15.0 \
--hash=sha256:12fd2f73c7b8ee8845a0431111df8faf4c1a07d6e64e2ee7f0c74014dab14181
# via flake8
pyflakes==4.0.3 ; python_full_version < '3.12' \
pyflakes==4.0.3 \
--hash=sha256:330ba92b8c1db2eb0b8f4068f6c58674e2649a99e334769aa50e3e9c5b11c23a
# via flake8
pytest==8.3.4 ; python_full_version < '3.12' \
pyrefly==1.4.0 \
--hash=sha256:460cec39bc8743915e9c2c8c10ba926ad0b29b099d89c1859fb97e0059f42fa7 \
--hash=sha256:5a6370d686b6cbbac8869832f09a52012888371956fbc68d446a349bc85ccd43 \
--hash=sha256:7aff37c2b711c8240ed650da0c6148237b327bf7e5dfacee65884f1adea22305 \
--hash=sha256:b6951f51687304caebfedf13dd1a943aeafdbc95abcc4e24a683b97467a77007
pytest==8.3.4 \
--hash=sha256:00cba7845d2dccfe5403025a688d60ceae228b1ddaa866d2eb86b2edb6923e73 \
--hash=sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6
# via pytest-xdist
pytest-xdist==3.8.0 ; python_full_version < '3.12' \
pytest-xdist==3.8.0 \
--hash=sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88 \
--hash=sha256:9e659fa2eacbed776070a08a075eff2d9c8e010bab4eea169640c22a1b079f2c
+2
View File
@@ -17,6 +17,8 @@
import os
# Not installed in the test virtualenv.
# pyrefly: ignore
import setuptools
+2
View File
@@ -39,6 +39,8 @@ import xmlrpc.client
try:
import threading as _threading
except ImportError:
# This module was removed in Python 3.9, but we still support Python 3.6.
# pyrefly: ignore
import dummy_threading as _threading
try: