2Tests type compatibility rules for tuples.
5# Specification: https://typing.readthedocs.io/en/latest/spec/tuples.html#type-compatibility-rules
7# > Because tuple contents are immutable, the element types of a tuple are covariant.
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, ...]):
27 v2: tuple[int, *tuple[int, ...]]
[invalid-assignment] Object of type `tuple[int, ...]` is not assignable to `tuple[int, *tuple[int, ...]]`
[invalid-assignment] Object of type `tuple[int, *tuple[int, ...]]` is not assignable to `tuple[int]`
[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
54 untyped_iter: Iterable[Any],
55 some_type_tuple: tuple[SomeType, ...],
56 any_tuple: tuple[Any, ...],
57 int_tuple: tuple[int, ...],
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):
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]
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]
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):
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]
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]
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):
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]
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]``.
142def test_seq(x: Sequence[T]) -> Sequence[T]:
147 t1: tuple[complex, list[int]], t2: tuple[int, *tuple[str, ...]], t3: tuple[()]
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
[invalid-assignment] Object of type `tuple[Literal[1], Literal[""], Literal[""]]` is not assignable to `tuple[int, str]`
159t2: tuple[int, *tuple[str, ...]] = (1,) # OK
[invalid-assignment] Object of type `tuple[Literal[1], Literal[1], Literal[""]]` is not assignable to `tuple[int, *tuple[str, ...]]`
[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
168t3 = (1, "", "", 2) # OK
[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
[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]`