ワンクリックで
pyrefly-type-coverage
// Migrate a file to use stricter Pyrefly type checking with annotations required for all functions, classes, and attributes.
// Migrate a file to use stricter Pyrefly type checking with annotations required for all functions, classes, and attributes.
Fix bugs reported in PyTorch GitHub issues by reproducing, root-causing, and implementing a fix in the local working tree. Use when the user asks to fix a PyTorch GitHub issue.
Write Metal/MPS kernels for PyTorch operators. Use when adding MPS device support to operators, implementing Metal shaders, or porting CUDA kernels to Apple Silicon. Covers native_functions.yaml dispatch, host-side operators, and Metal kernel implementation.
Triages GitHub issues by routing to oncall teams, applying labels, and closing questions. Use when processing new PyTorch issues or when asked to triage an issue.
Sub-triages issues in the oncall:distributed queue by assigning distributed module labels, routing to sub-oncalls, and marking triaged. Use when an issue has been routed to oncall:distributed and needs second-level triage.
Review PyTorch pull requests for code quality, test coverage, security, and backward compatibility. Use when reviewing PRs, when asked to review code changes, or when the user mentions "review PR", "code review", or "check this PR".
Debug PyTorch 2 compiler stack failures including Dynamo graph breaks, Inductor codegen errors, AOTAutograd crashes, and accuracy mismatches. Use when encountering torch.compile errors, BackendCompilerFailed exceptions, recompilation issues, Triton kernel failures, FX graph problems, or when the user mentions debugging PT2, Dynamo, Inductor, or compiled model issues.
| name | pyrefly-type-coverage |
| description | Migrate a file to use stricter Pyrefly type checking with annotations required for all functions, classes, and attributes. |
pyrefly.toml.pyrefly, lintrunner, and the project's test runner must be on PATH. If any
are missing, stop and ask whether a conda environment needs activating — don't
install or substitute (per repo CLAUDE.md).Delete any of these from the top of the file (pyrefly honors # mypy: ignore-errors
for mypy compat, so that one must go too):
# pyre-ignore-all-errors
# pyre-ignore-all-errors[16,21,53,56]
# @lint-ignore-every PYRELINT
# mypy: ignore-errors
pyrefly.toml[[sub-config]]
matches = "path/to/directory/**"
[sub-config.errors]
implicit-import = false
implicit-any = true
bad-param-name-override = false
unannotated-return = true
unannotated-parameter = true
IMPORTANT: Setting any error key in [sub-config.errors] overrides only that key
relative to the parent — but enabling unannotated-return / unannotated-parameter /
implicit-any will resurface errors that were previously hidden file-wide. If you see
unrelated errors (e.g., bad-param-name-override) flooding the output, mirror the
parent config's setting for that key in the sub-config to silence them.
pyrefly check <FILENAME>
Goal: resolve all unannotated-return, unannotated-parameter, and implicit-any
errors by adding annotations — see Step 4's ladder. These three target categories are
always resolvable; never suppress them with # pyrefly: ignore. The single
exception is @compatibility(is_backward_compatible=True) (Step 4).
Other categories (bad-argument-type, missing-attribute, …) are real type bugs.
Handle them by where pyrefly reports them:
# pyrefly: ignore[<category>] # TODO.bad-return because an imported function's annotation is wrong):
suppress locally with the same TODO comment. Don't invent a cast() that
papers over the upstream gap.Use # pyrefly: ignore[...] only as a last resort, and only on non-target categories.
Examine call sites when the right type isn't obvious from the function body.
int | None, list[str]) — assume Python >= 3.10.collections.abc over typing for ABCs (Callable, Sequence, Generator, ...).typing when available on the project's minimum
Python version, and from typing_extensions only when you need a newer feature
(e.g., Self and override if supporting < 3.11/3.12, or PEP 696 default= for
TypeVar / ParamSpec). Don't blanket-import from typing_extensions.Callable — Callable[..., Any] when the signature is
genuinely unknown, never bare Callable. (See ParamSpec below for the
signature-preserving wrapper case.)__init__ should get a class-level annotation so pyrefly can see them.if TYPE_CHECKING: — annotation-only imports go inside the
guard, and use from __future__ import annotations (or string forward refs) so
runtime imports stay lazy:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from torch.fx import GraphModule
def transform(gm: GraphModule) -> GraphModule: ...
unannotated-return,
unannotated-parameter, and implicit-any are always resolvable by adding
an annotation; # pyrefly: ignore[<one of those>] is not an acceptable
outcome. The single exception is the Backward compatibility carve-out below.X | Y), Sequence[X]-style abstract type, or a bound TypeVar
for genuinely generic functions (identity-passthrough, container helpers).object — strictest fallback that still type-checks. Forces callers to
narrow before use, e.g., def serialize(value: object) -> str:. Visually
similar to Any but stricter — pyrefly rejects value.foo() without an
isinstance.Any — last rung. Always preferred over a # pyrefly: ignore on a target
category, but only after rungs 1–3 fail. Be able to articulate why each
earlier rung doesn't fit (e.g., "union exceeds 8 types", "no observable
common bound", "callers genuinely never narrow").Any —
don't pattern-match "looks dynamic" on the first try.# pyrefly: ignore[...] (on a non-target category) is reserved
for cases where pyrefly is actually wrong about a specific local error —
dynamic metaprogramming, third-party stub gaps:
# pyrefly: ignore[attr-defined]
result = getattr(obj, dynamic_name)()
CRITICAL: Functions decorated with @compatibility(is_backward_compatible=True)
must NOT have their signatures changed. The backward-compat test
(test_function_back_compat) compares stringified inspect.signature against a golden
file — adding annotations (even -> None) changes that string and the test fails.
Use pyrefly ignore comments instead:
@compatibility(is_backward_compatible=True)
def my_function( # pyrefly: ignore[unannotated-return]
self,
arg1, # can't add type here either
):
...
The # pyrefly: ignore comment must be on the def line (where pyrefly reports the error),
not on the closing ).
ParamSpec for signature-preserving wrappers (decorators, functools.wraps-style
helpers). Use Callable[P, R] so the wrapped function's signature flows through
to the caller — Callable[..., Any] loses it. Skip ParamSpec if the wrapper
genuinely accepts arbitrary callables. Pair with Concatenate[X, P] when the
wrapper prepends or appends args.
from collections.abc import Callable
from typing import ParamSpec, TypeVar
P = ParamSpec("P")
R = TypeVar("R")
def log_calls(fn: Callable[P, R]) -> Callable[P, R]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
return fn(*args, **kwargs)
return wrapper
Re-run pyrefly check. New annotations often surface bad-return errors where the
function actually returns an incompatible type — fix those. Repeat until clean.
Required before handing off — annotations frequently shift import order and line length:
lintrunner -a <files...>
Resolve anything lintrunner can't auto-fix manually.
Precedence when something fails: tests passing > pyrefly clean > annotation
strictness. If a freshly-added annotation breaks a test, narrow it one rung in
the discipline ladder (e.g., concrete → object, or remove an Any widening
that broke a downstream isinstance check) before reverting the file.
Backward-compat check. Run iff
grep -l '@compatibility(is_backward_compatible=True)' <target> returns the
file — the decorator is the actual precondition for the golden file. The
broader "imports torch.fx" heuristic catches half of torch/.
python -m pytest test/test_fx.py::TestFXAPIBackwardCompatibility -x -v
Unit tests for the modified module. Search both ways before concluding no coverage exists:
# torch/foo/bar.py is usually covered by test/test_foo.py or test/test_bar.py
ls test/ | grep -i <module-name>
# or by import
grep -rl "from torch.foo.bar import\|import torch.foo.bar" test/
If both come up empty, tell the user — don't silently skip. Type changes can
introduce real runtime regressions (Optional[X] vs X, Sequence vs
list when .append is called, etc.).
from __future__ import annotations
still need string quoting:
class MyClass:
def __new__(cls) -> "MyClass": ...