2Tests the handling of class objects as implementations of a protocol.
5# Specification: https://typing.readthedocs.io/en/latest/spec/protocol.html#type-and-class-objects-vs-protocols
7# > Variables and parameters annotated with Type[Proto] accept only concrete
8# (non-protocol) subtypes of Proto.
10from abc import abstractmethod
11from typing import Any, ClassVar, Protocol
16 def meth(self) -> int:
21 def meth(self) -> int:
25def fun(cls: type[Proto]) -> int:
26 return cls().meth() # OK
Expected a ty diagnostic for this line
Expected a ty diagnostic for this line
39# > A class object is considered an implementation of a protocol if accessing
40# > all members on it results in types compatible with the protocol members.
43class ProtoA1(Protocol):
44 def method1(self, x: int) -> int:
48class ProtoA2(Protocol):
49 def method1(_self, self: Any, x: int) -> int:
54 def method1(self, x: int) -> int:
58pa1: ProtoA1 = ConcreteA # E: signatures don't match
[invalid-assignment] Object of type `<class 'ConcreteA'>` is not assignable to `ProtoA1`
59pa2: ProtoA2 = ConcreteA # OK
Unexpected error
[invalid-assignment] Object of type `<class 'ConcreteA'>` is not assignable to `ProtoA2`
62class ProtoB1(Protocol):
64 def prop1(self) -> int:
70 def prop1(self) -> int:
74pb1: ProtoB1 = ConcreteB # E
Expected a ty diagnostic for this line
77class ProtoC1(Protocol):
81class ProtoC2(Protocol):
86 attr1: ClassVar[int] = 1
96 def __init__(self, attr1: int) -> None:
100class ConcreteC3(metaclass=CMeta):
104pc1: ProtoC1 = ConcreteC1 # E
Expected a ty diagnostic for this line
105pc2: ProtoC2 = ConcreteC1 # OK
106pc3: ProtoC1 = ConcreteC2 # E
Expected a ty diagnostic for this line
107pc4: ProtoC2 = ConcreteC2 # E
Expected a ty diagnostic for this line
108pc5: ProtoC1 = ConcreteC3 # E
Expected a ty diagnostic for this line
109pc6: ProtoC2 = ConcreteC3 # OK