Skip to content

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