Unpack a tuple subclass with an unbounded part like a plain tuple Summary: Unpacking a `tuple` subclass whose tuple has an unbounded part, such as SQLAlchemy's `Row`, gave every target the union of all the element types. `iterate` only treated a subclass as a tuple when its tuple was fixed-length. Any other subclass fell through to the iterable protocol, which knows only the element type of `__iter__`, so `a, b, c = t` with `t: Variadic[str, int | None, *tuple[Any, ...]]` made `a` and `b` `int | str | Any | None`. Now a subclass whose tuple has fixed elements before or after the unbounded part is iterated as that plain tuple, which already keeps each fixed position's type. So `a` is `str`, `b` is `int | None`, `c` is `Any`, and a starred `*rest` is `list[Any]`, matching how a plain tuple with the same types unpacks. Fixed-length subclasses keep their existing path. Subclasses whose tuple has no fixed elements also keep the iterable protocol: routing them through the plain-tuple path added a false `bad-unpacking` error on a subclass of a generic tuple subclass (`class Nested[*Ts](Variadic[*Ts])`), which unpacks fine at runtime. That case still loses position types and is a separate gap. Fixes https://github.com/facebook/pyrefly/issues/5286 Reviewed By: samwgoldman Differential Revision: D127237256 fbshipit-source-id: 9faba386fe7a15ebe324261ef3af37132db3d060
Pyrefly is a type checker and language server for Python, which provides lightning-fast type checking along with IDE features such as code navigation, semantic highlighting, and code completion. It is available as a command-line tool and an extension for popular IDEs and editors such as VSCode, Neovim, Zed, and more.
See the Pyrefly website for full documentation and how to add Pyrefly to your editor of choice.
Pyrefly's current development status is stable.
pyrefly init, silence existing errors with pyrefly suppress, and generate type annotations with pyrefly infer. Start with one file and expand at your own pace.pip install pyreflyPyrefly releases new minor versions (1.x.0) monthly and patch versions in between as-needed for critical fixes. Pyrefly does not follow strict semantic versioning: minor versions contain more significant changes than patch versions, but any version may introduce new type errors and other breaking changes. The pyrefly suppress command can be used to easily silence errors when upgrading to a new version.
If you have questions or would like to report a bug, please create an issue.
See our contributing guide and architecture overview for information on how to contribute to Pyrefly.
Join our Discord to chat about Pyrefly and types. This is also where we hold biweekly office hours.