← Back to index

protocols_variance.py

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 0
FP: 0
FN: 9
Optional: 0 / 0
1"""
2Tests type variable variance inference for generic protocols.
3"""
4
5# Specification: https://typing.readthedocs.io/en/latest/spec/protocol.html#generic-protocols
6
7from typing import ParamSpec, Protocol, TypeVar
8
9T1 = TypeVar("T1")
10T2 = TypeVar("T2", bound=int)
11T3 = TypeVar("T3", bytes, str)
12T1_co = TypeVar("T1_co", covariant=True)
13T1_contra = TypeVar("T1_contra", contravariant=True)
14P = ParamSpec("P")
15R = TypeVar("R", covariant=True)
17# > Type checkers will warn if the inferred variance is different from the
18# > declared variance.
21class AnotherBox(Protocol[T1]): # E: T should be covariant
Expected a ty diagnostic for this line
22 def content(self) -> T1:
23 ...
26class Protocol1(Protocol[T1, T2, T3]): # OK
27 def m1(self, p0: T1, p1: T2, p2: T3) -> T1 | T2:
28 ...
30 def m2(self) -> T1:
31 ...
33 def m3(self) -> T2:
34 ...
36 def m4(self) -> T3:
37 ...
40class Protocol2(Protocol[T1, T2, T3]): # E: T3 should be contravariant
Expected a ty diagnostic for this line
41 def m1(self, p0: T1, p1: T2, p2: T3) -> T1:
42 ...
44 def m2(self) -> T1:
45 ...
47 def m3(self) -> T2:
48 ...
51class Protocol3(Protocol[T1_co]):
52 def m1(self) -> None:
53 pass
56class Protocol4(Protocol[T1]): # E: T1 should be contravariant
Expected a ty diagnostic for this line
57 def m1(self, p0: T1) -> None:
58 ...
61class Protocol5(Protocol[T1_co]): # E[covariant_in_input+]
Expected a ty diagnostic for this line (tag 'covariant_in_input')
62 def m1(self, p0: T1_co) -> None: # E[covariant_in_input+]
Expected a ty diagnostic for this line (tag 'covariant_in_input')
63 ...
66class Protocol6(Protocol[T1]): # E: T1 should be covariant
Expected a ty diagnostic for this line
67 def m1(self) -> T1:
68 ...
71class Protocol7(Protocol[T1_contra]): # E[contravariant_in_output+]
Expected a ty diagnostic for this line (tag 'contravariant_in_output')
72 def m1(self) -> T1_contra: # E[contravariant_in_output+]
Expected a ty diagnostic for this line (tag 'contravariant_in_output')
73 ...
76class Protocol8(Protocol[T1]): # OK
77 def m1(self) -> T1:
78 ...
80 def m2(self, p1: T1) -> None:
81 pass
84class Callback(Protocol[P, R]): # OK
85 def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
86 ...
89class Protocol9(Protocol[T1_co]): # OK
90 @property
91 def prop1(self) -> T1_co:
92 ...
95class Protocol10(Protocol[T1_co]): # OK
96 def m1(self) -> type[T1_co]:
97 ...
100class Protocol11(Protocol[T1]): # OK
101 x: T1 | None
104class Protocol12(Protocol[T1]): # E: T1 should be covariant
Expected a ty diagnostic for this line
105 # __init__ method is exempt from variance calculations.
106 def __init__(self, x: T1) -> None:
107 ...
110class Protocol13(Protocol[T1_contra]): # OK
111 def m1(self: "Protocol13[T1_contra]", x: T1_contra) -> None:
112 ...
114 @classmethod
115 def m2(cls: "type[Protocol13[T1_contra]]") -> None:
116 ...
119class Protocol14(Protocol[T1]): # OK
120 def m1(self) -> list[T1]:
121 ...