Skip to content

[ty] Homogeneous and mixed tuples #18600

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 65 commits into from
Jun 20, 2025
Merged

[ty] Homogeneous and mixed tuples #18600

merged 65 commits into from
Jun 20, 2025

Conversation

dcreager
Copy link
Member

@dcreager dcreager commented Jun 9, 2025

We already had support for homogeneous tuples (tuple[int, ...]). This PR extends this to also support mixed tuples (tuple[str, str, *tuple[int, ...], str str]).

A mixed tuple consists of a fixed-length (possibly empty) prefix and suffix, and a variable-length portion in the middle. Every element of the variable-length portion must be of the same type. A homogeneous tuple is then just a mixed tuple with an empty prefix and suffix.

The new data representation uses different Rust types for a fixed-length (aka heterogeneous) tuple. Another option would have been to use the VariableLengthTuple representation for all tuples, and to wrap the "variable + suffix" portion in an Option. I don't think that would simplify the method implementations much, though, since we would still have a 2×2 case analysis for most of them.

One wrinkle is that the definition of the tuple class in the typeshed has a single typevar, and canonically represents a homogeneous tuple. When getting the class of a tuple instance, that means that we have to summarize our detailed mixed tuple type information into its "homogeneous supertype". (We were already doing this for heterogeneous types.)

A similar thing happens when concatenating two mixed tuples: the variable-length portion and suffix of the LHS, and the prefix and variable-length portion of the RHS, all get unioned into the variable-length portion of the result. The LHS prefix and RHS suffix carry through unchanged.

Copy link
Contributor

github-actions bot commented Jun 9, 2025

mypy_primer results

