release_notes/release-notes-v1.2.0.md
Release date: July 31, 2026
Pyrefly v1.2.0 bundles 901 commits from 59 contributors.
@attr.s, @define, @frozen, and their variants, handling field specifiers (attr.ib(), field()), converters, validators, defaults, and private-field aliasing. Converters are typed from their real input type rather than Any, including the @<field>.converter decorator, attrs.converters.pipe, attrs.converters.default_if_none, and generic converters like copy.deepcopy. See the new attrs documentation for details.functools.partial is now type-checked instead of treated as opaque. Bound arguments are validated at construction and Pyrefly synthesizes a precise residual signature for the remaining parameters, so errors surface at both the partial(...) call and the later invocation. Generic functions, overloads, constructors, bound methods, and **Unpack[TypedDict] parameters are supported, and results expose .func, .args, and .keywords. Precise residual callable assignment is enabled by the strict and all presets or explicitly with strict-partial-subtyping.functools.singledispatch now type-check calls using the signature of the function you decorated, and registered implementations are checked against that function's first parameter. Generic singledispatch functions infer from call arguments instead of reporting Unknown.Any, with separate diagnostics for explicit and inferred cases. Off by default, and migrated automatically from mypy's warn_return_any.__match_args__ at solve time, sequence element captures read from the narrowed subject so sibling constraints refine them, and isinstance on a facet filters the parent union to matching members. Fully covered class and sequence patterns now subtract their union member from later cases.a, *rest, b = t where t: tuple[int, *tuple[bool, ...], str] types rest as list[bool].__required_keys__ and __optional_keys__, so protocols requiring them (like those in langgraph) satisfy structural checks. .get() and .pop() with literal defaults preserve the field type.asyncio.to_thread..value on an enum type now infers as the union of member literal values instead of widening to the mixed-in data type.*args/**kwargs resolve from callable hints to tuple[...] and dict[str, ...] inside the body while preserving element types in the signature.if TYPE_CHECKING is handled consistently, typing_extensions.sentinel is supported with relaxed naming restrictions, and super(cls, cls) is accepted.copy.replace is now type-checked like dataclass replacement, and isinstance(x, type) preserves type arguments when narrowing unions.Self to a subclass now preserves Self, eliminating false return errors in methods that return the narrowed receiver.populate_by_name and built-in alias_generator functions, ignores Field(init=False) to match runtime, and treats frozen as a readonly field reason.ForeignKey targets now resolve attribute expressions and string references such as "app_label.Model", preserving the generated relation and <field>_id types.FactoryMetaClass.partial marker from py.typed and merges the stubs with the runtime package, deferring to the runtime package for omitted modules while preserving .pyi-before-.py precedence for provided ones.typeshed-path now supplies stdlib stubs as well as third-party stubs, enabling complete custom-typeshed testing and overrides.__call__ signature, preserves overload docstrings at call sites, shows enum fields, wraps nested callable and Concatenate[...] signatures for readability, and covers and/or operators, augmented assignments, and union methods.python.analysis.autoImportCompletions, rank deprecated stdlib typing aliases below their modern equivalents, avoid duplicates for already-imported modules, and preserve import aliases correctly.__init__..thrift, including nested attribute and enum access and intermediate components of multi-dotted imports.NewType values now use their callable constructor signature instead of producing an invalid type[N] annotation.SymbolInformation for clients such as Helix, semantic tokens cover with ... as and except ... as bindings, and cross-file diagnostics refresh on save in strict-spec clients such as Zed.#region/#endregion markers create folding regions, and selection ranges now follow AST nesting from expression to statement to scope to document.lspArguments defaults to ["lsp"] when empty, preventing startup failures in dev containers and remote environments.implicit-bool, invalid-cast, invalid-abstract-method, unused-call-result, empty-body, missing-super-call, unsupported-dynamic-base, implicit-reexport, unknown-argument-type, unknown-attribute-type, unknown-variable-type, implicit-any-lambda, untyped-function-decorator, untyped-class-decorator, unused-type-ignore, and no-any-return.--output-format=min-text flattens multi-line headers so each error stays on one line.--output-format=code-climate produces GitLab-compatible Code Quality reports, while full-text-with-github combines readable diagnostics with GitHub workflow commands and is now used by the Pyrefly action.pyrefly coverage is no longer marked experimental.[coverage] config table with includes and excludes can target a file set different from the project globs, with --project-excludes and positional FILES... taking precedence over it.--public-only keeps public re-exports from excluded files, so a symbol is only excluded when all of its public re-export locations are. Privately named classes and their members are excluded unless exported via __all__.--fail-under always prints findings whether or not the threshold is met.pyrefly infer --dry-run previews inferred annotations without modifying files and exits unsuccessfully when changes would be made, making it suitable for CI.python-platform accepts one platform, multiple platforms, or all platforms. Platform guards are folded only when every configured platform agrees.# pyrefly: ignore-errors[code] directives selectively suppress named error codes using the same parent-kind matching as line-level ignores.suppress command's --remove-unused=type mode also removes unused # type: ignore comments.--update-baseline validates the baseline after config resolution, so a baseline configured in pyproject.toml works without repeating --baseline.[tool.mypy] section instead of silently falling back to pyright, and TOML parse errors point at the offending value rather than the start of the file.TypeAlias right-hand sides and static __all__ literals are now preserved, so re-exports survive in the stub.ClassVar[...], and multi-line parenthesized expressions keep their parentheses, preventing IndentationError in generated stubs.def with AsyncGenerator return annotations, following the typeshed convention.Callable[..., Incomplete] instead of bare Incomplete, and statements guarded by conditions other than TYPE_CHECKING are no longer dropped.bazel-check command adds Bazel-focused type-checking for projects that provide source information through JSON manifests. It is intended to collaborate with an in-progress rules_pyrefly Bazel rule implementation.pkgutil namespace probes are cached during import resolution.These may surface new errors or warnings in code that checked cleanly under v1.1.0.
isinstance narrowing now consumes dynamic uncertainty before intersecting with the target type, so x: Any narrowed by isinstance(x, C) refines to C instead of preserving the Any. This closes a type-safety hole while sacrificing the gradual guarantee in exchange for more precise runtime-evidence-based narrowing.# pyrefly: ignore-errors directive placed after code now emits a misplaced-ignore warning, directing users to move it into the file preamble or use a line-level suppression.direct-abstract-base-instantiation is now separated from bad-instantiation and is a warning by default.invalid-type-checking-constant is a new default error for user-defined TYPE_CHECKING constants that are not typed as bool.useless-overload-body is a new default warning for executable logic in @overload declarations, whose bodies are never executed at runtime.implicit-any-attribute now focuses on Any synthesized at an attribute assignment; propagated Any is reported separately as the off-by-default unknown-attribute-type, so per-code configurations may need updating.KW_ONLY markers, and invalid __init_subclass__ calls.TypeVars not assigned to their declared name, raw-string quoted types, defaults on self or cls, and super() in directly defined NamedTuple methods.We closed 137 bug issues this release 👏
isinstance() narrowing broke after an unrelated isinstance() check in a returning sibling branch, restoring correct narrowing behavior.TypeVar bounded by a heterogeneous tuple now preserves each positional element type instead of widening every element to their union.kw_only=True handling for SQLAlchemy-style declarative bases, preventing false "field without default may not follow field with default" errors in subclasses.enumerate() over tuple literals now preserves element types, so for i, x in enumerate(("a", "b")) types x as Literal["a"] | Literal["b"].bad-override error when a child class generic over a TypeVarTuple overrides a parent method with the same *args: *Ts signature.unannotated-return for @no_type_check functions.BaseModel fields named "self" are no longer incorrectly flagged on construction.Thank-you to all our contributors who found these bugs and reported them! Did you know this is one of the most helpful contributions you can make to an open-source project? If you find any bugs in Pyrefly we want to know about them! Please open a bug report issue here.
pip install --upgrade pyrefly==1.2.0
Upgrading the version of Pyrefly you're using or a third-party library you depend on can reveal new type errors in your code. Fixing them all at once is often unrealistic. We've written scripts to help you temporarily silence them. After upgrading, follow these steps:
pyrefly check --suppress-errorspyrefly check --remove-unused-ignoresThis will add # pyrefly: ignore comments to your code, enabling you to silence errors and return to fix them later. This can make the process of upgrading a large codebase much more manageable.
Read more about error suppressions in the Pyrefly documentation.
@stroxler, @shobhitmehro, @yangdanny97, @asukaminato0721, @rchen152, @kinto0, @samwgoldman, @grievejia, @jorenham, @NathanTempest, @anushamukka-dev, @ericzhonghou, @connernilsen, @tobyh-canva, @aodihis, @nitishagar, @kz357, @WilliamK112, @mikeleppane, @markselby9, @goutamadwant, @brosenfeld, @alexander-beedie, @ak4-sh, @xaskii, @qnox, @QEDady, @oprypin, @MannXo, @javabster, @fangyi-zhou, @durvesh1992, @arthaud, @vivekjm, @VasuAgrawal, @teerthsharma, @SarahMKosowsky, @roian6, @Punisheroot, @paranoa233, @olekuhlmann, @ndmitchell, @magic-akari, @maggiemoss, @lesbass, @lennardwalter, @knQzx, @Kartikey077, @JakobDegen, @ibraheemshaikh5, @hrolfurgylfa, @fhoehle, @dillydill123, @DibbayajyotiRoy, @coclique, @arogozhnikov, David Tolnay, Myles Matz, pratved64
Please note: These release notes summarize major updates and features. For brevity, not all individual commits are listed.