Back to Pyrefly

Pyrefly v1.2 is here!

website/blog/2026-08-05-v1.2.md

1.3.0-dev.19.4 KB
Original Source

Pyrefly v1.2 is now available 🎉 This release adds support for Bazel and attrs, along with improvements to type checking, the language server, and the CLI.

<!--truncate-->

This release includes 901 commits from 59 contributors. To get started, run:

shell
pip install --upgrade pyrefly==1.2.0

attrs Support

Pyrefly now type-checks attrs classes with no plugin or configuration required. It recognizes the modern API (@define, @frozen, @mutable, attrs.field) and the classic API (@attr.s, @attr.ib, @attr.dataclass) in the attr. and attrs. namespaces. Pyrefly synthesizes __init__ signatures, including converter input types, and catches misconfigurations that cause errors when the class is created.

py
from attrs import define, field

def to_bpm(s: str) -> int:
    return int(s.removesuffix(" bpm"))

@define
class Chart:
    title: str
    tempo: int = field(converter=to_bpm)

Chart("Blue Bossa", "120 bpm")  # OK: converter accepts str
Chart("Blue Bossa", 120)        # Error: expected str, got int

See the attrs documentation and dedicated blog post for details.


Bazel Support

Before v1.2, teams using Pyrefly with Bazel had to write custom build logic to collect sources, dependencies, import paths, and generated files for each target. Pyrefly v1.2 provides a standard integration through the new pyrefly bazel-check command and rules_pyrefly.

rules_pyrefly uses an aspect to apply Pyrefly across existing py_library, py_binary, and py_test targets. It follows the Bazel target graph, reading the Python version from the rules_python toolchain and the platform from Bazel platform constraints. Projects do not need wrapper rules or Pyrefly declarations in each BUILD file.

Once configured, run Pyrefly for any target or target pattern:

shell
bazel build --config=pyrefly //path/to/package:target

rules_pyrefly 0.1.0 is available via the Bazel Central Registry. The integration is still at an early stage. Some import layouts are not yet supported, and the rules_pyrefly and bazel-check interfaces may change as we expand coverage. If you build Python with Bazel, please try the integration and let us know how it works for you. Bug reports and PRs are always welcome!


Type Coverage

pyrefly coverage is now stable and ready for production use. It provides two subcommands:

  • pyrefly coverage report writes a JSON report with project, module, and per-symbol coverage data, including the locations of missing annotations.
  • pyrefly coverage check reports incomplete coverage and can enforce a minimum coverage threshold in CI.

Projects including NumPy, Narwhals, sh, and scipy-stubs already use Pyrefly to track their type coverage.

Our collaborator Joren Hammudoglu (@jorenham) has led the development of the coverage feature. We will publish a dedicated post about this topic soon.


Tensor Shape Checking

Tensor shape checking remains early alpha. This release adds a NumPy stubs package that covers array construction, broadcasting, ufuncs, reductions, and parts of linalg and random. Arithmetic and broadcasting have moved from the type checker's Rust internals into the editable shape DSL. The shape primitives are now named Int, IntVar, and IntTuple. Dim has been removed.

The API will continue to change as this work develops. The tensor shapes documentation tracks the current API.


Other Type Checking Improvements

Other type-checking improvements in v1.2 include:

  • functools.partial support: bound arguments are validated at the partial(...) call, and Pyrefly synthesizes a signature for the remaining parameters. This catches errors when the partial is created and when it is called.
  • functools.singledispatch support: calls are checked against the signature of the function you decorated, and each registered implementation is checked against that function's first parameter.
  • Pattern matching: narrowing and exhaustiveness checks are more precise for class and sequence patterns.
  • Pydantic and Django support: Pydantic constructor synthesis honors populate_by_name and built-in alias_generator functions. Django ForeignKey string references such as "app_label.Model" now resolve with the correct relation and <field>_id types.
  • TypedDict methods and attributes: classes synthesize __required_keys__ and __optional_keys__, allowing them to satisfy protocols that require these attributes, including protocols used by LangGraph. Calls to .get() and .pop() with literal defaults also preserve the field type.
  • Enum .value types: .value on an enum type is inferred as the union of its member literal values, preserving the type of each value.

The Pyrefly documentation and release notes cover the full set of changes.


Language Server / IDE Improvements

Language server improvements in v1.2 cover hover information, imports, rename, and editor compatibility:

  • Baseline diagnostics: baselined errors now use hint severity, which helps distinguish new problems from known technical debt. Baselining also applies to unused-ignore diagnostics.
  • Hover information: keyword arguments resolve, callable protocols render as their __call__ signature, overload docstrings remain available at call sites, and enum fields are shown. Nested callable and Concatenate[...] signatures also wrap for readability.
  • Alias-aware auto-imports: completions preserve existing import aliases and reuse modules already in scope, avoiding duplicate imports. Deprecated typing aliases are ranked below modern equivalents.
  • More reliable rename: rename now works on aliased imports, and keyword argument renames update references across files. Protocol class names and their references can also be renamed correctly.
  • Editor compatibility: document symbols fall back to flat SymbolInformation for clients such as Helix, cross-file diagnostics refresh on save in clients such as Zed, and lspArguments defaults to ["lsp"], preventing startup failures in dev containers and remote environments.
  • Inlay hints: a server-side debounce of 150ms prevents width jitter while typing.

Other Usability Improvements

v1.2 also includes updates to the CLI, configuration, import resolution, and stub generation:

  • pyrefly infer --dry-run previews inferred annotations without touching your files and exits unsuccessfully if changes would be made, so CI can fail when a file is missing annotations Pyrefly could have inferred.
  • 16 new opt-in diagnostics, including implicit-bool, invalid-cast, unused-call-result, empty-body, missing-super-call, implicit-reexport, no-any-return, and a family of unknown-*-type checks for finding sources of Any.
  • Selective file-level suppressions: # pyrefly: ignore-errors[code] suppresses a specific diagnostic throughout a file.
  • PEP 561 partial stub packages: Pyrefly reads the partial marker from py.typed and merges the stubs with the runtime package, deferring to the runtime package for omitted modules.
  • Multiple target platforms: python-platform accepts multiple platforms or all platforms. Platform guards are folded only when every configured platform agrees.
  • Stub generation: explicit TypeAlias right-hand sides and static __all__ literals are preserved so re-exports remain in generated stubs. Implicit class variables are wrapped in ClassVar[...], and multi-line parenthesized expressions keep their parentheses, preventing an IndentationError in the generated file.

Performance

Pyrefly gets faster with every release. In our benchmarks across eight projects from Astral's ty_benchmark suite, v1.2 was about 8% faster than v1.1. We also measured 2% to 4% lower memory use on tested repositories.


Bug Fixes

Between v1.1 and v1.2, we closed 137 bug issues. The fixes cover false positives, crashes, stack overflows, narrowing, and library support. You can browse the full list on GitHub.


What's Next & How to get Involved

Our priorities for v1.3 include reducing false positives, improving performance, and expanding library support. Follow development or get involved through these resources:

Thank you to the 59 contributors who made v1.2 possible, and to everyone who filed an issue or joined a discussion. We look forward to building v1.3 together.