Changes were detected when running on open source projects
parso (https://github.com/davidhalter/parso)
- error[invalid-argument-type] parso/python/diff.py:884:35: Argument to bound method `__init__` is incorrect: Expected `tuple[int, int]`, found `tuple[Unknown, ...]`
- Found 80 diagnostics
+ Found 79 diagnostics

anyio (https://github.com/agronholm/anyio)
- error[call-non-callable] src/anyio/_backends/_asyncio.py:2223:49: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/anyio/_backends/_asyncio.py:2223:49: Object of type `GenericAlias` is not callable
- Found 103 diagnostics
+ Found 101 diagnostics

beartype (https://github.com/beartype/beartype)
+ error[invalid-type-form] beartype/_data/hint/datahintpep.py:250:20: Variable of type `_SpecialForm` is not allowed in a type expression
- Found 580 diagnostics
+ Found 581 diagnostics

more-itertools (https://github.com/more-itertools/more-itertools)
- error[unsupported-operator] more_itertools/more.pyi:164:18: Operator `|` is unsupported between objects of type `<class 'type'>` and `<class 'tuple[@Todo(Generic tuple specializations), ...]'>`
+ error[unsupported-operator] more_itertools/more.pyi:164:18: Operator `|` is unsupported between objects of type `<class 'type'>` and `<class 'tuple[@Todo(Support for `typing.TypeAlias`), ...]'>`

Expression (https://github.com/cognitedata/Expression)
- error[invalid-argument-type] expression/extra/option/pipeline.py:91:19: Argument to function `reduce` is incorrect: Expected `(def Some(value: _T1) -> Option[_T1], (Any, /) -> Option[Any], /) -> def Some(value: _T1) -> Option[_T1]`, found `def reducer(acc: (Any, /) -> Option[Any], fn: (Any, /) -> Option[Any]) -> (Any, /) -> Option[Any]`
+ error[invalid-argument-type] expression/extra/option/pipeline.py:91:19: Argument to function `reduce` is incorrect: Expected `(def Some(value: _T1) -> Option[_T1], Unknown, /) -> def Some(value: _T1) -> Option[_T1]`, found `def reducer(acc: (Any, /) -> Option[Any], fn: (Any, /) -> Option[Any]) -> (Any, /) -> Option[Any]`
- error[invalid-argument-type] expression/extra/result/pipeline.py:96:19: Argument to function `reduce` is incorrect: Expected `(def Ok(value: _TSource) -> Result[_TSource, Any], (Any, /) -> Result[Any, Any], /) -> def Ok(value: _TSource) -> Result[_TSource, Any]`, found `def reducer(acc: (Any, /) -> Result[Any, Any], fn: (Any, /) -> Result[Any, Any]) -> (Any, /) -> Result[Any, Any]`
+ error[invalid-argument-type] expression/extra/result/pipeline.py:96:19: Argument to function `reduce` is incorrect: Expected `(def Ok(value: _TSource) -> Result[_TSource, Any], Unknown, /) -> def Ok(value: _TSource) -> Result[_TSource, Any]`, found `def reducer(acc: (Any, /) -> Result[Any, Any], fn: (Any, /) -> Result[Any, Any]) -> (Any, /) -> Result[Any, Any]`

websockets (https://github.com/aaugustin/websockets)
- warning[redundant-cast] src/websockets/legacy/auth.py:163:37: Value is already of type `Iterable[Unknown | tuple[@Todo(Generic tuple specializations), ...]]`
+ warning[redundant-cast] src/websockets/legacy/auth.py:163:37: Value is already of type `Iterable[Unknown | tuple[str, str]]`

black (https://github.com/psf/black)
+ error[unsupported-operator] src/black/parsing.py:80:37: Operator `-` is unsupported between objects of type `Unknown | str | int` and `Literal[1]`
+ error[invalid-argument-type] src/blib2to3/pgen2/parse.py:34:17: Argument to bound method `__init__` is incorrect: Expected `int`, found `Unknown | int | str | None | tuple[str, tuple[int, int]] | list[@Todo(Inference of subscript on special form)]`
+ error[invalid-argument-type] src/blib2to3/pgen2/parse.py:34:31: Argument to bound method `__init__` is incorrect: Expected `list[@Todo(Inference of subscript on special form)]`, found `(Unknown & ~None) | int | str | tuple[str, tuple[int, int]] | list[@Todo(Inference of subscript on special form)]`
- Found 68 diagnostics
+ Found 71 diagnostics

starlette (https://github.com/encode/starlette)
+ warning[possibly-unbound-attribute] starlette/middleware/base.py:134:27: Attribute `send` on type `Unknown | MemoryObjectSendStream[Unknown] | MemoryObjectReceiveStream[Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] starlette/middleware/base.py:151:33: Attribute `receive` on type `Unknown | MemoryObjectSendStream[Unknown] | MemoryObjectReceiveStream[Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] starlette/middleware/base.py:154:37: Attribute `receive` on type `Unknown | MemoryObjectSendStream[Unknown] | MemoryObjectReceiveStream[Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] starlette/testclient.py:138:40: Attribute `receive` on type `MemoryObjectSendStream[Unknown] | MemoryObjectReceiveStream[Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] starlette/testclient.py:138:60: Attribute `send` on type `MemoryObjectSendStream[Unknown] | MemoryObjectReceiveStream[Unknown]` is possibly unbound
+ error[invalid-assignment] tests/test_websockets.py:213:5: Object of type `MemoryObjectSendStream[Unknown] | MemoryObjectReceiveStream[Unknown]` is not assignable to `ObjectSendStream[MutableMapping[str, Any]]`
+ error[invalid-assignment] tests/test_websockets.py:213:18: Object of type `MemoryObjectSendStream[Unknown] | MemoryObjectReceiveStream[Unknown]` is not assignable to `ObjectReceiveStream[MutableMapping[str, Any]]`
- Found 166 diagnostics
+ Found 173 diagnostics

kornia (https://github.com/kornia/kornia)
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/gaussian_illumination.py:162:63: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/gaussian_illumination.py:162:69: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/gaussian_illumination.py:162:77: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/gaussian_illumination.py:162:84: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/linear_illumination.py:120:61: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/linear_illumination.py:120:67: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/linear_illumination.py:227:67: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/linear_illumination.py:227:73: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/salt_pepper_noise.py:127:56: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[invalid-argument-type] kornia/augmentation/_2d/intensity/salt_pepper_noise.py:127:64: Argument to bound method `__init__` is incorrect: Expected `tuple[int | float, int | float]`, found `(int & tuple[Unknown, ...] & ~float) | (tuple[int | float, int | float] & tuple[Unknown, ...] & ~float) | tuple[float, float] | tuple[@Todo(map_with_boundness: intersections with negative contributions), @Todo(map_with_boundness: intersections with negative contributions)]`
- error[unsupported-operator] kornia/augmentation/utils/param_validation.py:139:16: Operator `<` is not supported for types `tuple[Any, ...]` and `int`, in comparing `Unknown | int | float | tuple[Any, ...]` with `Literal[0]`
+ error[unsupported-operator] kornia/augmentation/utils/param_validation.py:139:16: Operator `<` is not supported for types `tuple[Any, ...]` and `Literal[0]`, in comparing `Unknown | int | float | tuple[Any, ...]` with `Literal[0]`
- error[invalid-return-type] kornia/feature/dedode/transformer/dinov2.py:309:20: Return type does not match returned value: expected `tuple[Unknown | tuple[Unknown]]`, found `tuple[Unknown, ...]`
- error[invalid-return-type] kornia/feature/dedode/transformer/dinov2.py:310:16: Return type does not match returned value: expected `tuple[Unknown | tuple[Unknown]]`, found `tuple[Unknown, ...]`
- error[call-non-callable] kornia/filters/kernels_geometry.py:172:17: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> Unknown, (key: slice[Any, Any, Any], /) -> tuple[Unknown, ...]])` is not callable on object of type `Unknown | tuple[int | float, int | float, int | float]`
+ error[call-non-callable] kornia/filters/kernels_geometry.py:172:17: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> int | float, (key: slice[Any, Any, Any], /) -> tuple[int | float, ...]])` is not callable on object of type `Unknown | tuple[int | float, int | float, int | float]`
- error[call-non-callable] kornia/filters/kernels_geometry.py:203:31: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> Unknown, (key: slice[Any, Any, Any], /) -> tuple[Unknown, ...]])` is not callable on object of type `Unknown | tuple[int | float, int | float, int | float]`
+ error[call-non-callable] kornia/filters/kernels_geometry.py:203:31: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> int | float, (key: slice[Any, Any, Any], /) -> tuple[int | float, ...]])` is not callable on object of type `Unknown | tuple[int | float, int | float, int | float]`
- error[call-non-callable] kornia/filters/kernels_geometry.py:203:44: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> Unknown, (key: slice[Any, Any, Any], /) -> tuple[Unknown, ...]])` is not callable on object of type `Unknown | tuple[int | float, int | float, int | float]`
+ error[call-non-callable] kornia/filters/kernels_geometry.py:203:44: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> int | float, (key: slice[Any, Any, Any], /) -> tuple[int | float, ...]])` is not callable on object of type `Unknown | tuple[int | float, int | float, int | float]`
- error[call-non-callable] kornia/filters/kernels_geometry.py:203:57: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> Unknown, (key: slice[Any, Any, Any], /) -> tuple[Unknown, ...]])` is not callable on object of type `Unknown | tuple[int | float, int | float, int | float]`
+ error[call-non-callable] kornia/filters/kernels_geometry.py:203:57: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> int | float, (key: slice[Any, Any, Any], /) -> tuple[int | float, ...]])` is not callable on object of type `Unknown | tuple[int | float, int | float, int | float]`
- error[call-non-callable] kornia/geometry/boxes.py:349:21: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> Unknown, (key: slice[Any, Any, Any], /) -> tuple[Unknown, ...]])` is not callable on object of type `Unknown | tuple[int, int] | None`
+ error[call-non-callable] kornia/geometry/boxes.py:349:21: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> int, (key: slice[Any, Any, Any], /) -> tuple[int, ...]])` is not callable on object of type `Unknown | tuple[int, int] | None`
- error[call-non-callable] kornia/geometry/boxes.py:352:21: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> Unknown, (key: slice[Any, Any, Any], /) -> tuple[Unknown, ...]])` is not callable on object of type `Unknown | tuple[int, int] | None`
+ error[call-non-callable] kornia/geometry/boxes.py:352:21: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> int, (key: slice[Any, Any, Any], /) -> tuple[int, ...]])` is not callable on object of type `Unknown | tuple[int, int] | None`
- error[call-non-callable] kornia/geometry/boxes.py:355:22: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> Unknown, (key: slice[Any, Any, Any], /) -> tuple[Unknown, ...]])` is not callable on object of type `Unknown | tuple[int, int] | None`
+ error[call-non-callable] kornia/geometry/boxes.py:355:22: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> int, (key: slice[Any, Any, Any], /) -> tuple[int, ...]])` is not callable on object of type `Unknown | tuple[int, int] | None`
- error[call-non-callable] kornia/geometry/boxes.py:358:22: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> Unknown, (key: slice[Any, Any, Any], /) -> tuple[Unknown, ...]])` is not callable on object of type `Unknown | tuple[int, int] | None`
+ error[call-non-callable] kornia/geometry/boxes.py:358:22: Method `__getitem__` of type `Unknown | (Overload[(key: SupportsIndex, /) -> int, (key: slice[Any, Any, Any], /) -> tuple[int, ...]])` is not callable on object of type `Unknown | tuple[int, int] | None`
- Found 948 diagnostics
+ Found 936 diagnostics

dedupe (https://github.com/dedupeio/dedupe)
- error[invalid-argument-type] dedupe/convenience.py:77:16: Argument to function `__new__` is incorrect: Expected `Iterable[Unknown]`, found `signedinteger[Unknown]`
- error[invalid-argument-type] dedupe/convenience.py:77:19: Argument to function `__new__` is incorrect: Expected `Iterable[Unknown]`, found `signedinteger[Unknown]`
- Found 64 diagnostics
+ Found 62 diagnostics

comtypes (https://github.com/enthought/comtypes)
+ error[unsupported-operator] comtypes/tools/codegenerator/comments.py:24:71: Operator `not in` is not supported for types `str` and `None`, in comparing `Literal["out"]` with `@Todo(Type::Intersection.call()) | str | list[str] | None`
+ error[unsupported-operator] comtypes/tools/codegenerator/comments.py:25:72: Operator `in` is not supported for types `str` and `None`, in comparing `Literal["out"]` with `@Todo(Type::Intersection.call()) | str | list[str] | None`
- Found 545 diagnostics
+ Found 547 diagnostics

strawberry (https://github.com/strawberry-graphql/strawberry)
- error[invalid-assignment] strawberry/exceptions/handler.py:90:9: Object of type `def strawberry_threading_exception_handler(args: tuple[type[BaseException], BaseException | None, TracebackType | None, Thread | None]) -> None` is not assignable to attribute `excepthook` of type `(_ExceptHookArgs, /) -> Any`
+ error[unresolved-attribute] strawberry/tools/merge_types.py:26:11: Type `type` has no attribute `__strawberry_definition__`

sockeye (https://github.com/awslabs/sockeye)
- warning[division-by-zero] sockeye/data_io.py:531:25: Cannot divide object of type `Literal[0]` by zero
- warning[division-by-zero] sockeye/data_io.py:532:25: Cannot divide object of type `Literal[0]` by zero
- Found 365 diagnostics
+ Found 363 diagnostics

trio (https://github.com/python-trio/trio)
+ error[invalid-argument-type] src/trio/_channel.py:546:38: Argument to bound method `__init__` is incorrect: Expected `MemoryReceiveChannel[Unknown]`, found `MemorySendChannel[Unknown] | MemoryReceiveChannel[Unknown]`
- error[call-non-callable] src/trio/_channel.py:534:32: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_channel.py:534:32: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_channel.py:534:32: Object of type `GenericAlias` is not callable
+ error[invalid-argument-type] src/trio/_core/_tests/test_guest_mode.py:524:66: Argument to function `aio_pingpong` is incorrect: Expected `MemorySendChannel[int]`, found `MemorySendChannel[int] | MemoryReceiveChannel[int]`
- error[call-non-callable] src/trio/_core/_tests/test_guest_mode.py:521:29: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_core/_tests/test_guest_mode.py:521:29: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_core/_tests/test_guest_mode.py:521:29: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_dtls.py:669:26: Object of type `GenericAlias` is not callable
+ warning[possibly-unbound-attribute] src/trio/_dtls.py:748:9: Attribute `send_nowait` on type `Unknown | MemorySendChannel[DTLSChannel] | MemoryReceiveChannel[DTLSChannel]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_dtls.py:789:29: Attribute `send_nowait` on type `Unknown | MemorySendChannel[bytes] | MemoryReceiveChannel[bytes]` is possibly unbound
- error[call-non-callable] src/trio/_tests/test_channel.py:26:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:26:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:26:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:64:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:64:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:64:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:78:37: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:78:37: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:78:37: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:102:41: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:102:41: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:102:41: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:124:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:124:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:124:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:143:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:143:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:143:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:160:15: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:160:15: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:160:15: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:182:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:182:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:182:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:201:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:201:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:201:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:218:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:218:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:218:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:232:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:232:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:232:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:261:13: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:261:13: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:261:13: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:282:13: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:282:13: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:282:13: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:301:21: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:301:21: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:301:21: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:313:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:313:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:313:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:365:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:365:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:365:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:391:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:391:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:391:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:405:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:405:12: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_channel.py:405:12: Object of type `GenericAlias` is not callable
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:30:5: Attribute `send_nowait` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:32:15: Attribute `send` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:34:9: Attribute `send_nowait` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:37:22: Attribute `receive` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:38:12: Attribute `receive_nowait` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:40:9: Attribute `receive_nowait` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:42:5: Attribute `send_nowait` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:45:15: Attribute `send` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:47:9: Attribute `send_nowait` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:52:12: Attribute `receive_nowait` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:54:15: Attribute `receive` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:57:15: Attribute `receive` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:59:9: Attribute `receive_nowait` on type `MemorySendChannel[int | str | None] | MemoryReceiveChannel[int | str | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:66:15: Attribute `receive` on type `MemorySendChannel[str] | MemoryReceiveChannel[str]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:68:11: Attribute `send` on type `MemorySendChannel[str] | MemoryReceiveChannel[str]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:108:23: Attribute `send` on type `MemorySendChannel[int] | MemoryReceiveChannel[int]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:132:9: Attribute `send_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:134:15: Attribute `send` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:138:9: Attribute `receive_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:140:15: Attribute `receive` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:151:9: Attribute `send_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:153:15: Attribute `send` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:168:9: Attribute `receive_nowait` on type `MemorySendChannel[int] | MemoryReceiveChannel[int]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:170:15: Attribute `receive` on type `MemorySendChannel[int] | MemoryReceiveChannel[int]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:190:9: Attribute `send_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:192:15: Attribute `send` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:196:9: Attribute `receive_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:198:15: Attribute `receive` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:209:9: Attribute `send_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:211:15: Attribute `send` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:226:9: Attribute `receive_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:228:15: Attribute `receive` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:237:5: Attribute `send_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:249:5: Attribute `send_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:255:9: Attribute `send_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:266:19: Attribute `send` on type `Unknown | MemorySendChannel[str] | MemoryReceiveChannel[str]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:269:15: Attribute `send` on type `Unknown | MemorySendChannel[str] | MemoryReceiveChannel[str]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:276:22: Attribute `receive` on type `MemorySendChannel[str] | MemoryReceiveChannel[str]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:287:19: Attribute `receive` on type `Unknown | MemorySendChannel[str] | MemoryReceiveChannel[str]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:290:22: Attribute `receive` on type `Unknown | MemorySendChannel[str] | MemoryReceiveChannel[str]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:297:15: Attribute `send` on type `MemorySendChannel[str] | MemoryReceiveChannel[str]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:306:13: Attribute `send_nowait` on type `MemorySendChannel[int] | MemoryReceiveChannel[int]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:324:5: Attribute `send_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:338:9: Attribute `send_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:340:28: Attribute `send` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:341:28: Attribute `send` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:350:13: Attribute `receive_nowait` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:355:28: Attribute `receive` on type `MemorySendChannel[None] | MemoryReceiveChannel[None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:366:5: Attribute `send_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:367:12: Attribute `receive_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:368:5: Attribute `send_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:369:12: Attribute `receive_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:383:9: Attribute `send_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:385:13: Attribute `receive_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:392:5: Attribute `send_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:394:9: Attribute `send_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:396:28: Attribute `send` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:398:16: Attribute `receive_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:400:13: Attribute `send_nowait` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:401:23: Attribute `receive` on type `MemorySendChannel[int | None] | MemoryReceiveChannel[int | None]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:407:9: Attribute `receive_nowait` on type `MemorySendChannel[int] | MemoryReceiveChannel[int]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:409:9: Attribute `send_nowait` on type `MemorySendChannel[int] | MemoryReceiveChannel[int]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:418:26: Attribute `receive` on type `MemorySendChannel[int] | MemoryReceiveChannel[int]` is possibly unbound
+ warning[possibly-unbound-attribute] src/trio/_tests/test_channel.py:420:9: Attribute `receive_nowait` on type `MemorySendChannel[int] | MemoryReceiveChannel[int]` is possibly unbound
- error[call-non-callable] src/trio/_tests/test_highlevel_serve_listeners.py:41:31: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_sync.py:423:26: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_sync.py:439:26: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/test_sync.py:454:26: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/type_tests/open_memory_channel.py:4:8: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/type_tests/open_memory_channel.py:4:8: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/_tests/type_tests/open_memory_channel.py:4:8: Object of type `GenericAlias` is not callable
- error[call-non-callable] src/trio/testing/_fake_net.py:230:54: Object of type `GenericAlias` is not callable
- Found 1010 diagnostics
+ Found 1009 diagnostics

pydantic (https://github.com/pydantic/pydantic)
- error[invalid-assignment] pydantic/_internal/_generics.py:97:1: Object of type `ContextVar[None]` is not assignable to `ContextVar[WeakValueDictionary[tuple[@Todo(Generic tuple specializations), ...], type[BaseModel]] | None]`
+ error[invalid-assignment] pydantic/_internal/_generics.py:97:1: Object of type `ContextVar[None]` is not assignable to `ContextVar[WeakValueDictionary[tuple[Any, Any, tuple[Any, ...]], type[BaseModel]] | None]`
- error[invalid-return-type] pydantic/version.py:84:12: Return type does not match returned value: expected `tuple[int, int, int]`, found `tuple[Unknown, ...]`
- Found 731 diagnostics
+ Found 730 diagnostics

rich (https://github.com/Textualize/rich)
+ error[invalid-argument-type] tests/test_syntax.py:169:38: Argument to bound method `get_style_for_token` is incorrect: Expected `tuple[str, ...]`, found `Literal["abc"]`
- Found 373 diagnostics
+ Found 374 diagnostics

flake8 (https://github.com/pycqa/flake8)
- error[invalid-return-type] src/flake8/checker.py:605:16: Return type does not match returned value: expected `tuple[int, int]`, found `int & tuple[Unknown, ...]`
+ error[unsupported-operator] src/flake8/checker.py:609:12: Operator `<=` is not supported for types `int` and `tuple[int, int]`, in comparing `int & ~tuple[Unknown, ...]` with `Unknown | int | tuple[int, int]`
+ warning[possibly-unbound-implicit-call] src/flake8/checker.py:615:13: Method `__getitem__` of type `Unknown | int | tuple[int, int]` is possibly unbound
+ error[unsupported-operator] src/flake8/checker.py:615:26: Operator `-` is unsupported between objects of type `Unknown | int` and `Unknown | int | tuple[int, int]`
+ warning[possibly-unbound-implicit-call] src/flake8/checker.py:615:26: Method `__getitem__` of type `Unknown | int | tuple[int, int]` is possibly unbound
+ error[not-iterable] src/flake8/processor.py:166:34: Object of type `int` is not iterable
- Found 43 diagnostics
+ Found 47 diagnostics

yarl (https://github.com/aio-libs/yarl)
- error[invalid-argument-type] tests/test_pickle.py:29:20: Argument to bound method `__setstate__` is incorrect: Expected `tuple[Unknown | tuple[@Todo(Generic tuple specializations), ...]] | tuple[None, _InternalURLCache]`, found `tuple[None, dict[Unknown, Unknown]]`
+ error[invalid-argument-type] tests/test_pickle.py:29:20: Argument to bound method `__setstate__` is incorrect: Expected `tuple[Unknown | tuple[str, str, str, str, str]] | tuple[None, _InternalURLCache]`, found `tuple[None, dict[Unknown, Unknown]]`

hydra-zen (https://github.com/mit-ll-responsible-ai/hydra-zen)
- warning[possibly-unbound-attribute] src/hydra_zen/structured_configs/_implementations.py:2146:28: Attribute `get` on type `DataclassOptions | None` is possibly unbound
- warning[possibly-unbound-attribute] src/hydra_zen/structured_configs/_implementations.py:3153:21: Attribute `get` on type `DataclassOptions | None` is possibly unbound
- Found 597 diagnostics
+ Found 595 diagnostics

poetry (https://github.com/python-poetry/poetry)
- error[invalid-return-type] tests/conftest.py:432:12: Return type does not match returned value: expected `tuple[int, int, int]`, found `Unknown | tuple[@Todo(Generic tuple specializations), ...]`
+ error[invalid-return-type] tests/conftest.py:432:12: Return type does not match returned value: expected `tuple[int, int, int]`, found `Unknown | tuple[int | str, ...]`

urllib3 (https://github.com/urllib3/urllib3)
+ warning[possibly-unbound-attribute] src/urllib3/filepost.py:72:9: Attribute `write` on type `Unknown | tuple[bytes, int]` is possibly unbound
+ error[invalid-argument-type] src/urllib3/filepost.py:72:16: Argument to bound method `__call__` is incorrect: Expected `str`, found `BytesIO`
+ warning[possibly-unbound-attribute] src/urllib3/filepost.py:79:13: Attribute `write` on type `Unknown | tuple[bytes, int]` is possibly unbound
+ error[invalid-argument-type] src/urllib3/filepost.py:79:20: Argument to bound method `__call__` is incorrect: Expected `str`, found `BytesIO`
- Found 506 diagnostics
+ Found 510 diagnostics

vision (https://github.com/pytorch/vision)
- error[invalid-return-type] references/depth/stereo/transforms.py:108:16: Return type does not match returned value: expected `tuple[@Todo(Inference of subscript on special form), tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)]]`, found `tuple[@Todo(Inference of subscript on special form), tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)], tuple[Unknown, ...]]`
- error[invalid-return-type] references/depth/stereo/transforms.py:124:16: Return type does not match returned value: expected `tuple[@Todo(Inference of subscript on special form), tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)]]`, found `tuple[tuple[Unknown, ...], tuple[Unknown, ...], tuple[Unknown, ...]]`
- error[invalid-return-type] references/depth/stereo/transforms.py:190:16: Return type does not match returned value: expected `tuple[@Todo(Inference of subscript on special form), tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)]]`, found `tuple[tuple[Unknown, Unknown], tuple[()] | tuple[Unknown] | tuple[None], tuple[()] | tuple[Unknown] | tuple[None]]`
+ error[invalid-return-type] references/depth/stereo/transforms.py:190:16: Return type does not match returned value: expected `tuple[tuple[Unknown, Unknown], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)]]`, found `tuple[tuple[Unknown, Unknown], tuple[()] | tuple[Unknown] | tuple[None], tuple[()] | tuple[Unknown] | tuple[None]]`
- error[invalid-return-type] references/depth/stereo/transforms.py:485:16: Return type does not match returned value: expected `tuple[@Todo(Inference of subscript on special form), tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)]]`, found `tuple[tuple[()] | tuple[Unknown], tuple[()] | tuple[Unknown] | tuple[None], tuple[()] | tuple[Unknown] | tuple[None]]`
+ error[invalid-return-type] references/depth/stereo/transforms.py:485:16: Return type does not match returned value: expected `tuple[tuple[Unknown, Unknown], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)]]`, found `tuple[tuple[()] | tuple[Unknown], tuple[()] | tuple[Unknown] | tuple[None], tuple[()] | tuple[Unknown] | tuple[None]]`
- error[invalid-return-type] references/depth/stereo/transforms.py:601:16: Return type does not match returned value: expected `tuple[@Todo(Inference of subscript on special form), tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)]]`, found `tuple[tuple[Unknown, Unknown], tuple[(@Todo(Inference of subscript on special form) & None) | Unknown, (@Todo(Inference of subscript on special form) & None) | Unknown], tuple[()] | tuple[(@Todo(Inference of subscript on special form) & None) | Unknown]]`
+ error[invalid-return-type] references/depth/stereo/transforms.py:601:16: Return type does not match returned value: expected `tuple[tuple[Unknown, Unknown], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)], tuple[@Todo(Inference of subscript on special form), @Todo(Inference of subscript on special form)]]`, found `tuple[tuple[Unknown, Unknown], tuple[(@Todo(Inference of subscript on special form) & None) | Unknown, (@Todo(Inference of subscript on special form) & None) | Unknown], tuple[()] | tuple[(@Todo(Inference of subscript on special form) & None) | Unknown]]`
- error[invalid-assignment] test/datasets_utils.py:1043:9: Object of type `LiteralString` is not assignable to `tuple[str, ...]`
- Found 1541 diagnostics
+ Found 1538 diagnostics

paasta (https://github.com/yelp/paasta)
- error[unresolved-reference] paasta_tools/paastaapi/model/instance_status_adhoc.py:152:30: Name `_path_to_item` used when not defined
- error[unresolved-reference] paasta_tools/paastaapi/model/instance_tasks.py:147:30: Name `_path_to_item` used when not defined
- error[unresolved-reference] paasta_tools/paastaapi/model/resource.py:152:30: Name `_path_to_item` used when not defined
+ error[invalid-return-type] paasta_tools/utils.py:3111:12: Return type does not match returned value: expected `str`, found `str | int`
- Found 954 diagnostics
+ Found 952 diagnostics

schemathesis (https://github.com/schemathesis/schemathesis)
- error[invalid-argument-type] src/schemathesis/specs/openapi/patterns.py:325:42: Argument to function `_handle_repeat_quantifier` is incorrect: Expected `tuple[int, int, tuple[Unknown, ...]]`, found `tuple[Unknown, ...]`
- Found 315 diagnostics
+ Found 314 diagnostics

jinja (https://github.com/pallets/jinja)
- warning[possibly-unresolved-reference] src/jinja2/filters.py:1740:17: Name `name` used when possibly not defined
- Found 209 diagnostics
+ Found 208 diagnostics

pwndbg (https://github.com/pwndbg/pwndbg)
+ error[invalid-assignment] pwndbg/commands/hijack_fd.py:222:13: Object of type `str | int | bytes` is not assignable to `str`
- error[invalid-assignment] pwndbg/emu/emulator.py:514:9: Object of type `tuple[Unknown, ...]` is not assignable to `tuple[str]`
- error[invalid-return-type] pwndbg/emu/emulator.py:841:20: Return type does not match returned value: expected `tuple[int, int]`, found `InstructionExecutedResult`
- error[invalid-return-type] pwndbg/emu/emulator.py:869:24: Return type does not match returned value: expected `tuple[int, int]`, found `InstructionExecutedResult`
+ error[unsupported-operator] pwndbg/integration/binja.py:451:17: Operator `-` is unsupported between objects of type `Unknown | int | None` and `int`
+ error[unsupported-operator] pwndbg/integration/binja.py:452:15: Operator `+` is unsupported between objects of type `Unknown | int | None` and `int`

pywin32 (https://github.com/mhammond/pywin32)
+ error[invalid-argument-type] Pythonwin/pywin/framework/editor/configui.py:254:41: Argument to function `RGB` is incorrect: Expected `int`, found `Unknown | Literal["Black", "Navy", "Green", "Cyan", "Maroon", "Purple", "Olive", "Gray", "Silver", "Blue", "Lime", "Aqua", "Red", "Fuchsia", "Yellow", "White", 0, 128, 192, 255]`
+ error[invalid-argument-type] Pythonwin/pywin/framework/editor/configui.py:254:47: Argument to function `RGB` is incorrect: Expected `int`, found `Unknown | Literal["Black", "Navy", "Green", "Cyan", "Maroon", "Purple", "Olive", "Gray", "Silver", "Blue", "Lime", "Aqua", "Red", "Fuchsia", "Yellow", "White", 0, 128, 192, 255]`
+ error[invalid-argument-type] Pythonwin/pywin/framework/editor/configui.py:254:53: Argument to function `RGB` is incorrect: Expected `int`, found `Unknown | Literal["Black", "Navy", "Green", "Cyan", "Maroon", "Purple", "Olive", "Gray", "Silver", "Blue", "Lime", "Aqua", "Red", "Fuchsia", "Yellow", "White", 0, 128, 192, 255]`
+ error[call-non-callable] com/win32com/makegw/makegwparse.py:786:16: Object of type `int` is not callable
- error[invalid-argument-type] com/win32com/test/testDynamic.py:61:51: Argument to function `Dispatch` is incorrect: Expected `str | PyIDispatch | tuple[@Todo(Generic tuple specializations), ...] | PyIUnknown`, found `Unknown | PyIID`
+ error[invalid-argument-type] com/win32com/test/testDynamic.py:61:51: Argument to function `Dispatch` is incorrect: Expected `str | PyIDispatch | tuple[type[str], <class 'PyIID'>] | PyIUnknown`, found `Unknown | PyIID`
+ error[invalid-argument-type] com/win32comext/adsi/demos/scp.py:393:45: Argument to function `wrap` is incorrect: Expected `str`, found `Unknown | str | None`
- error[invalid-argument-type] win32/Demos/win32gui_menu.py:434:67: Argument to function `ExtTextOut` is incorrect: Expected `PyRECT`, found `tuple[Any, Any, Any, Any]`
+ error[invalid-argument-type] win32/Demos/win32gui_menu.py:434:67: Argument to function `ExtTextOut` is incorrect: Expected `PyRECT`, found `tuple[@Todo(Unpack variable-length tuple), @Todo(Unpack variable-length tuple), @Todo(Unpack variable-length tuple), @Todo(Unpack variable-length tuple)]`
- Found 2318 diagnostics
+ Found 2323 diagnostics

psycopg (https://github.com/psycopg/psycopg)
- error[invalid-return-type] psycopg/psycopg/_py_transformer.py:329:16: Return type does not match returned value: expected `Row`, found `tuple[@Todo(Generic tuple specializations), ...]`
+ error[invalid-return-type] psycopg/psycopg/_py_transformer.py:329:16: Return type does not match returned value: expected `Row`, found `tuple[Any, ...]`

discord.py (https://github.com/Rapptz/discord.py)
- error[invalid-argument-type] discord/ext/commands/converter.py:1122:16: Argument to function `len` is incorrect: Expected `Sized`, found `tuple[T] | T`
+ error[invalid-argument-type] discord/ext/commands/converter.py:1122:16: Argument to function `len` is incorrect: Expected `Sized`, found `(tuple[T] & tuple[Unknown, ...]) | (T & tuple[Unknown, ...]) | tuple[T] | T`
+ warning[possibly-unbound-implicit-call] discord/ext/commands/converter.py:1124:21: Method `__getitem__` of type `(tuple[T] & tuple[Unknown, ...]) | (T & tuple[Unknown, ...]) | tuple[T] | T` is possibly unbound
- warning[possibly-unbound-implicit-call] discord/ext/commands/converter.py:1124:21: Method `__getitem__` of type `tuple[T] | T` is possibly unbound
- warning[unused-ignore-comment] discord/ext/commands/converter.py:1136:75: Unused blanket `type: ignore` directive
- Found 576 diagnostics
+ Found 575 diagnostics

cwltool (https://github.com/common-workflow-language/cwltool)
+ warning[possibly-unbound-attribute] cwltool/cwlprov/__init__.py:16:20: Attribute `split` on type `str | int` is possibly unbound
- Found 188 diagnostics
+ Found 189 diagnostics

mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
+ error[invalid-argument-type] pymongo/asynchronous/auth.py:224:45: Argument to function `_canonicalize_hostname` is incorrect: Expected `str`, found `(Unknown & ~AlwaysFalsy) | Unknown | str | int`
- warning[unused-ignore-comment] pymongo/pool_shared.py:352:84: Unused blanket `type: ignore` directive
- warning[unused-ignore-comment] pymongo/pool_shared.py:472:77: Unused blanket `type: ignore` directive
+ error[invalid-argument-type] pymongo/pool_shared.py:521:54: Argument to bound method `wrap_socket` is incorrect: Expected `str | None`, found `Unknown | str | int | None`
+ error[invalid-argument-type] pymongo/synchronous/auth.py:221:39: Argument to function `_canonicalize_hostname` is incorrect: Expected `str`, found `(Unknown & ~AlwaysFalsy) | Unknown | str | int`
- Found 528 diagnostics
+ Found 529 diagnostics

mitmproxy (https://github.com/mitmproxy/mitmproxy)
- warning[possibly-unbound-implicit-call] examples/contrib/change_upstream_proxy.py:28:34: Method `__getitem__` of type `Unknown | tuple[@Todo(Generic tuple specializations), ...] | None` is possibly unbound
+ warning[possibly-unbound-implicit-call] examples/contrib/change_upstream_proxy.py:28:34: Method `__getitem__` of type `Unknown | tuple[Literal["http", "https", "http3", "tls", "dtls", "tcp", "udp", "dns", "quic"], tuple[str, int]] | None` is possibly unbound
+ error[call-non-callable] mitmproxy/http.py:422:13: Method `__getitem__` of type `(Overload[(key: SupportsIndex | slice[Any, Any, Any], /) -> LiteralString, (key: SupportsIndex | slice[Any, Any, Any], /) -> str]) | (bound method dict[str, str].__getitem__(key: str, /) -> str) | (bound method dict[Unknown, Unknown].__getitem__(key: Unknown, /) -> Unknown)` is not callable on object of type `str | dict[str, str] | dict[Unknown, Unknown]`
- warning[unused-ignore-comment] mitmproxy/net/server_spec.py:85:34: Unused blanket `type: ignore` directive
+ error[invalid-assignment] mitmproxy/proxy/layers/http/_upstream_proxy.py:42:13: Object of type `@Todo(map_with_boundness: intersections with negative contributions) | str | int` is not assignable to attribute `sni` of type `str | None`
+ error[invalid-assignment] test/mitmproxy/addons/test_next_layer.py:374:17: Object of type `tuple[Literal["2001:db8::1"], Literal[443], Literal[0], Literal[0]] | tuple[Literal["192.0.2.1"], Literal[443]]` is not assignable to attribute `peername` of type `tuple[str, int] | None`
- Found 1847 diagnostics
+ Found 1849 diagnostics

pytest (https://github.com/pytest-dev/pytest)
- error[no-matching-overload] src/_pytest/raises.py:283:20: No overload of bound method `__init__` matches arguments
- Found 655 diagnostics
+ Found 654 diagnostics

pycryptodome (https://github.com/Legrandin/pycryptodome)
+ error[no-matching-overload] lib/Crypto/SelfTest/Protocol/test_SecretSharing.py:226:47: No overload of function `__new__` matches arguments
+ error[no-matching-overload] lib/Crypto/SelfTest/Protocol/test_SecretSharing.py:226:47: No overload of function `__new__` matches arguments
+ error[no-matching-overload] lib/Crypto/SelfTest/Protocol/test_SecretSharing.py:226:47: No overload of function `__new__` matches arguments
- Found 1549 diagnostics
+ Found 1552 diagnostics

aiohttp (https://github.com/aio-libs/aiohttp)
- warning[possibly-unbound-attribute] aiohttp/resolver.py:102:26: Attribute `get_resolver` on type `_DNSResolverManager | None` is possibly unbound
- Found 139 diagnostics
+ Found 138 diagnostics

meson (https://github.com/mesonbuild/meson)
+ warning[possibly-unbound-attribute] mesonbuild/backend/vs2010backend.py:430:56: Attribute `parents` on type `Unknown | str | Path | MachineChoice` is possibly unbound
+ warning[possibly-unbound-attribute] mesonbuild/backend/vs2010backend.py:531:24: Attribute `parent` on type `Unknown | str | Path | MachineChoice` is possibly unbound
+ warning[possibly-unbound-attribute] mesonbuild/backend/vs2010backend.py:532:87: Attribute `parent` on type `Unknown | str | Path | MachineChoice` is possibly unbound
- Found 1216 diagnostics
+ Found 1219 diagnostics

cloud-init (https://github.com/canonical/cloud-init)
- error[invalid-return-type] cloudinit/cmd/main.py:277:28: Return type does not match returned value: expected `tuple[int, str]`, found `DeprecationLog`
- error[invalid-return-type] cloudinit/config/cc_growpart.py:214:12: Return type does not match returned value: expected `Resizer`, found `None | (Unknown & ~AlwaysFalsy)`
+ error[invalid-return-type] cloudinit/config/cc_growpart.py:214:12: Return type does not match returned value: expected `Resizer`, found `None | (Unknown & ~AlwaysFalsy) | (ResizeGrowPart & ~AlwaysFalsy) | (ResizeGrowFS & ~AlwaysFalsy) | (ResizeGpart & ~AlwaysFalsy)`
- error[unsupported-operator] cloudinit/util.py:1331:16: Operator `not in` is not supported for types `Unknown` and `None`, in comparing `Unknown` with `set[Unknown] | Unknown | None`
+ error[unsupported-operator] cloudinit/util.py:1331:16: Operator `not in` is not supported for types `str` and `None`, in comparing `str | int | bytes` with `set[Unknown] | Unknown | None`
- Found 741 diagnostics
+ Found 740 diagnostics

apprise (https://github.com/caronc/apprise)
+ warning[possibly-unbound-attribute] apprise/plugins/email/base.py:413:21: Attribute `match` on type `Unknown | Literal["Google Mail", "Yandex", "Microsoft Hotmail", "Microsoft Outlook", "Microsoft Office 365", "Yahoo Mail", "Fast Mail", "Fast Mail Extended Addresses", "Zoho Mail", "SendGrid", "163.com", "Foxmail.com", "Comcast.net", "Custom"] | Pattern[str] | dict[Unknown, Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] apprise/plugins/email/base.py:420:31: Attribute `get` on type `Unknown | Literal["Google Mail", "Yandex", "Microsoft Hotmail", "Microsoft Outlook", "Microsoft Office 365", "Yahoo Mail", "Fast Mail", "Fast Mail Extended Addresses", "Zoho Mail", "SendGrid", "163.com", "Foxmail.com", "Comcast.net", "Custom"] | Pattern[str] | dict[Unknown, Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] apprise/plugins/email/base.py:425:34: Attribute `get` on type `Unknown | Literal["Google Mail", "Yandex", "Microsoft Hotmail", "Microsoft Outlook", "Microsoft Office 365", "Yahoo Mail", "Fast Mail", "Fast Mail Extended Addresses", "Zoho Mail", "SendGrid", "163.com", "Foxmail.com", "Comcast.net", "Custom"] | Pattern[str] | dict[Unknown, Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] apprise/plugins/email/base.py:431:33: Attribute `get` on type `Unknown | Literal["Google Mail", "Yandex", "Microsoft Hotmail", "Microsoft Outlook", "Microsoft Office 365", "Yahoo Mail", "Fast Mail", "Fast Mail Extended Addresses", "Zoho Mail", "SendGrid", "163.com", "Foxmail.com", "Comcast.net", "Custom"] | Pattern[str] | dict[Unknown, Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] apprise/plugins/email/base.py:434:40: Attribute `get` on type `Unknown | Literal["Google Mail", "Yandex", "Microsoft Hotmail", "Microsoft Outlook", "Microsoft Office 365", "Yahoo Mail", "Fast Mail", "Fast Mail Extended Addresses", "Zoho Mail", "SendGrid", "163.com", "Foxmail.com", "Comcast.net", "Custom"] | Pattern[str] | dict[Unknown, Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] apprise/plugins/email/base.py:442:21: Attribute `get` on type `Unknown | Literal["Google Mail", "Yandex", "Microsoft Hotmail", "Microsoft Outlook", "Microsoft Office 365", "Yahoo Mail", "Fast Mail", "Fast Mail Extended Addresses", "Zoho Mail", "SendGrid", "163.com", "Foxmail.com", "Comcast.net", "Custom"] | Pattern[str] | dict[Unknown, Unknown]` is possibly unbound
+ warning[possibly-unbound-attribute] test/test_plugin_email.py:369:24: Attribute `parse_url` on type `Unknown | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/test_plugin_email.py:370:24: Attribute `parse_url` on type `Unknown | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/test_plugin_email.py:371:24: Attribute `parse_url` on type `Unknown | None` is possibly unbound
- Found 4453 diagnostics
+ Found 4462 diagnostics

sphinx (https://github.com/sphinx-doc/sphinx)
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:564:25: Attribute `code` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:564:55: Attribute `filename` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:564:73: Attribute `lineno` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:569:25: Attribute `code` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:570:35: Attribute `filename` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:570:53: Attribute `lineno` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:577:31: Attribute `options` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:594:21: Attribute `code` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:597:28: Attribute `lineno` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:604:21: Attribute `filename` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/ext/doctest.py:605:21: Attribute `lineno` on type `TestCode | None` is possibly unbound
+ warning[possibly-unbound-attribute] sphinx/util/docfields.py:479:13: Attribute `append` on type `Field | list[@Todo(Support for `typing.TypeAlias`)] | Node | (Unknown & ~None)` is possibly unbound
- Found 631 diagnostics
+ Found 643 diagnostics

bokeh (https://github.com/bokeh/bokeh)
+ error[invalid-assignment] src/bokeh/layouts.py:587:13: Object of type `UIElement | int` is not assignable to `row | col`
+ error[invalid-argument-type] src/bokeh/layouts.py:588:33: Argument to function `_has_auto_sizing` is incorrect: Expected `LayoutDOM`, found `row | col`
+ error[invalid-assignment] src/bokeh/layouts.py:589:17: Object of type `Unknown & ~None` is not assignable to attribute `sizing_mode` on type `row | col`
- error[invalid-return-type] src/bokeh/layouts.py:666:16: Return type does not match returned value: expected `list[L]`, found `list[L | list[L]]`
+ error[invalid-argument-type] src/bokeh/server/tornado.py:419:31: Argument to function `issubclass` is incorrect: Expected `type`, found `str | type[RequestHandler] | dict[str, Any]`
- error[invalid-argument-type] src/bokeh/util/deprecation.py:70:10: Argument to function `warn` is incorrect: Expected `str`, found `str | (tuple[@Todo(Generic tuple specializations), ...] & ~tuple[Unknown, ...])`
+ error[invalid-argument-type] src/bokeh/util/deprecation.py:70:10: Argument to function `warn` is incorrect: Expected `str`, found `str | (tuple[int, int, int] & ~tuple[Unknown, ...]) | (str & ~tuple[Unknown, ...])`
- Found 920 diagnostics
+ Found 923 diagnostics

static-frame (https://github.com/static-frame/static-frame)
- warning[unused-ignore-comment] static_frame/core/container_util.py:1653:84: Unused blanket `type: ignore` directive
- warning[unused-ignore-comment] static_frame/core/container_util.py:1662:81: Unused blanket `type: ignore` directive
+ warning[possibly-unbound-attribute] static_frame/core/container_util.py:1667:39: Attribute `index_types` on type `IndexBase | IMTOAdapter | Unknown` is possibly unbound
+ warning[unused-ignore-comment] static_frame/core/db_util.py:389:66: Unused blanket `type: ignore` directive
+ warning[unused-ignore-comment] static_frame/core/db_util.py:391:87: Unused blanket `type: ignore` directive
- warning[unused-ignore-comment] static_frame/core/reduce.py:460:48: Unused blanket `type: ignore` directive
- warning[unused-ignore-comment] static_frame/core/reduce.py:484:48: Unused blanket `type: ignore` directive
+ error[invalid-assignment] static_frame/test/unit/test_archive_npy.py:174:21: Too many values to unpack: Expected 2
- error[invalid-argument-type] static_frame/test/unit/test_store_config.py:13:31: Argument to function `label_encode_tuple` is incorrect: Expected `tuple[Any]`, found `tuple[Unknown, ...]`
- error[invalid-argument-type] static_frame/test/unit/test_store_config.py:14:31:...*[Comment body truncated]*

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Jun 9, 2025
@AlexWaygood
Copy link
Member

This is really exciting! One nit:

This adds support for homogeneous tuples (tuple[int, ...])

I thought we already supported homogenous tuples following #17998 — I thought it was just the mixed partially-homogenous-partially-heterogeneous ones that we didn't support yet?

@dcreager
Copy link
Member Author

I thought we already supported homogenous tuples following #17998 — I thought it was just the mixed partially-homogenous-partially-heterogeneous ones that we didn't support yet?

Yep you're right! I had just put in a placeholder PR body for now

dcreager added 3 commits June 10, 2025 14:20
* main:
  [`pylint`] De-emphasize `__hash__ = Parent.__hash__` (`PLW1641`) (#18613)
  [`flake8-pyi`] Avoid syntax error in the case of starred and keyword arguments (`PYI059`) (#18611)
  [ty] Add support for global __debug__ constant (#18540)
  [`ruff`] Preserve parentheses around `deque` in fix for `unnecessary-empty-iterable-within-deque-call` (`RUF037`) (#18598)
  [`refurb`] Parenthesize lambda and ternary expressions in iter (`FURB122`, `FURB142`) (#18592)
Copy link

codspeed-hq bot commented Jun 10, 2025

CodSpeed Instrumentation Performance Report

Merging #18600 will degrade performances by 11.29%

Comparing dcreager/tuple-spec (e5aa429) with main (d926628)

Summary

❌ 1 (👁 1) regressions
✅ 36 untouched benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
👁 ty_micro[many_tuple_assignments] 180.7 ms 203.7 ms -11.29%

dcreager added 5 commits June 10, 2025 16:30
* main:
  [ty] implement disjointness of Callable vs SpecialForm (#18503)
  [ty] more simplification of infer_parameterized_legacy_typing_alias (#18526)
  [`refurb`] Add a note about float literal handling (`FURB157`) (#18615)
* main:
  [ty] Add some "inside string" tests for `object.<CURSOR>` completions
  [ty] Pull types on synthesized Python files created by mdtest (#18539)
  Update Rust crate anstyle to v1.0.11 (#18583)
  [`pyupgrade`] Fix `super(__class__, self)` detection in UP008 (super-call-with-parameters) (#18478)
  [ty] Generate the top and bottom materialization of a type (#18594)
  `SourceOrderVisitor` should visit the `Identifier` part of the `PatternKeyword` node (#18635)
  Update salsa (#18636)
  [ty] Update mypy_primer doc (#18638)
  [ty] Improve support for `object.<CURSOR>` completions
  [ty] Add `CoveringNode::find_last`
  [ty] Refactor covering node representation
  [ty] Infer the Python version from `--python=<system installation>` on Unix (#18550)
  [`flake8-return`] Fix `RET504` autofix generating a syntax error (#18428)
  Fix incorrect salsa `return_ref` attribute (#18605)
  Move corpus tests to `ty_python_semantic` (#18609)
  [`pyupgrade`] Don't offer fix for `Optional[None]` in non-pep604-annotation-optional (`UP045)` or non-pep604-annotation-union (`UP007`) (#18545)
  [`pep8-naming`] Suppress fix for `N804` and `N805` if the recommend name is already used (#18472)
  [`ruff`] skip fix for `RUF059` if dummy name is already bound (unused-unpacked-variable) (#18509)
@AlexWaygood
Copy link
Member

AlexWaygood commented Jun 20, 2025

(It's fine to address this comment in a followup; doesn't need to be tackled in this PR!) --

Do we need to add some more tests and TODOs around generics solving for mixed tuples and pure-homogeneous tuples? It looks like for these four reveal_type calls, we're only able to solve the TypeVar for the call to g() on this branch -- the rest of the calls are all revealed as Unknown:

from typing import reveal_type

def f[T](x: tuple[int, bytes, *tuple[str, ...], T, int]) -> T:
    return x[-2]

reveal_type(f((1, b"foo", "bar", "baz", True, 42)))  # Unknown

def f2[T](x: tuple[int, T, *tuple[str, ...], bool, int]) -> T:
    return x[1]

reveal_type(f2((1, b"foo", "bar", "baz", True, 42)))  # Unknown

def g[T](x: tuple[T, int]) -> T:
    return x[0]

reveal_type(g((True, 42)))  # bool

def h[T](x: tuple[T, ...]) -> T:
    return x[0]

reveal_type(h((42,)))  # Unknown

@dcreager dcreager closed this Jun 20, 2025
@dcreager dcreager reopened this Jun 20, 2025
@dcreager
Copy link
Member Author

The point I raised in #18600 (comment) still stands: it's unsound to allow tuple generic aliases to be directly instantiated without checking the arguments passed in.

I misunderstood this the first time around — I thought you were asking about reveal_type((1, 2).__class__), not reveal_type((1, 2).__class__()). Now that I understand what you mean, I added these as TODO tests.

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really great work -- thank you!

@dcreager
Copy link
Member Author

Do we need to add some more tests and TODOs around generics solving for mixed tuples and pure-homogeneous tuples?

Done. (We already had a TODO comment in the code, just no TODO tests)

dcreager added 2 commits June 20, 2025 18:11
* main:
  Handle parenthesized arguments in `remove_argument` (#18805)
  Unify helpers modules (#18835)
  Normalize some docs sections (#18831)
  [`flake8_pyi`] Fix `PYI041`'s fix causing TypeError with `None | None | ...` (#18637)
Copy link

codspeed-hq bot commented Jun 20, 2025

CodSpeed WallTime Performance Report

Merging #18600 will improve performances by 4.04%

Comparing dcreager/tuple-spec (e5aa429) with main (d926628)

Summary

⚡ 1 improvements
✅ 5 untouched benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
medium[colour-science] 9 s 8.7 s +4.04%

@AlexWaygood
Copy link
Member

There is a fairly big primer report here -- have you spot-checked them/do the new diagnostics make sense?

@dcreager dcreager merged commit ea812d0 into main Jun 20, 2025
36 checks passed
@dcreager dcreager deleted the dcreager/tuple-spec branch June 20, 2025 22:23
@carljm
Copy link
Contributor

carljm commented Jun 21, 2025

Another really useful follow-up to uncover any issues here would be to add support to our property tests to generate variadic and mixed tuple types. Should be pretty easy (unless it uncovers actual problems!)

@sharkdp
Copy link
Contributor

sharkdp commented Jun 23, 2025

There is a fairly big primer report here

I uploaded a rich diff here: https://shark.fish/diff-tuple-spec.html

@AlexWaygood
Copy link
Member

AlexWaygood commented Jun 23, 2025

I uploaded a rich diff here: shark.fish/diff-tuple-spec.html

I have a WIP patch locally to fix the 58 new incompatible-slots false positives on sympy

@dcreager
Copy link
Member Author

strawberry/tools/merge_types.py
[error] unresolved-attribute - :26:11 - Type type has no attribute __strawberry_definition__

This one is because there's a function that returns a TypeGuard of a Protocol, where the protocol includes the attribute in question

@dcreager
Copy link
Member Author

A lot of the new possibly-unbound-attribute diagnostics are because of astral-sh/ty#625 — there's a union with Unknown, which means we fall back on the typeshed definition of tuple.__getitem__, which returns a union of all elements instead of hitting our special-case logic to pull out a specific element.

dcreager added a commit that referenced this pull request Jun 24, 2025
Add property test generators for the new variable-length tuples. This
covers homogeneous tuples as well.

The property tests did their job! This identified several fixes we
needed to make to various type property methods.

cf #18600 (comment)

---------

Co-authored-by: Alex Waygood <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ecosystem-analyzer ty Multi-file analysis & type inference
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants