← Back to index

tuples_type_compat.py

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 24
FP: 0
FN: 0
Optional: 0 / 0
1"""
2Tests type compatibility rules for tuples.
3"""
4
5# Specification: https://typing.readthedocs.io/en/latest/spec/tuples.html#type-compatibility-rules
6
7# > Because tuple contents are immutable, the element types of a tuple are covariant.
8
9
10from typing import Any, Iterable, Never, Sequence, TypeAlias, TypeVar, assert_type
13def func1(t1: tuple[float, complex], t2: tuple[int, int]):
14 v1: tuple[float, complex] = t2 # OK
15 v2: tuple[int, int] = t1 # E
[invalid-assignment] Object of type `tuple[int | float, int | float | complex]` is not assignable to `tuple[int, int]`
18# > A homogeneous tuple of arbitrary length is equivalent
19# > to a union of tuples of different lengths.
22def func2(t1: tuple[int], t2: tuple[int, *tuple[int, ...]], t3: tuple[int, ...]):
23 v1: tuple[int, ...]
24 v1 = t1 # OK
25 v1 = t2 # OK
27 v2: tuple[int, *tuple[int, ...]]
28 v2 = t1 # OK
29 v2 = t3 # E
[invalid-assignment] Object of type `tuple[int, ...]` is not assignable to `tuple[int, *tuple[int, ...]]`
31 v3: tuple[int]
32 v3 = t2 # E
[invalid-assignment] Object of type `tuple[int, *tuple[int, ...]]` is not assignable to `tuple[int]`
33 v3 = t3 # E
[invalid-assignment] Object of type `tuple[int, ...]` is not assignable to `tuple[int]`
36# > The type ``tuple[Any, ...]`` is bidirectionally compatible with any tuple::
39def func3(t1: tuple[int], t2: tuple[int, ...], t3: tuple[Any, ...]):
40 v1: tuple[int, ...] = t1 # OK
41 v2: tuple[Any, ...] = t1 # OK
43 v3: tuple[int] = t2 # E
[invalid-assignment] Object of type `tuple[int, ...]` is not assignable to `tuple[int]`
44 v4: tuple[Any, ...] = t2 # OK
46 v5: tuple[float, float] = t3 # OK
47 v6: tuple[int, *tuple[str, ...]] = t3 # OK
50from missing_module import SomeType # type: ignore
53def func4(
54 untyped_iter: Iterable[Any],
55 some_type_tuple: tuple[SomeType, ...],
56 any_tuple: tuple[Any, ...],
57 int_tuple: tuple[int, ...],
58):
59 a: tuple[int, int] = tuple(untyped_iter) # OK
60 b: tuple[int, int] = some_type_tuple # OK
61 c: tuple[int, int] = any_tuple # OK
62 d: tuple[int, int] = int_tuple # E
[invalid-assignment] Object of type `tuple[int, ...]` is not assignable to `tuple[int, int]`
65# > The length of a tuple at runtime is immutable, so it is safe for type
66# > checkers to use length checks to narrow the type of a tuple
68# NOTE: This type narrowing functionality is optional, not mandated.
70Func5Input: TypeAlias = tuple[int] | tuple[str, str] | tuple[int, *tuple[str, ...], int]
72def func5(val: Func5Input):
73 if len(val) == 1:
74 # Type can be narrowed to tuple[int].
75 assert_type(val, tuple[int]) # E[func5_1]
Tag 'func5_1' [type-assertion-failure] Type `tuple[int]` does not match asserted type `tuple[int] | tuple[str, str] | tuple[int, *tuple[str, ...], int]`
76 assert_type(val, Func5Input) # E[func5_1]
78 if len(val) == 2:
79 # Type can be narrowed to tuple[str, str] | tuple[int, int].
80 assert_type(val, tuple[str, str] | tuple[int, int]) # E[func5_2]
Tag 'func5_2' [type-assertion-failure] Type `tuple[str, str] | tuple[int, int]` does not match asserted type `tuple[int] | tuple[str, str] | tuple[int, *tuple[str, ...], int]`
81 assert_type(val, Func5Input) # E[func5_2]
83 if len(val) == 3:
84 # Type can be narrowed to tuple[int, str, int].
85 assert_type(val, tuple[int, str, int]) # E[func5_3]
Tag 'func5_3' [type-assertion-failure] Type `tuple[int, str, int]` does not match asserted type `tuple[int] | tuple[str, str] | tuple[int, *tuple[str, ...], int]`
86 assert_type(val, Func5Input) # E[func5_3]
89# > This property may also be used to safely narrow tuple types within a match
90# > statement that uses sequence patterns.
92# NOTE: This type narrowing functionality is optional, not mandated.
94Func6Input: TypeAlias = tuple[int] | tuple[str, str] | tuple[int, *tuple[str, ...], int]
97def func6(val: Func6Input):
98 match val:
99 case (x,):
100 # Type may be narrowed to tuple[int].
101 assert_type(val, tuple[int]) # E[func6_1]
Tag 'func6_1' [type-assertion-failure] Type `tuple[int]` does not match asserted type `tuple[int] | tuple[str, str] | tuple[int, *tuple[str, ...], int]`
102 assert_type(val, Func6Input) # E[func6_1]
104 case (x, y):
105 # Type may be narrowed to tuple[str, str] | tuple[int, int].
106 assert_type(val, tuple[str, str] | tuple[int, int]) # E[func6_2]
Tag 'func6_2' [type-assertion-failure] Type `tuple[str, str] | tuple[int, int]` does not match asserted type `tuple[int] | tuple[str, str] | tuple[int, *tuple[str, ...], int]`
107 assert_type(val, Func6Input) # E[func6_2]
109 case (x, y, z):
110 # Type may be narrowed to tuple[int, str, int].
111 assert_type(val, tuple[int, str, int]) # E[func6_3]
Tag 'func6_3' [type-assertion-failure] Type `tuple[int, str, int]` does not match asserted type `tuple[int] | tuple[str, str] | tuple[int, *tuple[str, ...], int]`
112 assert_type(val, Func6Input) # E[func6_3]
115# > Type checkers may safely use this equivalency rule (tuple expansion)
116# > when narrowing tuple types
118# NOTE: This type narrowing functionality is optional, not mandated.
120Func7Input: TypeAlias = tuple[int | str, int | str]
123def func7(subj: Func7Input):
124 match subj:
125 case x, str():
126 assert_type(subj, tuple[int | str, str]) # E[func7_1]
Tag 'func7_1' [type-assertion-failure] Type `tuple[int | str, str]` does not match asserted type `tuple[int | str, int | str]`
127 assert_type(subj, Func7Input) # E[func7_1]
128 case y:
129 assert_type(subj, tuple[int | str, int]) # E[func7_2]
Tag 'func7_2' [type-assertion-failure] Type `tuple[int | str, int]` does not match asserted type `tuple[int | str, int | str]`
130 assert_type(subj, Func7Input) # E[func7_2]
133# > The tuple class derives from Sequence[T_co] where ``T_co`` is a covariant
134# (non-variadic) type variable. The specialized type of ``T_co`` should be
135# computed by a type checker as a a supertype of all element types.
137# > A zero-length tuple (``tuple[()]``) is a subtype of ``Sequence[Never]``.
139T = TypeVar("T")
142def test_seq(x: Sequence[T]) -> Sequence[T]:
143 return x
146def func8(
147 t1: tuple[complex, list[int]], t2: tuple[int, *tuple[str, ...]], t3: tuple[()]
148):
149 assert_type(
150 test_seq(t1), Sequence[complex | list[int]]
151 ) # Could be Sequence[object]
152 assert_type(test_seq(t2), Sequence[int | str]) # Could be Sequence[object]
153 assert_type(test_seq(t3), Sequence[Never])
156t1: tuple[int, *tuple[str]] = (1, "") # OK
157t1 = (1, "", "") # E
[invalid-assignment] Object of type `tuple[Literal[1], Literal[""], Literal[""]]` is not assignable to `tuple[int, str]`
159t2: tuple[int, *tuple[str, ...]] = (1,) # OK
160t2 = (1, "") # OK
161t2 = (1, "", "") # OK
162t2 = (1, 1, "") # E
[invalid-assignment] Object of type `tuple[Literal[1], Literal[1], Literal[""]]` is not assignable to `tuple[int, *tuple[str, ...]]`
163t2 = (1, "", 1) # E
[invalid-assignment] Object of type `tuple[Literal[1], Literal[""], Literal[1]]` is not assignable to `tuple[int, *tuple[str, ...]]`
166t3: tuple[int, *tuple[str, ...], int] = (1, 2) # OK
167t3 = (1, "", 2) # OK
168t3 = (1, "", "", 2) # OK
169t3 = (1, "", "") # E
[invalid-assignment] Object of type `tuple[Literal[1], Literal[""], Literal[""]]` is not assignable to `tuple[int, *tuple[str, ...], int]`
170t3 = (1, "", "", 1.2) # E
[invalid-assignment] Object of type `tuple[Literal[1], Literal[""], Literal[""], float]` is not assignable to `tuple[int, *tuple[str, ...], int]`
172t4: tuple[*tuple[str, ...], int] = (1,) # OK
173t4 = ("", 1) # OK
174t4 = ("", "", 1) # OK
175t4 = (1, "", 1) # E
[invalid-assignment] Object of type `tuple[Literal[1], Literal[""], Literal[1]]` is not assignable to `tuple[*tuple[str, ...], int]`
176t4 = ("", "", 1.2) # E
[invalid-assignment] Object of type `tuple[Literal[""], Literal[""], float]` is not assignable to `tuple[*tuple[str, ...], int]`
179def func9(a: tuple[str, str]):
180 t1: tuple[str, str, *tuple[int, ...]] = a # OK
181 t2: tuple[str, str, *tuple[int]] = a # E
[invalid-assignment] Object of type `tuple[str, str]` is not assignable to `tuple[str, str, int]`
182 t3: tuple[str, *tuple[str, ...]] = a # OK
183 t4: tuple[str, str, *tuple[str, ...]] = a # OK
184 t5: tuple[str, str, str, *tuple[str, ...]] = a # E
[invalid-assignment] Object of type `tuple[str, str]` is not assignable to `tuple[str, str, str, *tuple[str, ...]]`
185 t6: tuple[str, *tuple[int, ...], str] = a # OK
186 t7: tuple[*tuple[str, ...], str] = a # OK
187 t8: tuple[*tuple[str, ...], str] = a # OK
188 t9: tuple[*tuple[str, ...], str, str, str] = a # E
[invalid-assignment] Object of type `tuple[str, str]` is not assignable to `tuple[*tuple[str, ...], str, str, str]`