← Back to index

generics_syntax_infer_variance.py

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 16
FP: 7
FN: 2
Optional: 0 / 0
1"""
2Tests the handling of "infer_variance" parameter for TypeVar.
3"""
4
5# Specification: https://peps.python.org/pep-0695/#auto-variance-for-typevar
6
7from typing import Final, Generic, Iterator, overload, Sequence, TypeVar
8from dataclasses import dataclass
9
11T = TypeVar("T", infer_variance=True)
12K = TypeVar("K", infer_variance=True)
13V = TypeVar("V", infer_variance=True)
15S1 = TypeVar("S1", covariant=True, infer_variance=True) # E: cannot use covariant with infer_variance
Expected a ty diagnostic for this line
17S2 = TypeVar("S2", contravariant=True, infer_variance=True) # E: cannot use contravariant with infer_variance
Expected a ty diagnostic for this line
20class ShouldBeCovariant1(Generic[T]):
21 def __getitem__(self, index: int) -> T:
22 raise NotImplementedError
24 def __iter__(self) -> Iterator[T]:
25 raise NotImplementedError
28vco1_1: ShouldBeCovariant1[float] = ShouldBeCovariant1[int]() # OK
Unexpected error [invalid-assignment] Object of type `ShouldBeCovariant1[int]` is not assignable to `ShouldBeCovariant1[int | float]`
29vco1_2: ShouldBeCovariant1[int] = ShouldBeCovariant1[float]() # E
[invalid-assignment] Object of type `ShouldBeCovariant1[int | float]` is not assignable to `ShouldBeCovariant1[int]`
32class ShouldBeCovariant2(Sequence[T]):
33 @overload
34 def __getitem__(self, index: int) -> T:
35 ...
36 @overload
37 def __getitem__(self, index: slice) -> Sequence[T]:
38 ...
39 def __getitem__(self, index: int | slice) -> T | Sequence[T]:
40 raise NotImplementedError
42 def __len__(self) -> int:
43 raise NotImplementedError
46vco2_1: ShouldBeCovariant2[float] = ShouldBeCovariant2[int]() # OK
Unexpected error [invalid-assignment] Object of type `ShouldBeCovariant2[int]` is not assignable to `ShouldBeCovariant2[int | float]`
47vco2_2: ShouldBeCovariant2[int] = ShouldBeCovariant2[float]() # E
[invalid-assignment] Object of type `ShouldBeCovariant2[int | float]` is not assignable to `ShouldBeCovariant2[int]`
50class ShouldBeCovariant3(Generic[T]):
51 def method1(self) -> "ShouldBeCovariant2[T]":
52 raise NotImplementedError
55vco3_1: ShouldBeCovariant3[float] = ShouldBeCovariant3[int]() # OK
Unexpected error [invalid-assignment] Object of type `ShouldBeCovariant3[int]` is not assignable to `ShouldBeCovariant3[int | float]`
56vco3_2: ShouldBeCovariant3[int] = ShouldBeCovariant3[float]() # E
[invalid-assignment] Object of type `ShouldBeCovariant3[int | float]` is not assignable to `ShouldBeCovariant3[int]`
59@dataclass(frozen=True)
60class ShouldBeCovariant4(Generic[T]):
61 x: T
64# This test is problematic as of Python 3.13 because of the
65# newly synthesized "__replace__" method, which causes the type
66# variable to be inferred as invariant rather than covariant.
67# See https://github.com/python/mypy/issues/17623#issuecomment-2266312738
68# for details. Until we sort this out, we'll leave this test commented
69# out.
71# vo4_1: ShouldBeCovariant4[float] = ShouldBeCovariant4[int](1) # OK
72# vo4_4: ShouldBeCovariant4[int] = ShouldBeCovariant4[float](1.0) # E
75class ShouldBeCovariant5(Generic[T]):
76 def __init__(self, x: T) -> None:
77 self._x = x
79 @property
80 def x(self) -> T:
81 return self._x
84vo5_1: ShouldBeCovariant5[float] = ShouldBeCovariant5[int](1) # OK
Unexpected error [invalid-assignment] Object of type `ShouldBeCovariant5[int]` is not assignable to `ShouldBeCovariant5[int | float]`
85vo5_2: ShouldBeCovariant5[int] = ShouldBeCovariant5[float](1.0) # E
[invalid-assignment] Object of type `ShouldBeCovariant5[int | float]` is not assignable to `ShouldBeCovariant5[int]`
88class ShouldBeCovariant6(Generic[T]):
89 x: Final[T]
91 def __init__(self, value: T):
92 self.x = value
Unexpected error [invalid-assignment] Cannot assign to final attribute `x` on type `Self@__init__`
95vo6_1: ShouldBeCovariant6[float] = ShouldBeCovariant6[int](1) # OK
Unexpected error [invalid-assignment] Object of type `ShouldBeCovariant6[int]` is not assignable to `ShouldBeCovariant6[int | float]`
96vo6_2: ShouldBeCovariant6[int] = ShouldBeCovariant6[float](1.0) # E
[invalid-assignment] Object of type `ShouldBeCovariant6[int | float]` is not assignable to `ShouldBeCovariant6[int]`
99class ShouldBeInvariant1(Generic[T]):
100 def __init__(self, value: T) -> None:
101 self._value = value
103 @property
104 def value(self) -> T:
105 return self._value
107 @value.setter
108 def value(self, value: T):
109 self._value = value
112vinv1_1: ShouldBeInvariant1[float] = ShouldBeInvariant1[int](1) # E
[invalid-assignment] Object of type `ShouldBeInvariant1[int]` is not assignable to `ShouldBeInvariant1[int | float]`
113vinv1_2: ShouldBeInvariant1[int] = ShouldBeInvariant1[float](1.1) # E
[invalid-assignment] Object of type `ShouldBeInvariant1[int | float]` is not assignable to `ShouldBeInvariant1[int]`
116class ShouldBeInvariant2(Generic[T]):
117 def __init__(self, value: T) -> None:
118 self._value = value
120 def get_value(self) -> T:
121 return self._value
123 def set_value(self, value: T):
124 self._value = value
127vinv2_1: ShouldBeInvariant2[float] = ShouldBeInvariant2[int](1) # E
[invalid-assignment] Object of type `ShouldBeInvariant2[int]` is not assignable to `ShouldBeInvariant2[int | float]`
128vinv2_2: ShouldBeInvariant2[int] = ShouldBeInvariant2[float](1.1) # E
[invalid-assignment] Object of type `ShouldBeInvariant2[int | float]` is not assignable to `ShouldBeInvariant2[int]`
131class ShouldBeInvariant3(dict[K, V]):
132 pass
135vinv3_1: ShouldBeInvariant3[float, str] = ShouldBeInvariant3[int, str]() # E
[invalid-assignment] Object of type `ShouldBeInvariant3[int, str]` is not assignable to `ShouldBeInvariant3[int | float, str]`
136vinv3_2: ShouldBeInvariant3[int, str] = ShouldBeInvariant3[float, str]() # E
[invalid-assignment] Object of type `ShouldBeInvariant3[int | float, str]` is not assignable to `ShouldBeInvariant3[int, str]`
137vinv3_3: ShouldBeInvariant3[str, float] = ShouldBeInvariant3[str, int]() # E
[invalid-assignment] Object of type `ShouldBeInvariant3[str, int]` is not assignable to `ShouldBeInvariant3[str, int | float]`
138vinv3_4: ShouldBeInvariant3[str, int] = ShouldBeInvariant3[str, float]() # E
[invalid-assignment] Object of type `ShouldBeInvariant3[str, int | float]` is not assignable to `ShouldBeInvariant3[str, int]`
141@dataclass
142class ShouldBeInvariant4[T]:
143 x: T
146vinv4_1: ShouldBeInvariant4[float] = ShouldBeInvariant4[int](1) # E
[invalid-assignment] Object of type `ShouldBeInvariant4[int]` is not assignable to `ShouldBeInvariant4[int | float]`
149class ShouldBeInvariant5[T]:
150 def __init__(self, x: T) -> None:
151 self.x = x
154vinv5_1: ShouldBeInvariant5[float] = ShouldBeInvariant5[int](1) # E
[invalid-assignment] Object of type `ShouldBeInvariant5[int]` is not assignable to `ShouldBeInvariant5[int | float]`
157class ShouldBeContravariant1(Generic[T]):
158 def __init__(self, value: T) -> None:
159 pass
161 def set_value(self, value: T):
162 pass
165vcontra1_1: ShouldBeContravariant1[float] = ShouldBeContravariant1[int](1) # E
[invalid-assignment] Object of type `ShouldBeContravariant1[int]` is not assignable to `ShouldBeContravariant1[int | float]`
166vcontra1_2: ShouldBeContravariant1[int] = ShouldBeContravariant1[float](1.2) # OK
Unexpected error [invalid-assignment] Object of type `ShouldBeContravariant1[int | float]` is not assignable to `ShouldBeContravariant1[int]`