-- Simple protocol types -- --------------------- [case testCannotInstantiateProtocol] from typing import Protocol class P(Protocol): def meth(self) -> None: pass P() # E: Cannot instantiate protocol class "P" [case testSimpleProtocolOneMethod] from typing import Protocol class P(Protocol): def meth(self) -> None: pass class B: pass class C: def meth(self) -> None: pass x: P def fun(x: P) -> None: x.meth() x.meth(x) # E: Too many arguments for "meth" of "P" x.bad # E: "P" has no attribute "bad" x = C() x = B() # E: Incompatible types in assignment (expression has type "B", variable has type "P") fun(C()) fun(B()) # E: Argument 1 to "fun" has incompatible type "B"; expected "P" def fun2() -> P: return C() def fun3() -> P: return B() # E: Incompatible return value type (got "B", expected "P") [case testProtocolAttrAccessDecoratedGetAttrDunder] from typing import Any, Protocol, Callable def typed_decorator(fun: Callable) -> Callable[[Any, str], str]: pass def untyped_decorator(fun): pass class P(Protocol): @property def x(self) -> int: pass class A: @untyped_decorator def __getattr__(self, key: str) -> int: pass class B: @typed_decorator def __getattr__(self, key: str) -> int: pass class C: def __getattr__(self, key: str) -> int: pass def fun(x: P) -> None: pass a: A reveal_type(a.x) fun(a) b: B reveal_type(b.x) fun(b) c: C reveal_type(c.x) fun(c) [out] main:32: note: Revealed type is "Any" main:36: note: Revealed type is "builtins.str" main:37: error: Argument 1 to "fun" has incompatible type "B"; expected "P" main:37: note: Following member(s) of "B" have conflicts: main:37: note: x: expected "int", got "str" main:40: note: Revealed type is "builtins.int" [builtins fixtures/bool.pyi] [case testSimpleProtocolOneAbstractMethod] from typing import Protocol from abc import abstractmethod class P(Protocol): @abstractmethod def meth(self) -> None: pass class B: pass class C: def meth(self) -> None: pass class D(B): def meth(self) -> None: pass x: P def fun(x: P) -> None: x.meth() x.meth(x) # E: Too many arguments for "meth" of "P" x.bad # E: "P" has no attribute "bad" x = C() x = D() x = B() # E: Incompatible types in assignment (expression has type "B", variable has type "P") fun(C()) fun(D()) fun(B()) # E: Argument 1 to "fun" has incompatible type "B"; expected "P" fun(x) [case testProtocolMethodBodies] from typing import Protocol, List class P(Protocol): def meth(self) -> int: return 'no way' # E: Incompatible return value type (got "str", expected "int") # explicit ellipsis is OK in protocol methods class P2(Protocol): def meth2(self) -> List[int]: ... [builtins fixtures/list.pyi] [case testSimpleProtocolOneMethodOverride] from typing import Protocol, Union class P(Protocol): def meth(self) -> Union[int, str]: pass class SubP(P, Protocol): def meth(self) -> int: pass class B: pass class C: def meth(self) -> int: pass z: P x: SubP def fun(x: SubP) -> str: x.bad # E: "SubP" has no attribute "bad" return x.meth() # E: Incompatible return value type (got "int", expected "str") z = x x = C() x = B() # E: Incompatible types in assignment (expression has type "B", variable has type "SubP") reveal_type(fun(C())) # N: Revealed type is "builtins.str" fun(B()) # E: Argument 1 to "fun" has incompatible type "B"; expected "SubP" [case testSimpleProtocolTwoMethodsMerge] from typing import Protocol class P1(Protocol): def meth1(self) -> int: pass class P2(Protocol): def meth2(self) -> str: pass class P(P1, P2, Protocol): pass class B: pass class C1: def meth1(self) -> int: pass class C2(C1): def meth2(self) -> str: pass class C: def meth1(self) -> int: pass def meth2(self) -> str: pass class AnotherP(Protocol): def meth1(self) -> int: pass def meth2(self) -> str: pass x: P reveal_type(x.meth1()) # N: Revealed type is "builtins.int" reveal_type(x.meth2()) # N: Revealed type is "builtins.str" c: C c1: C1 c2: C2 y: AnotherP if int(): x = c if int(): x = B() # E: Incompatible types in assignment (expression has type "B", variable has type "P") if int(): x = c1 # E: Incompatible types in assignment (expression has type "C1", variable has type "P") \ # N: "C1" is missing following "P" protocol member: \ # N: meth2 if int(): x = c2 if int(): x = y if int(): y = x [case testSimpleProtocolTwoMethodsExtend] from typing import Protocol class P1(Protocol): def meth1(self) -> int: pass class P2(P1, Protocol): def meth2(self) -> str: pass class Cbad: def meth1(self) -> int: pass class C: def meth1(self) -> int: pass def meth2(self) -> str: pass x: P2 reveal_type(x.meth1()) # N: Revealed type is "builtins.int" reveal_type(x.meth2()) # N: Revealed type is "builtins.str" if int(): x = C() # OK if int(): x = Cbad() # E: Incompatible types in assignment (expression has type "Cbad", variable has type "P2") \ # N: "Cbad" is missing following "P2" protocol member: \ # N: meth2 [case testProtocolMethodVsAttributeErrors] from typing import Protocol class P(Protocol): def meth(self) -> int: pass class C: meth: int x: P = C() # E: Incompatible types in assignment (expression has type "C", variable has type "P") \ # N: Following member(s) of "C" have conflicts: \ # N: meth: expected "Callable[[], int]", got "int" [case testProtocolMethodVsAttributeErrors2] from typing import Protocol class P(Protocol): @property def meth(self) -> int: pass class C: def meth(self) -> int: pass x: P = C() # E: Incompatible types in assignment (expression has type "C", variable has type "P") \ # N: Following member(s) of "C" have conflicts: \ # N: meth: expected "int", got "Callable[[], int]" [builtins fixtures/property.pyi] [case testCannotAssignNormalToProtocol] from typing import Protocol class P(Protocol): def meth(self) -> int: pass class C: def meth(self) -> int: pass x: C y: P x = y # E: Incompatible types in assignment (expression has type "P", variable has type "C") [case testIndependentProtocolSubtyping] from typing import Protocol class P1(Protocol): def meth(self) -> int: pass class P2(Protocol): def meth(self) -> int: pass x1: P1 x2: P2 x1 = x2 x2 = x1 def f1(x: P1) -> None: pass def f2(x: P2) -> None: pass f1(x2) f2(x1) [case testNoneDisablesProtocolImplementation] from typing import Protocol class MyHashable(Protocol): def __my_hash__(self) -> int: return 0 class C: __my_hash__ = None var: MyHashable = C() # E: Incompatible types in assignment (expression has type "C", variable has type "MyHashable") \ # N: Following member(s) of "C" have conflicts: \ # N: __my_hash__: expected "Callable[[], int]", got "None" [case testNoneDisablesProtocolSubclassingWithStrictOptional] from typing import Protocol class MyHashable(Protocol): def __my_hash__(self) -> int: return 0 class C(MyHashable): __my_hash__ = None # E: Incompatible types in assignment \ (expression has type "None", base class "MyHashable" defined the type as "Callable[[], int]") [case testProtocolsWithNoneAndStrictOptional] from typing import Protocol class P(Protocol): x = 0 # type: int class C: x = None x: P = C() # Error! def f(x: P) -> None: pass f(C()) # Error! [out] main:8: error: Incompatible types in assignment (expression has type "C", variable has type "P") main:8: note: Following member(s) of "C" have conflicts: main:8: note: x: expected "int", got "None" main:10: error: Argument 1 to "f" has incompatible type "C"; expected "P" main:10: note: Following member(s) of "C" have conflicts: main:10: note: x: expected "int", got "None" -- Semanal errors in protocol types -- -------------------------------- [case testBasicSemanalErrorsInProtocols] from typing import Protocol, Generic, TypeVar, Iterable T = TypeVar('T', covariant=True) S = TypeVar('S', covariant=True) class P1(Protocol[T, T]): # E: Duplicate type variables in Generic[...] or Protocol[...] def meth(self) -> T: pass class P2(Protocol[T], Protocol[S]): # E: Only single Generic[...] or Protocol[...] can be in bases def meth(self) -> T: pass class P3(Protocol[T], Generic[S]): # E: Only single Generic[...] or Protocol[...] can be in bases def meth(self) -> T: pass class P4(Protocol[T]): attr: Iterable[S] # E: Type variable "__main__.S" is unbound \ # N: (Hint: Use "Generic[S]" or "Protocol[S]" base class to bind "S" inside a class) \ # N: (Hint: Use "S" in function signature to bind "S" inside a function) class P5(Iterable[S], Protocol[T]): # E: If Generic[...] or Protocol[...] is present it should list all type variables def meth(self) -> T: pass [case testProhibitSelfDefinitionInProtocols] from typing import Protocol class P(Protocol): def __init__(self, a: int) -> None: self.a = a # E: Protocol members cannot be defined via assignment to self \ # E: "P" has no attribute "a" class B: pass class C: def __init__(self, a: int) -> None: pass x: P x = B() # The above has an incompatible __init__, but mypy ignores this for nominal subtypes? x = C(1) class P2(Protocol): a: int def __init__(self) -> None: self.a = 1 class B2(P2): a: int x2: P2 = B2() # OK [case testProtocolAndRuntimeAreDefinedAlsoInTypingExtensions] from typing_extensions import Protocol, runtime_checkable @runtime_checkable class P(Protocol): def meth(self) -> int: pass x: object if isinstance(x, P): reveal_type(x) # N: Revealed type is "__main__.P" reveal_type(x.meth()) # N: Revealed type is "builtins.int" class C: def meth(self) -> int: pass z: P = C() [builtins fixtures/dict.pyi] [case testProtocolsCannotInheritFromNormal] from typing import Protocol class C: pass class D: pass class P(C, Protocol): # E: All bases of a protocol must be protocols attr: int class P2(P, D, Protocol): # E: All bases of a protocol must be protocols pass P2() # E: Cannot instantiate protocol class "P2" p: P2 reveal_type(p.attr) # N: Revealed type is "builtins.int" -- Generic protocol types -- ---------------------- [case testGenericMethodWithProtocol] from typing import Protocol, TypeVar T = TypeVar('T') class P(Protocol): def meth(self, x: int) -> int: return x class C: def meth(self, x: T) -> T: return x x: P = C() [case testGenericMethodWithProtocol2] from typing import Protocol, TypeVar T = TypeVar('T') class P(Protocol): def meth(self, x: T) -> T: return x class C: def meth(self, x: int) -> int: return x x: P = C() [out] main:11: error: Incompatible types in assignment (expression has type "C", variable has type "P") main:11: note: Following member(s) of "C" have conflicts: main:11: note: Expected: main:11: note: def [T] meth(self, x: T) -> T main:11: note: Got: main:11: note: def meth(self, x: int) -> int [case testAutomaticProtocolVariance] from typing import TypeVar, Protocol T = TypeVar('T') # In case of these errors we proceed with declared variance. class Pco(Protocol[T]): # E: Invariant type variable "T" used in protocol where covariant one is expected def meth(self) -> T: pass class Pcontra(Protocol[T]): # E: Invariant type variable "T" used in protocol where contravariant one is expected def meth(self, x: T) -> None: pass class Pinv(Protocol[T]): attr: T class A: pass class B(A): pass x1: Pco[B] y1: Pco[A] if int(): x1 = y1 # E: Incompatible types in assignment (expression has type "Pco[A]", variable has type "Pco[B]") if int(): y1 = x1 # E: Incompatible types in assignment (expression has type "Pco[B]", variable has type "Pco[A]") x2: Pcontra[B] y2: Pcontra[A] if int(): y2 = x2 # E: Incompatible types in assignment (expression has type "Pcontra[B]", variable has type "Pcontra[A]") if int(): x2 = y2 # E: Incompatible types in assignment (expression has type "Pcontra[A]", variable has type "Pcontra[B]") x3: Pinv[B] y3: Pinv[A] if int(): y3 = x3 # E: Incompatible types in assignment (expression has type "Pinv[B]", variable has type "Pinv[A]") if int(): x3 = y3 # E: Incompatible types in assignment (expression has type "Pinv[A]", variable has type "Pinv[B]") [case testProtocolVarianceWithCallableAndList] from typing import Protocol, TypeVar, Callable, List T = TypeVar('T') S = TypeVar('S') T_co = TypeVar('T_co', covariant=True) class P(Protocol[T, S]): # E: Invariant type variable "T" used in protocol where covariant one is expected \ # E: Invariant type variable "S" used in protocol where contravariant one is expected def fun(self, callback: Callable[[T], S]) -> None: pass class P2(Protocol[T_co]): # E: Covariant type variable "T_co" used in protocol where invariant one is expected lst: List[T_co] [builtins fixtures/list.pyi] [case testProtocolConstraintsUnsolvableWithSelfAnnotation1] # https://github.com/python/mypy/issues/11020 from typing import overload, Protocol, TypeVar I = TypeVar('I', covariant=True) V_contra = TypeVar('V_contra', contravariant=True) class C(Protocol[I]): def __abs__(self: 'C[V_contra]') -> 'C[V_contra]': ... @overload def f(self: 'C', q: int) -> int: ... @overload def f(self: 'C[float]', q: float) -> 'C[float]': ... [builtins fixtures/bool.pyi] [case testProtocolConstraintsUnsolvableWithSelfAnnotation2] # https://github.com/python/mypy/issues/11020 from typing import Protocol, TypeVar I = TypeVar('I', covariant=True) V = TypeVar('V') class C(Protocol[I]): def g(self: 'C[V]') -> 'C[V]': ... class D: pass x: C = D() # E: Incompatible types in assignment (expression has type "D", variable has type "C[Any]") [builtins fixtures/bool.pyi] [case testProtocolConstraintsUnsolvableWithSelfAnnotation3] # https://github.com/python/mypy/issues/11020 from typing import Protocol, TypeVar I = TypeVar('I', covariant=True) V = TypeVar('V') class C(Protocol[I]): def g(self: 'C[V]') -> 'C[V]': ... class D: def g(self) -> D: ... x: C = D() [builtins fixtures/bool.pyi] [case testProtocolVarianceWithUnusedVariable] from typing import Protocol, TypeVar T = TypeVar('T') class P(Protocol[T]): # E: Invariant type variable "T" used in protocol where covariant one is expected attr: int [case testGenericProtocolsInference1] from typing import Protocol, Sequence, TypeVar T = TypeVar('T', covariant=True) class Closeable(Protocol[T]): def close(self) -> T: pass class F: def close(self) -> int: return 0 def close(arg: Closeable[T]) -> T: return arg.close() def close_all(args: Sequence[Closeable[T]]) -> T: for arg in args: arg.close() return args[0].close() arg: Closeable[int] reveal_type(close(F())) # N: Revealed type is "builtins.int" reveal_type(close(arg)) # N: Revealed type is "builtins.int" reveal_type(close_all([F()])) # N: Revealed type is "builtins.int" reveal_type(close_all([arg])) # N: Revealed type is "builtins.int" [builtins fixtures/isinstancelist.pyi] [typing fixtures/typing-medium.pyi] [case testProtocolGenericInference2] from typing import Generic, TypeVar, Protocol T = TypeVar('T') S = TypeVar('S') class P(Protocol[T, S]): x: T y: S class C: x: int y: int def fun3(x: P[T, T]) -> T: pass reveal_type(fun3(C())) # N: Revealed type is "builtins.int" [case testProtocolGenericInferenceCovariant] from typing import Generic, TypeVar, Protocol T = TypeVar('T', covariant=True) S = TypeVar('S', covariant=True) U = TypeVar('U') class P(Protocol[T, S]): def x(self) -> T: pass def y(self) -> S: pass class C: def x(self) -> int: pass def y(self) -> int: pass def fun4(x: U, y: P[U, U]) -> U: pass reveal_type(fun4('a', C())) # N: Revealed type is "builtins.object" [case testUnrealtedGenericProtocolsEquivalent] from typing import TypeVar, Protocol T = TypeVar('T') class PA(Protocol[T]): attr: int def meth(self) -> T: pass def other(self, arg: T) -> None: pass class PB(Protocol[T]): # exactly the same as above attr: int def meth(self) -> T: pass def other(self, arg: T) -> None: pass def fun(x: PA[T]) -> PA[T]: y: PB[T] = x z: PB[T] return z x: PA y: PB x = y y = x xi: PA[int] yi: PB[int] xi = yi yi = xi [case testGenericSubProtocols] from typing import TypeVar, Protocol, Tuple, Generic T = TypeVar('T') S = TypeVar('S') class P1(Protocol[T]): attr1: T class P2(P1[T], Protocol[T, S]): attr2: Tuple[T, S] class C: def __init__(self, a1: int, a2: Tuple[int, int]) -> None: self.attr1 = a1 self.attr2 = a2 c: C var: P2[int, int] = c var2: P2[int, str] = c # E: Incompatible types in assignment (expression has type "C", variable has type "P2[int, str]") \ # N: Following member(s) of "C" have conflicts: \ # N: attr2: expected "tuple[int, str]", got "tuple[int, int]" class D(Generic[T]): attr1: T class E(D[T]): attr2: Tuple[T, T] def f(x: T) -> T: z: P2[T, T] = E[T]() y: P2[T, T] = D[T]() # E: Incompatible types in assignment (expression has type "D[T]", variable has type "P2[T, T]") \ # N: "D" is missing following "P2" protocol member: \ # N: attr2 return x [builtins fixtures/isinstancelist.pyi] [case testGenericSubProtocolsExtensionInvariant] from typing import TypeVar, Protocol, Union T = TypeVar('T') S = TypeVar('S') class P1(Protocol[T]): attr1: T class P2(Protocol[T]): attr2: T class P(P1[T], P2[S], Protocol): pass class C: attr1: int attr2: str class A: attr1: A class B: attr2: B class D(A, B): pass x: P = D() # Same as P[Any, Any] var: P[Union[int, P], Union[P, str]] = C() # E: Incompatible types in assignment (expression has type "C", variable has type "P[int | P[Any, Any], P[Any, Any] | str]") \ # N: Following member(s) of "C" have conflicts: \ # N: attr1: expected "int | P[Any, Any]", got "int" \ # N: attr2: expected "P[Any, Any] | str", got "str" [case testGenericSubProtocolsExtensionCovariant] from typing import TypeVar, Protocol, Union T = TypeVar('T', covariant=True) S = TypeVar('S', covariant=True) class P1(Protocol[T]): def attr1(self) -> T: pass class P2(Protocol[T]): def attr2(self) -> T: pass class P(P1[T], P2[S], Protocol): pass class C: def attr1(self) -> int: pass def attr2(self) -> str: pass var: P[Union[int, P], Union[P, str]] = C() # OK for covariant var2: P[Union[str, P], Union[P, int]] = C() [out] main:18: error: Incompatible types in assignment (expression has type "C", variable has type "P[str | P[Any, Any], P[Any, Any] | int]") main:18: note: Following member(s) of "C" have conflicts: main:18: note: Expected: main:18: note: def attr1(self) -> str | P[Any, Any] main:18: note: Got: main:18: note: def attr1(self) -> int main:18: note: Expected: main:18: note: def attr2(self) -> P[Any, Any] | int main:18: note: Got: main:18: note: def attr2(self) -> str [case testSelfTypesWithProtocolsBehaveAsWithNominal] from typing import Protocol, TypeVar T = TypeVar('T', bound='Shape') class Shape(Protocol): def combine(self: T, other: T) -> T: pass class NonProtoShape: def combine(self: T, other: T) -> T: pass class Circle: def combine(self: T, other: Shape) -> T: pass class Triangle: def combine(self, other: Shape) -> Shape: pass class Bad: def combine(self, other: int) -> str: pass def f(s: Shape) -> None: pass f(NonProtoShape()) f(Circle()) s: Shape if int(): s = Triangle() s = Bad() n2: NonProtoShape = s [out] main:26: error: Incompatible types in assignment (expression has type "Triangle", variable has type "Shape") main:26: note: Following member(s) of "Triangle" have conflicts: main:26: note: Expected: main:26: note: def combine(self, other: Triangle) -> Triangle main:26: note: Got: main:26: note: def combine(self, other: Shape) -> Shape main:27: error: Incompatible types in assignment (expression has type "Bad", variable has type "Shape") main:27: note: Following member(s) of "Bad" have conflicts: main:27: note: Expected: main:27: note: def combine(self, other: Bad) -> Bad main:27: note: Got: main:27: note: def combine(self, other: int) -> str main:29: error: Incompatible types in assignment (expression has type "Shape", variable has type "NonProtoShape") [case testBadVarianceInProtocols] from typing import Protocol, TypeVar T_co = TypeVar('T_co', covariant=True) T_contra = TypeVar('T_contra', contravariant=True) class Proto(Protocol[T_co, T_contra]): # type: ignore def one(self, x: T_co) -> None: # E: Cannot use a covariant type variable as a parameter pass def other(self) -> T_contra: # E: Cannot use a contravariant type variable as return type pass # Check that we respect user overrides of variance after the errors are reported x: Proto[int, float] y: Proto[float, int] y = x # OK [builtins fixtures/list.pyi] [case testSubtleBadVarianceInProtocols] from typing import Protocol, TypeVar, Iterable, Sequence T_co = TypeVar('T_co', covariant=True) T_contra = TypeVar('T_contra', contravariant=True) class Proto(Protocol[T_co, T_contra]): # E: Covariant type variable "T_co" used in protocol where contravariant one is expected \ # E: Contravariant type variable "T_contra" used in protocol where covariant one is expected def one(self, x: Iterable[T_co]) -> None: pass def other(self) -> Sequence[T_contra]: pass # Check that we respect user overrides of variance after the errors are reported x: Proto[int, float] y: Proto[float, int] y = x # OK [builtins fixtures/list.pyi] -- Recursive protocol types -- ------------------------ [case testRecursiveProtocols1] from typing import Protocol, Sequence, List, Generic, TypeVar T = TypeVar('T') class Traversable(Protocol): @property def leaves(self) -> Sequence[Traversable]: pass class C: pass class D(Generic[T]): leaves: List[D[T]] t: Traversable t = D[int]() # OK if int(): t = C() # E: Incompatible types in assignment (expression has type "C", variable has type "Traversable") [builtins fixtures/list.pyi] [typing fixtures/typing-medium.pyi] [case testRecursiveProtocols2] from typing import Protocol, TypeVar T = TypeVar('T') class Linked(Protocol[T]): val: T def next(self) -> Linked[T]: pass class L: val: int def next(self) -> L: pass def last(seq: Linked[T]) -> T: pass reveal_type(last(L())) # N: Revealed type is "builtins.int" [builtins fixtures/list.pyi] [case testRecursiveProtocolSubtleMismatch] from typing import Protocol, TypeVar T = TypeVar('T') class Linked(Protocol[T]): val: T def next(self) -> Linked[T]: pass class L: val: int def next(self) -> int: pass def last(seq: Linked[T]) -> T: pass last(L()) # E: Argument 1 to "last" has incompatible type "L"; expected "Linked[Never]" [case testMutuallyRecursiveProtocols] from typing import Protocol, Sequence, List class P1(Protocol): @property def attr1(self) -> Sequence[P2]: pass class P2(Protocol): @property def attr2(self) -> Sequence[P1]: pass class C: pass class A: attr1: List[B] class B: attr2: List[A] t: P1 t = A() # OK if int(): t = B() # E: Incompatible types in assignment (expression has type "B", variable has type "P1") t = C() # E: Incompatible types in assignment (expression has type "C", variable has type "P1") [builtins fixtures/list.pyi] [typing fixtures/typing-medium.pyi] [case testMutuallyRecursiveProtocolsTypesWithSubteMismatch] from typing import Protocol, Sequence, List class P1(Protocol): @property def attr1(self) -> Sequence[P2]: pass class P2(Protocol): @property def attr2(self) -> Sequence[P1]: pass class C: pass class A: attr1: List[B] class B: attr2: List[C] t: P1 t = A() # E: Incompatible types in assignment (expression has type "A", variable has type "P1") \ # N: Following member(s) of "A" have conflicts: \ # N: attr1: expected "Sequence[P2]", got "list[B]" [builtins fixtures/list.pyi] [case testMutuallyRecursiveProtocolsTypesWithSubteMismatchWriteable] from typing import Protocol class P1(Protocol): @property def attr1(self) -> P2: pass class P2(Protocol): attr2: P1 class A: attr1: B class B: attr2: A x: P1 = A() # E: Incompatible types in assignment (expression has type "A", variable has type "P1") \ # N: Following member(s) of "A" have conflicts: \ # N: attr1: expected "P2", got "B" [builtins fixtures/property.pyi] [case testTwoUncomfortablyIncompatibleProtocolsWithoutRunningInIssue9771] from typing import cast, Protocol, TypeVar, Union T1 = TypeVar("T1", covariant=True) T2 = TypeVar("T2") class P1(Protocol[T1]): def b(self) -> int: ... def a(self, other: "P1[T2]") -> T1: ... class P2(Protocol[T1]): def a(self, other: Union[P1[T2], "P2[T2]"]) -> T1: ... p11: P1 = cast(P1, 1) p12: P1 = cast(P2, 1) # E p21: P2 = cast(P1, 1) p22: P2 = cast(P2, 1) # E [out] main:14: error: Incompatible types in assignment (expression has type "P2[Any]", variable has type "P1[Any]") main:14: note: "P2" is missing following "P1" protocol member: main:14: note: b main:15: error: Incompatible types in assignment (expression has type "P1[Any]", variable has type "P2[Any]") main:15: note: Following member(s) of "P1[Any]" have conflicts: main:15: note: Expected: main:15: note: def [T2] a(self, other: P1[T2] | P2[T2]) -> Any main:15: note: Got: main:15: note: def [T2] a(self, other: P1[T2]) -> Any [case testHashable] from typing import Hashable, Iterable def f(x: Hashable) -> None: pass def g(x: Iterable[str]) -> None: f(x) # E: Argument 1 to "f" has incompatible type "Iterable[str]"; expected "Hashable" [builtins fixtures/object_hashable.pyi] [typing fixtures/typing-full.pyi] -- FIXME: things like this should work [case testWeirdRecursiveInferenceForProtocols-skip] from typing import Protocol, TypeVar, Generic T_co = TypeVar('T_co', covariant=True) T = TypeVar('T') class P(Protocol[T_co]): def meth(self) -> P[T_co]: pass class C(Generic[T]): def meth(self) -> C[T]: pass x: C[int] def f(arg: P[T]) -> T: pass reveal_type(f(x)) #E: Revealed type is "builtins.int" -- @property, @classmethod and @staticmethod in protocol types -- ----------------------------------------------------------- [case testCannotInstantiateAbstractMethodExplicitProtocolSubtypes] from typing import Protocol from abc import abstractmethod class P(Protocol): @abstractmethod def meth(self) -> int: pass class A(P): pass A() # E: Cannot instantiate abstract class "A" with abstract attribute "meth" class C(A): def meth(self) -> int: pass class C2(P): def meth(self) -> int: pass C() C2() [case testCannotInstantiateAbstractVariableExplicitProtocolSubtypes] from typing import Protocol class P(Protocol): attr: int class A(P): pass A() # E: Cannot instantiate abstract class "A" with abstract attribute "attr" class C(A): attr: int class C2(P): def __init__(self) -> None: self.attr = 1 C() C2() class P2(Protocol): attr: int = 1 class B(P2): pass B() # OK, attr is not abstract [case testClassVarsInProtocols] from typing import Protocol, ClassVar class PInst(Protocol): v: int class PClass(Protocol): v: ClassVar[int] class CInst: v: int class CClass: v: ClassVar[int] x: PInst y: PClass x = CInst() if int(): x = CClass() # E: Incompatible types in assignment (expression has type "CClass", variable has type "PInst") \ # N: Protocol member PInst.v expected instance variable, got class variable y = CClass() if int(): y = CInst() # E: Incompatible types in assignment (expression has type "CInst", variable has type "PClass") \ # N: Protocol member PClass.v expected class variable, got instance variable [case testPropertyInProtocols] from typing import Protocol class PP(Protocol): @property def attr(self) -> int: pass class P(Protocol): attr: int x: P y: PP y = x x2: P y2: PP x2 = y2 # E: Incompatible types in assignment (expression has type "PP", variable has type "P") \ # N: Protocol member P.attr expected settable variable, got read-only attribute [builtins fixtures/property.pyi] [case testClassVarProtocolImmutable] from typing import Protocol, ClassVar class P(Protocol): @property def x(self) -> int: ... class C: x: ClassVar[int] class Bad: x: ClassVar[str] x: P = C() y: P = Bad() # E: Incompatible types in assignment (expression has type "Bad", variable has type "P") \ # N: Following member(s) of "Bad" have conflicts: \ # N: x: expected "int", got "str" [builtins fixtures/property.pyi] [case testSettablePropertyInProtocols] from typing import Protocol class PPS(Protocol): @property def attr(self) -> int: pass @attr.setter def attr(self, x: int) -> None: pass class PP(Protocol): @property def attr(self) -> int: pass class P(Protocol): attr: int x: P z: PPS z = x x2: P z2: PPS x2 = z2 y3: PP z3: PPS y3 = z3 y4: PP z4: PPS z4 = y4 # E: Incompatible types in assignment (expression has type "PP", variable has type "PPS") \ # N: Protocol member PPS.attr expected settable variable, got read-only attribute [builtins fixtures/property.pyi] [case testFinalAttributeProtocol] from typing import Protocol, Final class P(Protocol): x: int class C: def __init__(self, x: int) -> None: self.x = x class CF: def __init__(self, x: int) -> None: self.x: Final = x x: P y: P x = C(42) y = CF(42) # E: Incompatible types in assignment (expression has type "CF", variable has type "P") \ # N: Protocol member P.x expected settable variable, got read-only attribute [case testStaticAndClassMethodsInProtocols] from typing import Protocol, Type, TypeVar class P(Protocol): def meth(self, x: int) -> str: pass class PC(Protocol): @classmethod def meth(cls, x: int) -> str: pass class B: @staticmethod def meth(x: int) -> str: pass class C: def meth(self, x: int) -> str: pass x: P x = C() if int(): x = B() y: PC y = B() if int(): y = C() \ # E: Incompatible types in assignment (expression has type "C", variable has type "PC") \ # N: Protocol member PC.meth expected class or static method [builtins fixtures/classmethod.pyi] [case testOverloadedMethodsInProtocols] from typing import overload, Protocol, Union, Optional class P(Protocol): @overload def f(self, x: int) -> Optional[int]: pass @overload def f(self, x: str) -> Optional[str]: pass class C: def f(self, x: Union[int, str]) -> None: pass class D: def f(self, x: int) -> None: pass x: P = C() if int(): x = D() [out] main:18: error: Incompatible types in assignment (expression has type "D", variable has type "P") main:18: note: Following member(s) of "D" have conflicts: main:18: note: Expected: main:18: note: @overload main:18: note: def f(self, x: int) -> int | None main:18: note: @overload main:18: note: def f(self, x: str) -> str | None main:18: note: Got: main:18: note: def f(self, x: int) -> None [case testCannotInstantiateProtocolWithOverloadedUnimplementedMethod] from typing import overload, Protocol class P(Protocol): @overload def meth(self, x: int) -> int: pass @overload def meth(self, x: str) -> bytes: pass class C(P): pass C() # E: Cannot instantiate abstract class "C" with abstract attribute "meth" [case testCanUseOverloadedImplementationsInProtocols] from typing import overload, Protocol, Union class P(Protocol): @overload def meth(self, x: int) -> int: pass @overload def meth(self, x: str) -> bool: pass def meth(self, x: Union[int, str]): if isinstance(x, int): return x return True class C(P): pass x = C() reveal_type(x.meth('hi')) # N: Revealed type is "builtins.bool" [builtins fixtures/isinstance.pyi] [case testProtocolsWithIdenticalOverloads] from typing import overload, Protocol class PA(Protocol): @overload def meth(self, x: int) -> int: pass @overload def meth(self, x: str) -> bytes: pass class PB(Protocol): # identical to above @overload def meth(self, x: int) -> int: pass @overload def meth(self, x: str) -> bytes: pass x: PA y: PB x = y def fun(arg: PB) -> None: pass fun(x) [case testProtocolsWithIncompatibleOverloads] from typing import overload, Protocol class PA(Protocol): @overload def meth(self, x: int) -> int: pass @overload def meth(self, x: str) -> bytes: pass class PB(Protocol): @overload def meth(self, x: int) -> int: pass @overload def meth(self, x: bytes) -> str: pass x: PA y: PB x = y [out] main:16: error: Incompatible types in assignment (expression has type "PB", variable has type "PA") main:16: note: Following member(s) of "PB" have conflicts: main:16: note: Expected: main:16: note: @overload main:16: note: def meth(self, x: int) -> int main:16: note: @overload main:16: note: def meth(self, x: str) -> bytes main:16: note: Got: main:16: note: @overload main:16: note: def meth(self, x: int) -> int main:16: note: @overload main:16: note: def meth(self, x: bytes) -> str [case testProtocolWithMultiContravariantTypeVarOverloads] from typing import overload, Protocol, TypeVar T1 = TypeVar("T1", contravariant=True) T2 = TypeVar("T2", contravariant=True) class A(Protocol[T1, T2]): @overload def method(self, a: T1) -> None: ... @overload def method(self, a: T2) -> None: ... -- Join and meet with protocol types -- --------------------------------- [case testJoinProtocolWithProtocol] from typing import Protocol class P(Protocol): attr: int class P2(Protocol): attr: int attr2: str x: P y: P2 l0 = [x, x] l1 = [y, y] l = [x, y] reveal_type(l0) # N: Revealed type is "builtins.list[__main__.P]" reveal_type(l1) # N: Revealed type is "builtins.list[__main__.P2]" reveal_type(l) # N: Revealed type is "builtins.list[__main__.P]" [builtins fixtures/list.pyi] [case testJoinOfIncompatibleProtocols] from typing import Protocol class P(Protocol): attr: int class P2(Protocol): attr2: str x: P y: P2 reveal_type([x, y]) # N: Revealed type is "builtins.list[builtins.object]" [builtins fixtures/list.pyi] [case testJoinProtocolWithNormal] from typing import Protocol class P(Protocol): attr: int class C: attr: int x: P y: C l = [x, y] reveal_type(l) # N: Revealed type is "builtins.list[__main__.P]" [builtins fixtures/list.pyi] [case testMeetProtocolWithProtocol] from typing import Protocol, Callable, TypeVar class P(Protocol): attr: int class P2(Protocol): attr: int attr2: str T = TypeVar('T') def f(x: Callable[[T, T], None]) -> T: pass def g(x: P, y: P2) -> None: pass reveal_type(f(g)) # N: Revealed type is "__main__.P2" [case testMeetOfIncompatibleProtocols] # flags: --no-strict-optional from typing import Protocol, Callable, TypeVar class P(Protocol): attr: int class P2(Protocol): attr2: str T = TypeVar('T') def f(x: Callable[[T, T], None]) -> T: pass def g(x: P, y: P2) -> None: pass x = f(g) reveal_type(x) # N: Revealed type is "None" [case testMeetProtocolWithNormal] from typing import Protocol, Callable, TypeVar class P(Protocol): attr: int class C: attr: int T = TypeVar('T') def f(x: Callable[[T, T], None]) -> T: pass def g(x: P, y: C) -> None: pass reveal_type(f(g)) # N: Revealed type is "__main__.C" [case testInferProtocolFromProtocol] from typing import Protocol, Sequence, TypeVar, Generic T = TypeVar('T') class Box(Protocol[T]): content: T class Linked(Protocol[T]): val: T def next(self) -> Linked[T]: pass class L(Generic[T]): val: Box[T] def next(self) -> L[T]: pass def last(seq: Linked[T]) -> T: pass reveal_type(last(L[int]())) # N: Revealed type is "__main__.Box[builtins.int]" reveal_type(last(L[str]()).content) # N: Revealed type is "builtins.str" [case testOverloadOnProtocol] from typing import overload, Protocol, runtime_checkable @runtime_checkable class P1(Protocol): attr1: int class P2(Protocol): attr2: str class C1: attr1: int class C2: attr2: str class C: pass @overload def f(x: P1) -> int: ... @overload def f(x: P2) -> str: ... def f(x: object) -> object: if isinstance(x, P1): return P1.attr1 if isinstance(x, P2): # E: Only @runtime_checkable protocols can be used with instance and class checks return P2.attr2 return None reveal_type(f(C1())) # N: Revealed type is "builtins.int" reveal_type(f(C2())) # N: Revealed type is "builtins.str" class D(C1, C2): pass # Compatible with both P1 and P2 # TODO: Should this return a union instead? reveal_type(f(D())) # N: Revealed type is "builtins.int" f(C()) # E: No overload variant of "f" matches argument type "C" \ # N: Possible overload variants: \ # N: def f(x: P1) -> int \ # N: def f(x: P2) -> str [builtins fixtures/isinstance.pyi] [typing fixtures/typing-full.pyi] -- Unions of protocol types -- ------------------------ [case testBasicUnionsOfProtocols] from typing import Union, Protocol class P1(Protocol): attr1: int class P2(Protocol): attr2: int class C1: attr1: int class C2: attr2: int class C(C1, C2): pass class B: ... x: Union[P1, P2] x = C1() if int(): x = C2() x = C() x = B() # E: Incompatible types in assignment (expression has type "B", variable has type "P1 | P2") [case testUnionsOfNormalClassesWithProtocols] from typing import Protocol, Union class P1(Protocol): attr1: int class P2(Protocol): attr2: int class C1: attr1: int class C2: attr2: int class C(C1, C2): pass class D1: attr1: int def f1(x: P1) -> None: pass def f2(x: P2) -> None: pass x: Union[C1, C2] y: Union[C1, D1] z: Union[C, D1] f1(x) # E: Argument 1 to "f1" has incompatible type "C1 | C2"; expected "P1" f1(y) f1(z) f2(x) # E: Argument 1 to "f2" has incompatible type "C1 | C2"; expected "P2" f2(z) # E: Argument 1 to "f2" has incompatible type "C | D1"; expected "P2" -- Type[] with protocol types -- -------------------------- [case testInstantiationProtocolInTypeForFunctions] from typing import Type, Protocol class P(Protocol): def m(self) -> None: return None class P1(Protocol): def m(self) -> None: pass class Pbad(Protocol): def mbad(self) -> int: pass class B(P): pass class C: def m(self) -> None: pass def f(cls: Type[P]) -> P: return cls() # OK def g() -> P: return P() # E: Cannot instantiate protocol class "P" f(P) # E: Only concrete class can be given where "type[P]" is expected f(B) # OK f(C) # OK x: Type[P1] xbad: Type[Pbad] f(x) # OK f(xbad) # E: Argument 1 to "f" has incompatible type "type[Pbad]"; expected "type[P]" [case testInstantiationProtocolInTypeForAliases] from typing import Type, Protocol class P(Protocol): def m(self) -> None: pass class C: def m(self) -> None: pass def f(cls: Type[P]) -> P: return cls() # OK Alias = P GoodAlias = C Alias() # E: Cannot instantiate protocol class "P" GoodAlias() f(Alias) # E: Only concrete class can be given where "type[P]" is expected f(GoodAlias) [case testInstantiationProtocolInTypeForVariables] # flags: --no-strict-optional from typing import Type, Protocol class P(Protocol): def m(self) -> None: return None class B(P): pass class C: def m(self) -> None: pass var: Type[P] var() if int(): var = P # E: Can only assign concrete classes to a variable of type "type[P]" var = B # OK var = C # OK var_old = None # type: Type[P] # Old syntax for variable annotations var_old() if int(): var_old = P # E: Can only assign concrete classes to a variable of type "type[P]" var_old = B # OK var_old = C # OK [case testInstantiationProtocolInTypeForClassMethods] from typing import Type, Protocol class Logger: @staticmethod def log(a: Type[C]): pass class C(Protocol): @classmethod def action(cls) -> None: cls() #OK for classmethods Logger.log(cls) #OK for classmethods [builtins fixtures/classmethod.pyi] -- isinstance() with @runtime_checkable protocols -- ---------------------------------------------- [case testSimpleRuntimeProtocolCheck] from typing import Protocol, runtime_checkable @runtime_checkable class C: # E: @runtime_checkable can only be used with protocol classes pass class P(Protocol): def meth(self) -> None: pass @runtime_checkable class R(Protocol): def meth(self) -> int: pass x: object if isinstance(x, P): # E: Only @runtime_checkable protocols can be used with instance and class checks reveal_type(x) # N: Revealed type is "__main__.P" if isinstance(x, R): reveal_type(x) # N: Revealed type is "__main__.R" reveal_type(x.meth()) # N: Revealed type is "builtins.int" [builtins fixtures/isinstance.pyi] [typing fixtures/typing-full.pyi] [case testRuntimeIterableProtocolCheck] from typing import Iterable, List, Union x: Union[int, List[str]] if isinstance(x, Iterable): reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" [builtins fixtures/isinstancelist.pyi] [typing fixtures/typing-full.pyi] [case testConcreteClassesInProtocolsIsInstance] # flags: --warn-unreachable from typing import Protocol, runtime_checkable, TypeVar, Generic T = TypeVar('T') @runtime_checkable class P1(Protocol): def meth1(self) -> int: pass @runtime_checkable class P2(Protocol): def meth2(self) -> int: pass @runtime_checkable class P(P1, P2, Protocol): pass class C1(Generic[T]): def meth1(self) -> T: pass class C2: def meth2(self) -> int: pass class C(C1[int], C2): pass c = C() if isinstance(c, P1): reveal_type(c) # N: Revealed type is "__main__.C" else: reveal_type(c) # E: Statement is unreachable if isinstance(c, P): reveal_type(c) # N: Revealed type is "__main__.C" else: reveal_type(c) # E: Statement is unreachable c1i: C1[int] if isinstance(c1i, P1): reveal_type(c1i) # N: Revealed type is "__main__.C1[builtins.int]" else: reveal_type(c1i) # E: Statement is unreachable if isinstance(c1i, P): reveal_type(c1i) # N: Revealed type is "__main__." else: reveal_type(c1i) # N: Revealed type is "__main__.C1[builtins.int]" c1s: C1[str] if isinstance(c1s, P1): # E: Subclass of "C1[str]" and "P1" cannot exist: would have incompatible method signatures reveal_type(c1s) # E: Statement is unreachable else: reveal_type(c1s) # N: Revealed type is "__main__.C1[builtins.str]" c2: C2 if isinstance(c2, P): reveal_type(c2) # N: Revealed type is "__main__." else: reveal_type(c2) # N: Revealed type is "__main__.C2" [builtins fixtures/isinstancelist.pyi] [typing fixtures/typing-full.pyi] [case testConcreteClassesUnionInProtocolsIsInstance] from typing import Protocol, runtime_checkable, TypeVar, Generic, Union T = TypeVar('T') @runtime_checkable class P1(Protocol): def meth1(self) -> int: pass @runtime_checkable class P2(Protocol): def meth2(self) -> int: pass class C1(Generic[T]): def meth1(self) -> T: pass class C2: def meth2(self) -> int: pass x: Union[C1[int], C2] if isinstance(x, P1): reveal_type(x) # N: Revealed type is "__main__.C1[builtins.int]" else: reveal_type(x) # N: Revealed type is "__main__.C2" if isinstance(x, P2): reveal_type(x) # N: Revealed type is "__main__.C2" else: reveal_type(x) # N: Revealed type is "__main__.C1[builtins.int]" [builtins fixtures/isinstancelist.pyi] [typing fixtures/typing-full.pyi] -- Non-Instances and protocol types (Callable vs __call__ etc.) -- ------------------------------------------------------------ [case testBasicTupleStructuralSubtyping] from typing import Tuple, TypeVar, Protocol T = TypeVar('T', covariant=True) class MyProto(Protocol[T]): def __len__(self) -> T: pass t: Tuple[int, str] def f(x: MyProto[int]) -> None: pass f(t) # OK y: MyProto[str] y = t # E: Incompatible types in assignment (expression has type "tuple[int, str]", variable has type "MyProto[str]") [builtins fixtures/isinstancelist.pyi] [case testBasicNamedTupleStructuralSubtyping] from typing import NamedTuple, TypeVar, Protocol T = TypeVar('T', covariant=True) S = TypeVar('S', covariant=True) class P(Protocol[T, S]): @property def x(self) -> T: pass @property def y(self) -> S: pass class N(NamedTuple): x: int y: str class N2(NamedTuple): x: int class N3(NamedTuple): x: int y: int z: N z3: N3 def fun(x: P[int, str]) -> None: pass def fun2(x: P[int, int]) -> None: pass def fun3(x: P[T, T]) -> T: return x.x fun(z) fun2(z) # E: Argument 1 to "fun2" has incompatible type "N"; expected "P[int, int]" \ # N: Following member(s) of "N" have conflicts: \ # N: y: expected "int", got "str" fun(N2(1)) # E: Argument 1 to "fun" has incompatible type "N2"; expected "P[int, str]" \ # N: "N2" is missing following "P" protocol member: \ # N: y reveal_type(fun3(z)) # N: Revealed type is "builtins.object" reveal_type(fun3(z3)) # N: Revealed type is "builtins.int" [builtins fixtures/list.pyi] [case testBasicCallableStructuralSubtyping] from typing import Callable, Generic, TypeVar def apply(f: Callable[[int], int], x: int) -> int: return f(x) class Add5: def __call__(self, x: int) -> int: return x + 5 apply(Add5(), 5) T = TypeVar('T') def apply_gen(f: Callable[[T], T]) -> T: pass reveal_type(apply_gen(Add5())) # N: Revealed type is "builtins.int" def apply_str(f: Callable[[str], int], x: str) -> int: return f(x) apply_str(Add5(), 'a') # E: Argument 1 to "apply_str" has incompatible type "Add5"; expected "Callable[[str], int]" \ # N: "Add5.__call__" has type "def __call__(self, x: int) -> int" [builtins fixtures/isinstancelist.pyi] [case testMoreComplexCallableStructuralSubtyping] from mypy_extensions import Arg, VarArg from typing import Protocol, Callable def call_soon(cb: Callable[[Arg(int, 'x'), VarArg(str)], int]): pass class Good: def __call__(self, x: int, *rest: str) -> int: pass class Bad1: def __call__(self, x: int, *rest: int) -> int: pass class Bad2: def __call__(self, y: int, *rest: str) -> int: pass call_soon(Good()) call_soon(Bad1()) # E: Argument 1 to "call_soon" has incompatible type "Bad1"; expected "def (x: int, *str) -> int" \ # N: "Bad1.__call__" has type "def __call__(self, x: int, *rest: int) -> int" call_soon(Bad2()) # E: Argument 1 to "call_soon" has incompatible type "Bad2"; expected "def (x: int, *str) -> int" \ # N: "Bad2.__call__" has type "def __call__(self, y: int, *rest: str) -> int" [builtins fixtures/isinstancelist.pyi] [case testStructuralSupportForPartial] from typing import Callable, TypeVar, Generic, Any T = TypeVar('T') class partial(Generic[T]): def __init__(self, func: Callable[..., T], *args: Any) -> None: ... def __call__(self, *args: Any) -> T: ... def inc(a: int, temp: str) -> int: pass def foo(f: Callable[[int], T]) -> T: return f(1) reveal_type(foo(partial(inc, 'temp'))) # N: Revealed type is "builtins.int" [builtins fixtures/list.pyi] [case testStructuralInferenceForCallable] from typing import Callable, TypeVar, Tuple T = TypeVar('T') S = TypeVar('S') class Actual: def __call__(self, arg: int) -> str: pass def fun(cb: Callable[[T], S]) -> Tuple[T, S]: pass reveal_type(fun(Actual())) # N: Revealed type is "tuple[builtins.int, builtins.str]" [builtins fixtures/tuple.pyi] -- Standard protocol types (SupportsInt, Sized, etc.) -- -------------------------------------------------- -- More tests could be added for types from typing converted to protocols [case testBasicSizedProtocol] from typing import Sized class Foo: def __len__(self) -> int: return 42 def bar(a: Sized) -> int: return a.__len__() bar(Foo()) bar((1, 2)) bar(1) # E: Argument 1 to "bar" has incompatible type "int"; expected "Sized" [builtins fixtures/isinstancelist.pyi] [typing fixtures/typing-medium.pyi] [case testBasicSupportsIntProtocol] from typing import SupportsInt class Bar: def __int__(self): return 1 def foo(a: SupportsInt): pass foo(Bar()) foo('no way') # E: Argument 1 to "foo" has incompatible type "str"; expected "SupportsInt" [builtins fixtures/isinstancelist.pyi] [typing fixtures/typing-medium.pyi] -- Additional tests and corner cases for protocols -- ---------------------------------------------- [case testAnyWithProtocols] from typing import Protocol, Any, TypeVar T = TypeVar('T') class P1(Protocol): attr1: int class P2(Protocol[T]): attr2: T class P3(Protocol): attr: P3 def f1(x: P1) -> None: pass def f2(x: P2[str]) -> None: pass def f3(x: P3) -> None: pass class C1: attr1: Any class C2: attr2: Any class C3: attr: Any f1(C1()) f2(C2()) f3(C3()) f2(C3()) # E: Argument 1 to "f2" has incompatible type "C3"; expected "P2[str]" a: Any f1(a) f2(a) f3(a) [case testErrorsForProtocolsInDifferentPlaces] from typing import Protocol class P(Protocol): attr1: int attr2: str attr3: int class C: attr1: str @property def attr2(self) -> int: pass x: P = C() # E: Incompatible types in assignment (expression has type "C", variable has type "P") \ # N: "C" is missing following "P" protocol member: \ # N: attr3 \ # N: Following member(s) of "C" have conflicts: \ # N: attr1: expected "int", got "str" \ # N: attr2: expected "str", got "int" \ # N: Protocol member P.attr2 expected settable variable, got read-only attribute def f(x: P) -> P: return C() # E: Incompatible return value type (got "C", expected "P") \ # N: "C" is missing following "P" protocol member: \ # N: attr3 \ # N: Following member(s) of "C" have conflicts: \ # N: attr1: expected "int", got "str" \ # N: attr2: expected "str", got "int" \ # N: Protocol member P.attr2 expected settable variable, got read-only attribute f(C()) # E: Argument 1 to "f" has incompatible type "C"; expected "P" \ # N: "C" is missing following "P" protocol member: \ # N: attr3 \ # N: Following member(s) of "C" have conflicts: \ # N: attr1: expected "int", got "str" \ # N: attr2: expected "str", got "int" \ # N: Protocol member P.attr2 expected settable variable, got read-only attribute [builtins fixtures/list.pyi] [case testIterableProtocolOnClass] from typing import TypeVar, Iterator T = TypeVar('T', bound='A') class A: def __iter__(self: T) -> Iterator[T]: pass class B(A): pass reveal_type(list(b for b in B())) # N: Revealed type is "builtins.list[__main__.B]" reveal_type(list(B())) # N: Revealed type is "builtins.list[__main__.B]" [builtins fixtures/list.pyi] [case testIterableProtocolOnMetaclass] from typing import TypeVar, Iterator, Type T = TypeVar('T') class EMeta(type): def __iter__(self: Type[T]) -> Iterator[T]: pass class E(metaclass=EMeta): pass class C(E): pass reveal_type(list(c for c in C)) # N: Revealed type is "builtins.list[__main__.C]" reveal_type(list(C)) # N: Revealed type is "builtins.list[__main__.C]" [builtins fixtures/list.pyi] [case testClassesGetattrWithProtocols] from typing import Protocol class P(Protocol): attr: int class PP(Protocol): @property def attr(self) -> int: pass class C: def __getattr__(self, attr: str) -> int: pass class C2(C): def __setattr__(self, attr: str, val: int) -> None: pass class D: def __getattr__(self, attr: str) -> str: pass def fun(x: P) -> None: reveal_type(P.attr) # N: Revealed type is "builtins.int" def fun_p(x: PP) -> None: reveal_type(P.attr) # N: Revealed type is "builtins.int" fun(C()) # E: Argument 1 to "fun" has incompatible type "C"; expected "P" \ # N: Protocol member P.attr expected settable variable, got read-only attribute fun(C2()) fun_p(D()) # E: Argument 1 to "fun_p" has incompatible type "D"; expected "PP" \ # N: Following member(s) of "D" have conflicts: \ # N: attr: expected "int", got "str" fun_p(C()) # OK [builtins fixtures/list.pyi] [case testImplicitTypesInProtocols] from typing import Protocol class P(Protocol): x = 1 # E: All protocol members must have explicitly declared types class C: x: int class D: x: str x: P x = D() # E: Incompatible types in assignment (expression has type "D", variable has type "P") \ # N: Following member(s) of "D" have conflicts: \ # N: x: expected "int", got "str" x = C() # OK [builtins fixtures/list.pyi] [case testProtocolIncompatibilityWithGenericMethod] from typing import Protocol, TypeVar T = TypeVar('T') S = TypeVar('S') class A(Protocol): def f(self, x: T) -> None: pass class B: def f(self, x: S, y: T) -> None: pass x: A = B() [out] main:11: error: Incompatible types in assignment (expression has type "B", variable has type "A") main:11: note: Following member(s) of "B" have conflicts: main:11: note: Expected: main:11: note: def [T] f(self, x: T) -> None main:11: note: Got: main:11: note: def [S, T] f(self, x: S, y: T) -> None [case testProtocolIncompatibilityWithGenericMethodBounded] from typing import Protocol, TypeVar T = TypeVar('T') S = TypeVar('S', bound=int) class A(Protocol): def f(self, x: T) -> None: pass class B: def f(self, x: S, y: T) -> None: pass x: A = B() [out] main:11: error: Incompatible types in assignment (expression has type "B", variable has type "A") main:11: note: Following member(s) of "B" have conflicts: main:11: note: Expected: main:11: note: def [T] f(self, x: T) -> None main:11: note: Got: main:11: note: def [S: int, T] f(self, x: S, y: T) -> None [case testProtocolIncompatibilityWithGenericRestricted] from typing import Protocol, TypeVar T = TypeVar('T') S = TypeVar('S', int, str) class A(Protocol): def f(self, x: T) -> None: pass class B: def f(self, x: S, y: T) -> None: pass x: A = B() [out] main:11: error: Incompatible types in assignment (expression has type "B", variable has type "A") main:11: note: Following member(s) of "B" have conflicts: main:11: note: Expected: main:11: note: def [T] f(self, x: T) -> None main:11: note: Got: main:11: note: def [S: (int, str), T] f(self, x: S, y: T) -> None [case testProtocolIncompatibilityWithManyOverloads] from typing import Protocol, overload class C1: pass class C2: pass class A(Protocol): @overload def f(self, x: int) -> int: pass @overload def f(self, x: str) -> str: pass @overload def f(self, x: C1) -> C2: pass @overload def f(self, x: C2) -> C1: pass class B: def f(self) -> None: pass x: A = B() [out] main:18: error: Incompatible types in assignment (expression has type "B", variable has type "A") main:18: note: Following member(s) of "B" have conflicts: main:18: note: Expected: main:18: note: @overload main:18: note: def f(self, x: int) -> int main:18: note: @overload main:18: note: def f(self, x: str) -> str main:18: note: @overload main:18: note: def f(self, x: C1) -> C2 main:18: note: @overload main:18: note: def f(self, x: C2) -> C1 main:18: note: Got: main:18: note: def f(self) -> None [case testProtocolIncompatibilityWithManyConflicts] from typing import Protocol class A(Protocol): def f(self, x: int) -> None: pass def g(self, x: int) -> None: pass def h(self, x: int) -> None: pass def i(self, x: int) -> None: pass class B: def f(self, x: str) -> None: pass def g(self, x: str) -> None: pass def h(self, x: str) -> None: pass def i(self, x: str) -> None: pass x: A = B() [out] main:14: error: Incompatible types in assignment (expression has type "B", variable has type "A") main:14: note: Following member(s) of "B" have conflicts: main:14: note: Expected: main:14: note: def f(self, x: int) -> None main:14: note: Got: main:14: note: def f(self, x: str) -> None main:14: note: Expected: main:14: note: def g(self, x: int) -> None main:14: note: Got: main:14: note: def g(self, x: str) -> None main:14: note: <2 more conflict(s) not shown> [case testProtocolIncompatibilityWithUnionType] from typing import Any, Optional, Protocol class A(Protocol): def execute(self, statement: Any, *args: Any, **kwargs: Any) -> None: ... class B(Protocol): def execute(self, stmt: Any, *args: Any, **kwargs: Any) -> None: ... def cool(self) -> None: ... def func1(arg: A) -> None: ... def func2(arg: Optional[A]) -> None: ... x: B func1(x) func2(x) [builtins fixtures/dict.pyi] [out] main:14: error: Argument 1 to "func1" has incompatible type "B"; expected "A" main:14: note: Following member(s) of "B" have conflicts: main:14: note: Expected: main:14: note: def execute(self, statement: Any, *args: Any, **kwargs: Any) -> None main:14: note: Got: main:14: note: def execute(self, stmt: Any, *args: Any, **kwargs: Any) -> None main:15: error: Argument 1 to "func2" has incompatible type "B"; expected "A | None" main:15: note: Following member(s) of "B" have conflicts: main:15: note: Expected: main:15: note: def execute(self, statement: Any, *args: Any, **kwargs: Any) -> None main:15: note: Got: main:15: note: def execute(self, stmt: Any, *args: Any, **kwargs: Any) -> None [case testDontShowNotesForTupleAndIterableProtocol] from typing import Iterable, Sequence, Protocol, NamedTuple class N(NamedTuple): x: int def f1(x: Iterable[str]) -> None: pass def f2(x: Sequence[str]) -> None: pass # The errors below should be short f1(N(1)) # E: Argument 1 to "f1" has incompatible type "N"; expected "Iterable[str]" f2(N(2)) # E: Argument 1 to "f2" has incompatible type "N"; expected "Sequence[str]" [builtins fixtures/tuple.pyi] [case testNotManyFlagConflitsShownInProtocols] from typing import Protocol class AllSettable(Protocol): a: int b: int c: int d: int class AllReadOnly: @property def a(self) -> int: pass @property def b(self) -> int: pass @property def c(self) -> int: pass @property def d(self) -> int: pass x: AllSettable = AllReadOnly() [builtins fixtures/property.pyi] [out] main:19: error: Incompatible types in assignment (expression has type "AllReadOnly", variable has type "AllSettable") main:19: note: Protocol member AllSettable.a expected settable variable, got read-only attribute main:19: note: Protocol member AllSettable.b expected settable variable, got read-only attribute main:19: note: <2 more conflict(s) not shown> [case testProtocolsMoreConflictsNotShown] from typing import Generic, Protocol, TypeVar T = TypeVar('T') class MockMapping(Protocol[T]): def a(self, x: T) -> int: pass def b(self, x: T) -> int: pass def c(self, x: T) -> int: pass d: T e: T f: T class MockDict(MockMapping[T]): more: int def f(x: MockMapping[int]) -> None: pass x: MockDict[str] f(x) # E: Argument 1 to "f" has incompatible type "MockDict[str]"; expected "MockMapping[int]" [builtins fixtures/tuple.pyi] [case testProtocolNotesForComplexSignatures] from typing import Protocol, Optional class P(Protocol): def meth(self, x: int, *args: str) -> None: pass def other(self, *args, hint: Optional[str] = None, **kwargs: str) -> None: pass class C: def meth(self) -> int: pass def other(self) -> int: pass x: P = C() [builtins fixtures/dict.pyi] [out] main:10: error: Incompatible types in assignment (expression has type "C", variable has type "P") main:10: note: Following member(s) of "C" have conflicts: main:10: note: Expected: main:10: note: def meth(self, x: int, *args: str) -> None main:10: note: Got: main:10: note: def meth(self) -> int main:10: note: Expected: main:10: note: def other(self, *args: Any, hint: str | None = ..., **kwargs: str) -> None main:10: note: Got: main:10: note: def other(self) -> int [case testObjectAllowedInProtocolBases] from typing import Protocol class P(Protocol, object): pass [out] [case testNoneSubtypeOfEmptyProtocol] from typing import Protocol class P(Protocol): pass x: P = None [out] [case testNoneSubtypeOfAllProtocolsWithoutStrictOptional] # flags: --no-strict-optional from typing import Protocol class P(Protocol): attr: int def meth(self, arg: str) -> str: pass x: P = None [out] [case testNoneSubtypeOfEmptyProtocolStrict] from typing import Protocol class P(Protocol): pass x: P = None class PBad(Protocol): x: int y: PBad = None # E: Incompatible types in assignment (expression has type "None", variable has type "PBad") [out] [case testOnlyMethodProtocolUsableWithIsSubclass] from typing import Protocol, runtime_checkable, Union, Type, Sequence, overload @runtime_checkable class P(Protocol): def meth(self) -> int: pass @runtime_checkable class PBad(Protocol): x: str class C: x: str def meth(self) -> int: pass class E: pass cls: Type[Union[C, E]] issubclass(cls, PBad) # E: Only protocols that don't have non-method members can be used with issubclass() \ # N: Protocol "PBad" has non-method member(s): x if issubclass(cls, P): reveal_type(cls) # N: Revealed type is "type[__main__.C]" else: reveal_type(cls) # N: Revealed type is "type[__main__.E]" @runtime_checkable class POverload(Protocol): @overload def meth(self, a: int) -> float: ... @overload def meth(self, a: str) -> Sequence[float]: ... def meth(self, a): pass reveal_type(issubclass(int, POverload)) # N: Revealed type is "builtins.bool" [builtins fixtures/isinstance.pyi] [typing fixtures/typing-full.pyi] [out] [case testCallableImplementsProtocol] from typing import Protocol class Caller(Protocol): def __call__(self, x: str, *args: int) -> None: ... def call(x: str, *args: int) -> None: pass def bad(x: int, *args: str) -> None: pass def func(caller: Caller) -> None: pass func(call) func(bad) # E: Argument 1 to "func" has incompatible type "def bad(x: int, *args: str) -> None"; expected "Caller" \ # N: "Caller.__call__" has type "def __call__(self, x: str, *args: int) -> None" [builtins fixtures/tuple.pyi] [out] [case testCallableImplementsProtocolGeneric] from typing import Protocol, TypeVar, Tuple T = TypeVar('T') S = TypeVar('S') class Caller(Protocol[T, S]): def __call__(self, x: T, y: S) -> Tuple[T, S]: ... def call(x: int, y: str) -> Tuple[int, str]: ... def func(caller: Caller[T, S]) -> Tuple[T, S]: pass reveal_type(func(call)) # N: Revealed type is "tuple[builtins.int, builtins.str]" [builtins fixtures/tuple.pyi] [out] [case testCallableImplementsProtocolGenericTight] from typing import Protocol, TypeVar T = TypeVar('T') class Caller(Protocol): def __call__(self, x: T) -> T: ... def call(x: T) -> T: ... def bad(x: int) -> int: ... def func(caller: Caller) -> None: pass func(call) func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int], int]"; expected "Caller" \ # N: "Caller.__call__" has type "def [T] __call__(self, x: T) -> T" [builtins fixtures/tuple.pyi] [out] [case testCallableImplementsProtocolGenericNotGeneric] from typing import Protocol, TypeVar, Tuple T = TypeVar('T') class Caller(Protocol): def __call__(self, x: int) -> int: ... def call(x: T) -> T: ... def bad(x: T) -> Tuple[T, T]: ... def func(caller: Caller) -> None: pass func(call) func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[T], tuple[T, T]]"; expected "Caller" \ # N: "Caller.__call__" has type "def __call__(self, x: int) -> int" [builtins fixtures/tuple.pyi] [out] [case testCallableImplementsProtocolOverload] from typing import Protocol, overload, Union class Caller(Protocol): @overload def __call__(self, x: int) -> int: ... @overload def __call__(self, x: str) -> str: ... @overload def call(x: int) -> int: ... @overload def call(x: str) -> str: ... def call(x: Union[int, str]) -> Union[int, str]: pass def bad(x: Union[int, str]) -> Union[int, str]: pass def func(caller: Caller) -> None: pass func(call) func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int | str], int | str]"; expected "Caller" \ # N: "Caller.__call__" has type overloaded function [out] [case testCallableImplementsProtocolExtraNote] from typing import Protocol class Caller(Protocol): def __call__(self, x: str, *args: int) -> None: ... def bad(x: int, *args: str) -> None: pass cb: Caller = bad # E: Incompatible types in assignment (expression has type "def bad(x: int, *args: str) -> None", variable has type "Caller") \ # N: "Caller.__call__" has type "def __call__(self, x: str, *args: int) -> None" [builtins fixtures/tuple.pyi] [out] [case testCallableImplementsProtocolArgName] from typing import Protocol class Caller(Protocol): def __call__(self, x: str) -> None: ... class CallerAnon(Protocol): def __call__(self, __x: str) -> None: ... def call(x: str) -> None: pass def bad(y: str) -> None: pass def func(caller: Caller) -> None: pass def anon(caller: CallerAnon) -> None: pass func(call) func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[str], None]"; expected "Caller" \ # N: "Caller.__call__" has type "def __call__(self, x: str) -> None" anon(bad) [out] [case testCallableProtocolVsProtocol] from typing import Protocol class One(Protocol): def __call__(self, x: str) -> None: ... class Other(Protocol): def __call__(self, x: str) -> None: ... class Bad(Protocol): def __call__(self, zzz: str) -> None: ... def func(caller: One) -> None: pass a: Other b: Bad func(a) func(b) # E: Argument 1 to "func" has incompatible type "Bad"; expected "One" \ # N: "One.__call__" has type "def __call__(self, x: str) -> None" [out] [case testJoinProtocolCallback] from typing import Protocol, Callable class A: ... class B(A): ... class C(B): ... class D(B): ... class Call(Protocol): def __call__(self, x: B) -> C: ... Normal = Callable[[A], D] a: Call b: Normal reveal_type([a, b]) # N: Revealed type is "builtins.list[def (__main__.B) -> __main__.B]" reveal_type([b, a]) # N: Revealed type is "builtins.list[def (__main__.B) -> __main__.B]" [builtins fixtures/list.pyi] [out] [case testMeetProtocolCallback] from typing import Protocol, Callable class A: ... class B(A): ... class C(B): ... class D(B): ... class Call(Protocol): def __call__(self, __x: C) -> B: ... Normal = Callable[[D], A] def a(x: Call) -> None: ... def b(x: Normal) -> None: ... reveal_type([a, b]) # N: Revealed type is "builtins.list[def (x: def (__main__.B) -> __main__.B)]" reveal_type([b, a]) # N: Revealed type is "builtins.list[def (x: def (__main__.B) -> __main__.B)]" [builtins fixtures/list.pyi] [out] [case testCallbackProtocolFunctionAttributesSubtyping] from typing import Protocol class A(Protocol): __name__: str def __call__(self) -> str: ... class B1(Protocol): __name__: int def __call__(self) -> str: ... class B2(Protocol): __name__: str def __call__(self) -> int: ... class B3(Protocol): __name__: str extra_stuff: int def __call__(self) -> str: ... def f() -> str: ... reveal_type(f.__name__) # N: Revealed type is "builtins.str" a: A = f # OK b1: B1 = f # E: Incompatible types in assignment (expression has type "Callable[[], str]", variable has type "B1") \ # N: Following member(s) of "function" have conflicts: \ # N: __name__: expected "int", got "str" b2: B2 = f # E: Incompatible types in assignment (expression has type "Callable[[], str]", variable has type "B2") \ # N: "B2.__call__" has type "Callable[[], int]" b3: B3 = f # E: Incompatible types in assignment (expression has type "Callable[[], str]", variable has type "B3") \ # N: "function" is missing following "B3" protocol member: \ # N: extra_stuff [case testCallbackProtocolFunctionAttributesInference] from typing import Protocol, TypeVar, Generic, Tuple T = TypeVar("T") S = TypeVar("S", covariant=True) class A(Protocol[T, S]): __name__: T def __call__(self) -> S: ... def f() -> int: ... def test(func: A[T, S]) -> Tuple[T, S]: ... reveal_type(test(f)) # N: Revealed type is "tuple[builtins.str, builtins.int]" [builtins fixtures/tuple.pyi] [case testProtocolsAlwaysABCs] from typing import Protocol class P(Protocol): ... class C(P): ... reveal_type(C.register(int)) # N: Revealed type is "def () -> builtins.int" [builtins fixtures/tuple.pyi] [typing fixtures/typing-full.pyi] [out] [case testProtocolVarianceAfterDecorators] # The test case is simplified, in reality this caused problems with @abstractmethod # in stubs and test fixtures. from typing import Protocol, TypeVar T = TypeVar('T') def dec(x: T) -> T: ... alias = dec class P(Protocol[T]): @alias def meth(self, arg: T) -> T: ... [out] [case testNamedTupleWithNoArgsCallableField] from typing import Callable, NamedTuple, Protocol class N(NamedTuple): func: Callable[[], str] class P(Protocol): @property def func(self) -> Callable[[], str]: ... p: P = N(lambda: 'foo') [builtins fixtures/property.pyi] [case testNamedTupleWithManyArgsCallableField] from typing import Callable, NamedTuple, Protocol class N(NamedTuple): func: Callable[[str, str, str], str] class P(Protocol): @property def func(self) -> Callable[[str, str, str], str]: ... p: P = N(lambda a, b, c: 'foo') [builtins fixtures/property.pyi] [case testLiteralsAgainstProtocols] from typing import Final, Literal, SupportsInt, SupportsAbs, TypeVar T = TypeVar('T') def abs(x: SupportsAbs[T]) -> T: ... def foo(x: SupportsInt) -> None: ... ONE: Final = 1 TWO: Literal[2] ALL: Literal[1, 2, 3] foo(ONE) foo(TWO) foo(3) reveal_type(abs(ONE)) # N: Revealed type is "builtins.int" reveal_type(abs(TWO)) # N: Revealed type is "builtins.int" reveal_type(abs(3)) # N: Revealed type is "builtins.int" reveal_type(abs(ALL)) # N: Revealed type is "builtins.int" [builtins fixtures/float.pyi] [typing fixtures/typing-full.pyi] [case testProtocolWithSlots] from typing import Protocol class A(Protocol): __slots__ = () [builtins fixtures/tuple.pyi] [case testProtocolSlotsIsNotProtocolMember] # https://github.com/python/mypy/issues/11884 from typing import Protocol class Foo(Protocol): __slots__ = () class NoSlots: pass class EmptySlots: __slots__ = () class TupleSlots: __slots__ = ('x', 'y') class StringSlots: __slots__ = 'x y' class InitSlots: __slots__ = ('x',) def __init__(self) -> None: self.x = None def foo(f: Foo): pass # All should pass: foo(NoSlots()) foo(EmptySlots()) foo(TupleSlots()) foo(StringSlots()) foo(InitSlots()) [builtins fixtures/tuple.pyi] [case testProtocolSlotsAndRuntimeCheckable] from typing import Protocol, runtime_checkable @runtime_checkable class Foo(Protocol): __slots__ = () class Bar: pass issubclass(Bar, Foo) # Used to be an error, when `__slots__` counted as a protocol member [builtins fixtures/isinstance.pyi] [typing fixtures/typing-full.pyi] [case testProtocolWithClassGetItem] # https://github.com/python/mypy/issues/11886 from typing import Any, Iterable, Protocol, Union class B: ... class C: def __class_getitem__(cls, __item: Any) -> Any: ... class SupportsClassGetItem(Protocol): __slots__: Union[str, Iterable[str]] = () def __class_getitem__(cls, __item: Any) -> Any: ... b1: SupportsClassGetItem = B() c1: SupportsClassGetItem = C() [builtins fixtures/tuple.pyi] [typing fixtures/typing-full.pyi] [case testNoneVsProtocol] # mypy: strict-optional from typing import Protocol class MyHashable(Protocol): def __hash__(self) -> int: ... def f(h: MyHashable) -> None: pass f(None) class Proto(Protocol): def __hash__(self) -> int: ... def method(self) -> None: ... def g(h: Proto) -> None: pass g(None) # E: Argument 1 to "g" has incompatible type "None"; expected "Proto" class Proto2(Protocol): def hash(self) -> None: ... def h(h: Proto2) -> None: pass h(None) # E: Argument 1 to "h" has incompatible type "None"; expected "Proto2" class EmptyProto(Protocol): ... def hh(h: EmptyProto) -> None: pass hh(None) # See https://github.com/python/mypy/issues/13081 class SupportsStr(Protocol): def __str__(self) -> str: ... def ss(s: SupportsStr) -> None: pass ss(None) class HashableStr(Protocol): def __str__(self) -> str: ... def __hash__(self) -> int: ... def hs(n: HashableStr) -> None: pass hs(None) [builtins fixtures/tuple.pyi] [case testPartialTypeProtocol] # flags: --no-local-partial-types from typing import Protocol class Flapper(Protocol): def flap(self) -> int: ... class Blooper: flap = None def bloop(self, x: Flapper) -> None: reveal_type([self, x]) # N: Revealed type is "builtins.list[builtins.object]" class Gleemer: flap = [] # E: Need type annotation for "flap" (hint: "flap: list[] = ...") def gleem(self, x: Flapper) -> None: reveal_type([self, x]) # N: Revealed type is "builtins.list[builtins.object]" [builtins fixtures/tuple.pyi] [case testPartialTypeProtocolHashable] # flags: --no-strict-optional --no-local-partial-types from typing import Protocol class Hashable(Protocol): def __hash__(self) -> int: ... class ObjectHashable: def __hash__(self) -> int: ... class DataArray(ObjectHashable): __hash__ = None def f(self, x: Hashable) -> None: reveal_type([self, x]) # N: Revealed type is "builtins.list[builtins.object]" [builtins fixtures/tuple.pyi] [case testPartialTypeProtocolHashableLocalPartialTypes] # flags: --no-strict-optional --local-partial-types from typing import Protocol class Hashable(Protocol): def __hash__(self) -> int: ... class ObjectHashable: def __hash__(self) -> int: ... class DataArray(ObjectHashable): __hash__ = None def f(self, x: Hashable) -> None: reveal_type([self, x]) # N: Revealed type is "builtins.list[builtins.object]" [builtins fixtures/tuple.pyi] [case testPartialAttributeNoneType] # flags: --no-strict-optional --no-local-partial-types from typing import Optional, Protocol, runtime_checkable @runtime_checkable class MyProtocol(Protocol): def is_valid(self) -> bool: ... text: Optional[str] class MyClass: text = None def is_valid(self) -> bool: reveal_type(self.text) # N: Revealed type is "None" assert isinstance(self, MyProtocol) [builtins fixtures/isinstance.pyi] [typing fixtures/typing-full.pyi] [case testPartialAttributeNoneTypeStrictOptional] # flags: --no-local-partial-types from typing import Optional, Protocol, runtime_checkable @runtime_checkable class MyProtocol(Protocol): def is_valid(self) -> bool: ... text: Optional[str] class MyClass: text = None def is_valid(self) -> bool: reveal_type(self.text) # N: Revealed type is "None" assert isinstance(self, MyProtocol) [builtins fixtures/isinstance.pyi] [typing fixtures/typing-full.pyi] [case testProtocolAndTypeVariableSpecialCase] from typing import TypeVar, Iterable, Optional, Callable, Protocol T_co = TypeVar('T_co', covariant=True) class SupportsNext(Protocol[T_co]): def __next__(self) -> T_co: ... N = TypeVar("N", bound=SupportsNext, covariant=True) class SupportsIter(Protocol[T_co]): def __iter__(self) -> T_co: ... def f(i: SupportsIter[N]) -> N: ... I = TypeVar('I', bound=Iterable) def g(x: I, y: Iterable) -> None: f(x) f(y) [case testMatchProtocolAgainstOverloadWithAmbiguity] from typing import TypeVar, Protocol, Union, Generic, overload T = TypeVar("T", covariant=True) class slice: pass class GetItem(Protocol[T]): def __getitem__(self, k: int) -> T: ... class Str: # Resembles 'str' def __getitem__(self, k: Union[int, slice]) -> Str: ... class Lst(Generic[T]): # Resembles 'list' def __init__(self, x: T): ... @overload def __getitem__(self, k: int) -> T: ... @overload def __getitem__(self, k: slice) -> Lst[T]: ... def __getitem__(self, k): pass def f(x: GetItem[GetItem[Str]]) -> None: ... a: Lst[Str] f(Lst(a)) class Lst2(Generic[T]): def __init__(self, x: T): ... # The overload items are tweaked but still compatible @overload def __getitem__(self, k: Str) -> None: ... @overload def __getitem__(self, k: slice) -> Lst2[T]: ... @overload def __getitem__(self, k: Union[int, str]) -> T: ... def __getitem__(self, k): pass b: Lst2[Str] f(Lst2(b)) class Lst3(Generic[T]): # Resembles 'list' def __init__(self, x: T): ... # The overload items are no longer compatible (too narrow argument type) @overload def __getitem__(self, k: slice) -> Lst3[T]: ... @overload def __getitem__(self, k: bool) -> T: ... def __getitem__(self, k): pass c: Lst3[Str] f(Lst3(c)) # E: Argument 1 to "f" has incompatible type "Lst3[Lst3[Str]]"; expected "GetItem[GetItem[Str]]" \ # N: Following member(s) of "Lst3[Lst3[Str]]" have conflicts: \ # N: Expected: \ # N: def __getitem__(self, int, /) -> GetItem[Str] \ # N: Got: \ # N: @overload \ # N: def __getitem__(self, slice, /) -> Lst3[Lst3[Str]] \ # N: @overload \ # N: def __getitem__(self, bool, /) -> Lst3[Str] [builtins fixtures/list.pyi] [typing fixtures/typing-full.pyi] [case testMatchProtocolAgainstOverloadWithMultipleMatchingItems] from typing import Protocol, overload, TypeVar, Any _T_co = TypeVar("_T_co", covariant=True) _T = TypeVar("_T") class SupportsRound(Protocol[_T_co]): @overload def __round__(self) -> int: ... @overload def __round__(self, __ndigits: int) -> _T_co: ... class C: # This matches both overload items of SupportsRound def __round__(self, __ndigits: int = ...) -> int: ... def round(number: SupportsRound[_T], ndigits: int) -> _T: ... round(C(), 1) [case testEmptyBodyImplicitlyAbstractProtocol] from typing import Protocol, overload, Union class P1(Protocol): def meth(self) -> int: ... class B1(P1): ... class C1(P1): def meth(self) -> int: return 0 B1() # E: Cannot instantiate abstract class "B1" with abstract attribute "meth" C1() class P2(Protocol): @classmethod def meth(cls) -> int: ... class B2(P2): ... class C2(P2): @classmethod def meth(cls) -> int: return 0 B2() # E: Cannot instantiate abstract class "B2" with abstract attribute "meth" C2() class P3(Protocol): @overload def meth(self, x: int) -> int: ... @overload def meth(self, x: str) -> str: ... @overload def not_abstract(self, x: int) -> int: ... @overload def not_abstract(self, x: str) -> str: ... def not_abstract(self, x: Union[int, str]) -> Union[int, str]: return 0 class B3(P3): ... class C3(P3): @overload def meth(self, x: int) -> int: ... @overload def meth(self, x: str) -> str: ... def meth(self, x: Union[int, str]) -> Union[int, str]: return 0 B3() # E: Cannot instantiate abstract class "B3" with abstract attribute "meth" C3() [builtins fixtures/classmethod.pyi] [case testEmptyBodyImplicitlyAbstractProtocolProperty] from typing import Protocol class P1(Protocol): @property def attr(self) -> int: ... class B1(P1): ... class C1(P1): @property def attr(self) -> int: return 0 B1() # E: Cannot instantiate abstract class "B1" with abstract attribute "attr" C1() class P2(Protocol): @property def attr(self) -> int: ... @attr.setter def attr(self, value: int) -> None: ... class B2(P2): ... class C2(P2): @property def attr(self) -> int: return 0 @attr.setter def attr(self, value: int) -> None: pass B2() # E: Cannot instantiate abstract class "B2" with abstract attribute "attr" C2() [builtins fixtures/property.pyi] [case testEmptyBodyImplicitlyAbstractProtocolStub] from stub import P1, P2, P3, P4 class B1(P1): ... class B2(P2): ... class B3(P3): ... class B4(P4): ... B1() B2() B3() B4() # E: Cannot instantiate abstract class "B4" with abstract attribute "meth" [file stub.pyi] from typing import Protocol, overload, Union from abc import abstractmethod class P1(Protocol): def meth(self) -> int: ... class P2(Protocol): @classmethod def meth(cls) -> int: ... class P3(Protocol): @overload def meth(self, x: int) -> int: ... @overload def meth(self, x: str) -> str: ... class P4(Protocol): @abstractmethod def meth(self) -> int: ... [builtins fixtures/classmethod.pyi] [case testEmptyBodyVariationsImplicitlyAbstractProtocol] from typing import Protocol class WithPass(Protocol): def meth(self) -> int: pass class A(WithPass): ... A() # E: Cannot instantiate abstract class "A" with abstract attribute "meth" class WithEllipses(Protocol): def meth(self) -> int: ... class B(WithEllipses): ... B() # E: Cannot instantiate abstract class "B" with abstract attribute "meth" class WithDocstring(Protocol): def meth(self) -> int: """Docstring for meth. This is meth.""" class C(WithDocstring): ... C() # E: Cannot instantiate abstract class "C" with abstract attribute "meth" class WithRaise(Protocol): def meth(self) -> int: """Docstring for meth.""" raise NotImplementedError class D(WithRaise): ... D() # E: Cannot instantiate abstract class "D" with abstract attribute "meth" [builtins fixtures/exception.pyi] [case testEmptyBodyNoneCompatibleProtocol] from abc import abstractmethod from typing import Any, Optional, Protocol, Union, overload from typing_extensions import TypeAlias NoneAlias: TypeAlias = None class NoneCompatible(Protocol): def f(self) -> None: ... def g(self) -> Any: ... def h(self) -> Optional[int]: ... def i(self) -> NoneAlias: ... @classmethod def j(cls) -> None: ... class A(NoneCompatible): ... A() # E: Cannot instantiate abstract class "A" with abstract attributes "f", "g", "h", "i" and "j" \ # N: The following methods were marked implicitly abstract because they have empty function bodies: "f", "g", "h", "i" and "j". If they are not meant to be abstract, explicitly `return` or `return None`. class NoneCompatible2(Protocol): def f(self, x: int): ... class B(NoneCompatible2): ... B() # E: Cannot instantiate abstract class "B" with abstract attribute "f" \ # N: "f" is implicitly abstract because it has an empty function body. If it is not meant to be abstract, explicitly `return` or `return None`. class NoneCompatible3(Protocol): @abstractmethod def f(self) -> None: ... @overload def g(self, x: int) -> int: ... @overload def g(self, x: str) -> None: ... def h(self, x): ... class C(NoneCompatible3): ... C() # E: Cannot instantiate abstract class "C" with abstract attributes "f", "g" and "h" [builtins fixtures/classmethod.pyi] [case testEmptyBodyWithFinal] from typing import Protocol, final class P(Protocol): @final # E: Protocol member cannot be final def f(self, x: int) -> str: ... class A(P): ... A() # E: Cannot instantiate abstract class "A" with abstract attribute "f" [case testProtocolWithNestedClass] from typing import TypeVar, Protocol class Template(Protocol): var: int class Meta: ... class B: var: int class Meta: ... class C: var: int class Meta(Template.Meta): ... def foo(t: Template) -> None: ... foo(B()) # E: Argument 1 to "foo" has incompatible type "B"; expected "Template" \ # N: Following member(s) of "B" have conflicts: \ # N: Meta: expected "type[__main__.Template.Meta]", got "type[__main__.B.Meta]" foo(C()) # OK [case testProtocolClassObjectAttribute] from typing import ClassVar, Protocol class P(Protocol): foo: int class A: foo = 42 class B: foo: ClassVar[int] class C: foo: ClassVar[str] class D: foo: int def test(arg: P) -> None: ... test(A) # OK test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: foo: expected "int", got "str" test(D) # E: Argument 1 to "test" has incompatible type "type[D]"; expected "P" \ # N: Only class variables allowed for class object access on protocols, foo is an instance variable of "D" [case testProtocolClassObjectClassVarRejected] from typing import ClassVar, Protocol class P(Protocol): foo: ClassVar[int] class B: foo: ClassVar[int] def test(arg: P) -> None: ... test(B) # E: Argument 1 to "test" has incompatible type "type[B]"; expected "P" \ # N: ClassVar protocol member P.foo can never be matched by a class object [case testProtocolClassObjectPropertyRejected] from typing import ClassVar, Protocol class P(Protocol): @property def foo(self) -> int: ... class B: @property def foo(self) -> int: ... class C: foo: int class D: foo: ClassVar[int] def test(arg: P) -> None: ... # TODO: skip type mismatch diagnostics in this case. test(B) # E: Argument 1 to "test" has incompatible type "type[B]"; expected "P" \ # N: Following member(s) of "B" have conflicts: \ # N: foo: expected "int", got "Callable[[B], int]" \ # N: Only class variables allowed for class object access on protocols, foo is an instance variable of "B" test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Only class variables allowed for class object access on protocols, foo is an instance variable of "C" test(D) # OK [builtins fixtures/property.pyi] [case testProtocolClassObjectInstanceMethod] from typing import Any, Protocol class P(Protocol): def foo(self, obj: Any) -> int: ... class B: def foo(self) -> int: ... class C: def foo(self) -> str: ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def foo(obj: Any) -> int \ # N: Got: \ # N: def foo(self: C) -> str [case testProtocolClassObjectInstanceMethodArg] from typing import Any, Protocol class P(Protocol): def foo(self, obj: B) -> int: ... class B: def foo(self) -> int: ... class C: def foo(self) -> int: ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def foo(obj: B) -> int \ # N: Got: \ # N: def foo(self: C) -> int [case testProtocolClassObjectInstanceMethodOverloaded] from typing import Any, Protocol, overload class P(Protocol): @overload def foo(self, obj: Any, arg: int) -> int: ... @overload def foo(self, obj: Any, arg: str) -> str: ... class B: @overload def foo(self, arg: int) -> int: ... @overload def foo(self, arg: str) -> str: ... def foo(self, arg: Any) -> Any: ... class C: @overload def foo(self, arg: int) -> int: ... @overload def foo(self, arg: str) -> int: ... def foo(self, arg: Any) -> Any: ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: @overload \ # N: def foo(obj: Any, arg: int) -> int \ # N: @overload \ # N: def foo(obj: Any, arg: str) -> str \ # N: Got: \ # N: @overload \ # N: def foo(self: C, arg: int) -> int \ # N: @overload \ # N: def foo(self: C, arg: str) -> int [case testProtocolClassObjectClassMethod] from typing import Protocol class P(Protocol): def foo(self) -> int: ... class B: @classmethod def foo(cls) -> int: ... class C: @classmethod def foo(cls) -> str: ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def foo() -> int \ # N: Got: \ # N: def foo() -> str [builtins fixtures/classmethod.pyi] [case testProtocolClassObjectStaticMethod] from typing import Protocol class P(Protocol): def foo(self) -> int: ... class B: @staticmethod def foo() -> int: ... class C: @staticmethod def foo() -> str: ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def foo() -> int \ # N: Got: \ # N: def foo() -> str [builtins fixtures/staticmethod.pyi] [case testProtocolClassObjectGenericInstanceMethod] from typing import Any, Protocol, Generic, List, TypeVar class P(Protocol): def foo(self, obj: Any) -> List[int]: ... T = TypeVar("T") class A(Generic[T]): def foo(self) -> T: ... class AA(A[List[T]]): ... class B(AA[int]): ... class C(AA[str]): ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def foo(obj: Any) -> list[int] \ # N: Got: \ # N: def foo(self: A[list[str]]) -> list[str] [builtins fixtures/list.pyi] [case testProtocolClassObjectGenericClassMethod] from typing import Any, Protocol, Generic, List, TypeVar class P(Protocol): def foo(self) -> List[int]: ... T = TypeVar("T") class A(Generic[T]): @classmethod def foo(self) -> T: ... class AA(A[List[T]]): ... class B(AA[int]): ... class C(AA[str]): ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def foo() -> list[int] \ # N: Got: \ # N: def foo() -> list[str] [builtins fixtures/isinstancelist.pyi] [case testProtocolClassObjectSelfTypeInstanceMethod] from typing import Protocol, TypeVar, Union T = TypeVar("T") class P(Protocol): def foo(self, arg: T) -> T: ... class B: def foo(self: T) -> T: ... class C: def foo(self: T) -> Union[T, int]: ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def [T] foo(arg: T) -> T \ # N: Got: \ # N: def [T] foo(self: T) -> T | int [case testProtocolClassObjectSelfTypeClassMethod] from typing import Protocol, Type, TypeVar T = TypeVar("T") class P(Protocol): def foo(self) -> B: ... class B: @classmethod def foo(cls: Type[T]) -> T: ... class C: @classmethod def foo(cls: Type[T]) -> T: ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def foo() -> B \ # N: Got: \ # N: def foo() -> C [builtins fixtures/classmethod.pyi] [case testProtocolClassObjectAttributeAndCall] from typing import Any, ClassVar, Protocol class P(Protocol): foo: int def __call__(self, x: int, y: int) -> Any: ... class B: foo: ClassVar[int] def __init__(self, x: int, y: int) -> None: ... class C: foo: ClassVar[int] def __init__(self, x: int, y: str) -> None: ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: "C" has constructor incompatible with "__call__" of "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def __call__(x: int, y: int) -> Any \ # N: Got: \ # N: def C(x: int, y: str) -> C \ # N: "P.__call__" has type "def __call__(self, x: int, y: int) -> Any" [case testProtocolClassObjectPureCallback] from typing import Any, ClassVar, Protocol class P(Protocol): def __call__(self, x: int, y: int) -> Any: ... class B: def __init__(self, x: int, y: int) -> None: ... class C: def __init__(self, x: int, y: str) -> None: ... def test(arg: P) -> None: ... test(B) # OK test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: "C" has constructor incompatible with "__call__" of "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def __call__(x: int, y: int) -> Any \ # N: Got: \ # N: def C(x: int, y: str) -> C \ # N: "P.__call__" has type "def __call__(self, x: int, y: int) -> Any" [builtins fixtures/type.pyi] [case testProtocolClassObjectCallableError] from typing import Protocol, Any, Callable class P(Protocol): def __call__(self, app: int) -> Callable[[str], None]: ... class C: def __init__(self, app: str) -> None: pass def __call__(self, el: str) -> None: return None p: P = C # E: Incompatible types in assignment (expression has type "type[C]", variable has type "P") \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def __call__(app: int) -> Callable[[str], None] \ # N: Got: \ # N: def C(app: str) -> C \ # N: "P.__call__" has type "def __call__(self, app: int) -> Callable[[str], None]" [builtins fixtures/type.pyi] [case testProtocolTypeTypeAttribute] from typing import ClassVar, Protocol, Type class P(Protocol): foo: int class A: foo = 42 class B: foo: ClassVar[int] class C: foo: ClassVar[str] class D: foo: int def test(arg: P) -> None: ... a: Type[A] b: Type[B] c: Type[C] d: Type[D] test(a) # OK test(b) # OK test(c) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: foo: expected "int", got "str" test(d) # E: Argument 1 to "test" has incompatible type "type[D]"; expected "P" \ # N: Only class variables allowed for class object access on protocols, foo is an instance variable of "D" [case testProtocolTypeTypeInstanceMethod] from typing import Any, Protocol, Type class P(Protocol): def foo(self, cls: Any) -> int: ... class B: def foo(self) -> int: ... class C: def foo(self) -> str: ... def test(arg: P) -> None: ... b: Type[B] c: Type[C] test(b) # OK test(c) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def foo(cls: Any) -> int \ # N: Got: \ # N: def foo(self: C) -> str [case testProtocolTypeTypeClassMethod] from typing import Protocol, Type class P(Protocol): def foo(self) -> int: ... class B: @classmethod def foo(cls) -> int: ... class C: @classmethod def foo(cls) -> str: ... def test(arg: P) -> None: ... b: Type[B] c: Type[C] test(b) # OK test(c) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def foo() -> int \ # N: Got: \ # N: def foo() -> str [builtins fixtures/classmethod.pyi] [case testProtocolTypeTypeSelfTypeInstanceMethod] from typing import Protocol, Type, TypeVar, Union T = TypeVar("T") class P(Protocol): def foo(self, arg: T) -> T: ... class B: def foo(self: T) -> T: ... class C: def foo(self: T) -> Union[T, int]: ... def test(arg: P) -> None: ... b: Type[B] c: Type[C] test(b) # OK test(c) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P" \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def [T] foo(arg: T) -> T \ # N: Got: \ # N: def [T] foo(self: T) -> T | int [case testProtocolClassObjectInference] from typing import Any, Protocol, TypeVar T = TypeVar("T", contravariant=True) class P(Protocol[T]): def foo(self, obj: T) -> int: ... class B: def foo(self) -> int: ... S = TypeVar("S") def test(arg: P[S]) -> S: ... reveal_type(test(B)) # N: Revealed type is "__main__.B" [case testProtocolTypeTypeInference] from typing import Any, Protocol, TypeVar, Type T = TypeVar("T", contravariant=True) class P(Protocol[T]): def foo(self, obj: T) -> int: ... class B: def foo(self) -> int: ... S = TypeVar("S") def test(arg: P[S]) -> S: ... b: Type[B] reveal_type(test(b)) # N: Revealed type is "__main__.B" [case testTypeAliasInProtocolBody] from typing import Protocol, List class P(Protocol): x = List[str] # E: Type aliases are prohibited in protocol bodies \ # N: Use variable annotation syntax to define protocol members class C: x: int def foo(x: P) -> None: ... foo(C()) # No extra error here [builtins fixtures/list.pyi] [case testTypeVarInProtocolBody] from typing import Protocol, TypeVar class C(Protocol): T = TypeVar('T') def __call__(self, t: T) -> T: ... def f_bad(t: int) -> int: return t S = TypeVar("S") def f_good(t: S) -> S: return t g: C = f_bad # E: Incompatible types in assignment (expression has type "Callable[[int], int]", variable has type "C") \ # N: "C.__call__" has type "def [T] __call__(self, t: T) -> T" g = f_good # OK [case testModuleAsProtocolImplementation] import default_config import bad_config_1 import bad_config_2 import bad_config_3 from typing import Protocol class Options(Protocol): timeout: int one_flag: bool other_flag: bool def update(self) -> bool: ... def setup(options: Options) -> None: ... setup(default_config) # OK setup(bad_config_1) # E: Argument 1 to "setup" has incompatible type Module; expected "Options" \ # N: "ModuleType" is missing following "Options" protocol member: \ # N: timeout setup(bad_config_2) # E: Argument 1 to "setup" has incompatible type Module; expected "Options" \ # N: Following member(s) of Module "bad_config_2" have conflicts: \ # N: one_flag: expected "bool", got "int" setup(bad_config_3) # E: Argument 1 to "setup" has incompatible type Module; expected "Options" \ # N: Following member(s) of Module "bad_config_3" have conflicts: \ # N: Expected: \ # N: def update() -> bool \ # N: Got: \ # N: def update(obj: Any) -> bool [file default_config.py] timeout = 100 one_flag = True other_flag = False def update() -> bool: ... [file bad_config_1.py] one_flag = True other_flag = False def update() -> bool: ... [file bad_config_2.py] timeout = 100 one_flag = 42 other_flag = False def update() -> bool: ... [file bad_config_3.py] timeout = 100 one_flag = True other_flag = False def update(obj) -> bool: ... [builtins fixtures/module.pyi] [case testModuleAsProtocolImplementationInference] import default_config from typing import Protocol, TypeVar T = TypeVar("T", covariant=True) class Options(Protocol[T]): timeout: int one_flag: bool other_flag: bool def update(self) -> T: ... def setup(options: Options[T]) -> T: ... reveal_type(setup(default_config)) # N: Revealed type is "builtins.str" [file default_config.py] timeout = 100 one_flag = True other_flag = False def update() -> str: ... [builtins fixtures/module.pyi] [case testModuleAsProtocolImplementationClassObject] import runner import bad_runner from typing import Callable, Protocol class Runner(Protocol): @property def Run(self) -> Callable[[int], Result]: ... class Result(Protocol): value: int def run(x: Runner) -> None: ... run(runner) # OK run(bad_runner) # E: Argument 1 to "run" has incompatible type Module; expected "Runner" \ # N: Following member(s) of Module "bad_runner" have conflicts: \ # N: Expected: \ # N: def (int, /) -> Result \ # N: Got: \ # N: def Run(arg: str) -> Run [file runner.py] class Run: value: int def __init__(self, arg: int) -> None: ... [file bad_runner.py] class Run: value: int def __init__(self, arg: str) -> None: ... [builtins fixtures/module.pyi] [case testModuleAsProtocolImplementationTypeAlias] import runner import bad_runner from typing import Callable, Protocol class Runner(Protocol): @property def run(self) -> Callable[[int], Result]: ... class Result(Protocol): value: int def run(x: Runner) -> None: ... run(runner) # OK run(bad_runner) # E: Argument 1 to "run" has incompatible type Module; expected "Runner" \ # N: Following member(s) of Module "bad_runner" have conflicts: \ # N: Expected: \ # N: def (int, /) -> Result \ # N: Got: \ # N: def Run(arg: str) -> Run [file runner.py] class Run: value: int def __init__(self, arg: int) -> None: ... run = Run [file bad_runner.py] class Run: value: int def __init__(self, arg: str) -> None: ... run = Run [builtins fixtures/module.pyi] [case testModuleAsProtocolImplementationClassVar] from typing import ClassVar, Protocol import mod class My(Protocol): x: ClassVar[int] def test(mod: My) -> None: ... test(mod=mod) # E: Argument "mod" to "test" has incompatible type Module; expected "My" \ # N: Protocol member My.x expected class variable, got instance variable [file mod.py] x: int [builtins fixtures/module.pyi] [case testModuleAsProtocolImplementationFinal] from typing import Protocol import some_module class My(Protocol): a: int def func(arg: My) -> None: ... func(some_module) # E: Argument 1 to "func" has incompatible type Module; expected "My" \ # N: Protocol member My.a expected settable variable, got read-only attribute [file some_module.py] from typing import Final a: Final = 1 [builtins fixtures/module.pyi] [case testModuleAsProtocolRedefinitionTopLevel] from typing import Protocol class P(Protocol): def f(self) -> str: ... cond: bool t: P if cond: import mod1 as t else: import mod2 as t import badmod as t # E: Incompatible import of "t" (imported name has type Module, local name has type "P") [file mod1.py] def f() -> str: ... [file mod2.py] def f() -> str: ... [file badmod.py] def nothing() -> int: ... [builtins fixtures/module.pyi] [case testModuleAsProtocolRedefinitionImportFrom] from typing import Protocol class P(Protocol): def f(self) -> str: ... cond: bool t: P if cond: from package import mod1 as t else: from package import mod2 as t from package import badmod as t # E: Incompatible import of "t" (imported name has type Module, local name has type "P") package: int = 10 import package.mod1 as t import package.mod1 # E: Incompatible import of "package" (imported name has type Module, local name has type "int") [file package/mod1.py] def f() -> str: ... [file package/mod2.py] def f() -> str: ... [file package/badmod.py] def nothing() -> int: ... [builtins fixtures/module.pyi] [case testProtocolSelfTypeNewSyntax] from typing import Protocol, Self class P(Protocol): @property def next(self) -> Self: ... class C: next: C class S: next: Self x: P = C() y: P = S() z: P reveal_type(S().next) # N: Revealed type is "__main__.S" reveal_type(z.next) # N: Revealed type is "__main__.P" [builtins fixtures/property.pyi] [case testProtocolSelfTypeNewSyntaxSubProtocol] from typing import Protocol, Self class P(Protocol): @property def next(self) -> Self: ... class PS(P, Protocol): @property def other(self) -> Self: ... class C: next: C other: C class S: next: Self other: Self x: PS = C() y: PS = S() [builtins fixtures/property.pyi] [case testProtocolClassVarSelfType] from typing import ClassVar, Self, Protocol class P(Protocol): DEFAULT: ClassVar[Self] class C: DEFAULT: ClassVar[C] x: P = C() [case testInferenceViaTypeTypeMetaclass] from typing import Iterator, Iterable, TypeVar, Type M = TypeVar("M") class Meta(type): def __iter__(self: Type[M]) -> Iterator[M]: ... class Foo(metaclass=Meta): ... T = TypeVar("T") def test(x: Iterable[T]) -> T: ... reveal_type(test(Foo)) # N: Revealed type is "__main__.Foo" t_foo: Type[Foo] reveal_type(test(t_foo)) # N: Revealed type is "__main__.Foo" TF = TypeVar("TF", bound=Foo) def outer(cls: Type[TF]) -> TF: reveal_type(test(cls)) # N: Revealed type is "TF`-1" return cls() [case testProtocolImportNotMember] import m import lib class Bad: x: int class Good: x: lib.C x: m.P = Bad() # E: Incompatible types in assignment (expression has type "Bad", variable has type "P") \ # N: Following member(s) of "Bad" have conflicts: \ # N: x: expected "C", got "int" x = Good() [file m.py] from typing import Protocol class P(Protocol): import lib x: lib.C [file lib.py] class C: ... [case testAllowDefaultConstructorInProtocols] from typing import Protocol class P(Protocol): x: int def __init__(self, x: int) -> None: self.x = x class C(P): ... C(0) # OK [case testTypeVarValueConstraintAgainstGenericProtocol] from typing import TypeVar, Generic, Protocol, overload T_contra = TypeVar("T_contra", contravariant=True) AnyStr = TypeVar("AnyStr", str, bytes) class SupportsWrite(Protocol[T_contra]): def write(self, s: T_contra, /) -> None: ... class Buffer: ... class IO(Generic[AnyStr]): @overload def write(self: IO[bytes], s: Buffer, /) -> None: ... @overload def write(self, s: AnyStr, /) -> None: ... def write(self, s): ... def foo(fdst: SupportsWrite[AnyStr]) -> None: ... x: IO[str] foo(x) [case testTypeVarValueConstraintAgainstGenericProtocol2] from typing import Generic, Protocol, TypeVar, overload AnyStr = TypeVar("AnyStr", str, bytes) T_co = TypeVar("T_co", covariant=True) T_contra = TypeVar("T_contra", contravariant=True) class SupportsRead(Generic[T_co]): def read(self) -> T_co: ... class SupportsWrite(Protocol[T_contra]): def write(self, s: T_contra) -> object: ... def copyfileobj(fsrc: SupportsRead[AnyStr], fdst: SupportsWrite[AnyStr]) -> None: ... class WriteToMe(Generic[AnyStr]): @overload def write(self: WriteToMe[str], s: str) -> int: ... @overload def write(self: WriteToMe[bytes], s: bytes) -> int: ... def write(self, s): ... class WriteToMeOrReadFromMe(WriteToMe[AnyStr], SupportsRead[AnyStr]): ... copyfileobj(WriteToMeOrReadFromMe[bytes](), WriteToMe[bytes]()) [case testOverloadedMethodWithExplicitSelfTypes] from typing import Generic, overload, Protocol, TypeVar, Union AnyStr = TypeVar("AnyStr", str, bytes) T_co = TypeVar("T_co", covariant=True) T_contra = TypeVar("T_contra", contravariant=True) class SupportsRead(Protocol[T_co]): def read(self) -> T_co: ... class SupportsWrite(Protocol[T_contra]): def write(self, s: T_contra) -> int: ... class Input(Generic[AnyStr]): def read(self) -> AnyStr: ... class Output(Generic[AnyStr]): @overload def write(self: Output[str], s: str) -> int: ... @overload def write(self: Output[bytes], s: bytes) -> int: ... def write(self, s: Union[str, bytes]) -> int: ... def f(src: SupportsRead[AnyStr], dst: SupportsWrite[AnyStr]) -> None: ... def g1(a: Input[bytes], b: Output[bytes]) -> None: f(a, b) def g2(a: Input[bytes], b: Output[bytes]) -> None: f(a, b) def g3(a: Input[str], b: Output[bytes]) -> None: f(a, b) # E: Cannot infer value of type parameter "AnyStr" of "f" def g4(a: Input[bytes], b: Output[str]) -> None: f(a, b) # E: Cannot infer value of type parameter "AnyStr" of "f" [builtins fixtures/tuple.pyi] [case testOverloadProtocolSubtyping] from typing import Protocol, Self, overload class NumpyFloat: __add__: "FloatOP" class FloatOP(Protocol): @overload def __call__(self, other: float) -> NumpyFloat: ... @overload def __call__(self, other: NumpyFloat) -> NumpyFloat: ... class SupportsAdd(Protocol): @overload def __add__(self, other: float) -> Self: ... @overload def __add__(self, other: NumpyFloat) -> Self: ... x: SupportsAdd = NumpyFloat() [builtins fixtures/tuple.pyi] [case testSetterPropertyProtocolSubtypingBoth] from typing import Protocol class B1: ... class C1(B1): ... class B2: ... class C2(B2): ... class P1(Protocol): @property def foo(self) -> B1: ... @foo.setter def foo(self, x: C2) -> None: ... class P2(Protocol): @property def foo(self) -> B1: ... @foo.setter def foo(self, x: B2) -> None: ... class A1: @property def foo(self) -> B1: ... @foo.setter def foo(self, x: C2) -> None: ... class A2: @property def foo(self) -> C1: ... @foo.setter def foo(self, x: C2) -> None: ... class A3: @property def foo(self) -> C1: ... @foo.setter def foo(self, x: str) -> None: ... class A4: @property def foo(self) -> str: ... @foo.setter def foo(self, x: str) -> None: ... def f1(x: P1) -> None: ... def f2(x: P2) -> None: ... a1: A1 a2: A2 a3: A3 a4: A4 f1(a1) f1(a2) f1(a3) # E: Argument 1 to "f1" has incompatible type "A3"; expected "P1" \ # N: Following member(s) of "A3" have conflicts: \ # N: foo: expected setter type "C2", got "str" f1(a4) # E: Argument 1 to "f1" has incompatible type "A4"; expected "P1" \ # N: Following member(s) of "A4" have conflicts: \ # N: foo: expected "B1", got "str" \ # N: foo: expected setter type "C2", got "str" f2(a1) # E: Argument 1 to "f2" has incompatible type "A1"; expected "P2" \ # N: Following member(s) of "A1" have conflicts: \ # N: foo: expected setter type "B2", got "C2" \ # N: Setter types should behave contravariantly f2(a2) # E: Argument 1 to "f2" has incompatible type "A2"; expected "P2" \ # N: Following member(s) of "A2" have conflicts: \ # N: foo: expected setter type "B2", got "C2" \ # N: Setter types should behave contravariantly f2(a3) # E: Argument 1 to "f2" has incompatible type "A3"; expected "P2" \ # N: Following member(s) of "A3" have conflicts: \ # N: foo: expected setter type "B2", got "str" f2(a4) # E: Argument 1 to "f2" has incompatible type "A4"; expected "P2" \ # N: Following member(s) of "A4" have conflicts: \ # N: foo: expected "B1", got "str" \ # N: foo: expected setter type "B2", got "str" [builtins fixtures/property.pyi] [case testSetterPropertyProtocolSubtypingVarSuper] from typing import Protocol class B1: ... class C1(B1): ... class P1(Protocol): foo: B1 class P2(Protocol): foo: C1 class A1: @property def foo(self) -> B1: ... @foo.setter def foo(self, x: C1) -> None: ... class A2: @property def foo(self) -> C1: ... @foo.setter def foo(self, x: B1) -> None: ... class A3: @property def foo(self) -> C1: ... @foo.setter def foo(self, x: str) -> None: ... class A4: @property def foo(self) -> str: ... @foo.setter def foo(self, x: str) -> None: ... def f1(x: P1) -> None: ... def f2(x: P2) -> None: ... a1: A1 a2: A2 a3: A3 a4: A4 f1(a1) # E: Argument 1 to "f1" has incompatible type "A1"; expected "P1" \ # N: Following member(s) of "A1" have conflicts: \ # N: foo: expected setter type "B1", got "C1" \ # N: Setter types should behave contravariantly f1(a2) f1(a3) # E: Argument 1 to "f1" has incompatible type "A3"; expected "P1" \ # N: Following member(s) of "A3" have conflicts: \ # N: foo: expected setter type "B1", got "str" f1(a4) # E: Argument 1 to "f1" has incompatible type "A4"; expected "P1" \ # N: Following member(s) of "A4" have conflicts: \ # N: foo: expected "B1", got "str" f2(a1) # E: Argument 1 to "f2" has incompatible type "A1"; expected "P2" \ # N: Following member(s) of "A1" have conflicts: \ # N: foo: expected "C1", got "B1" f2(a2) f2(a3) # E: Argument 1 to "f2" has incompatible type "A3"; expected "P2" \ # N: Following member(s) of "A3" have conflicts: \ # N: foo: expected setter type "C1", got "str" f2(a4) # E: Argument 1 to "f2" has incompatible type "A4"; expected "P2" \ # N: Following member(s) of "A4" have conflicts: \ # N: foo: expected "C1", got "str" [builtins fixtures/property.pyi] [case testSetterPropertyProtocolSubtypingVarSub] from typing import Protocol class B1: ... class C1(B1): ... class B2: ... class C2(B2): ... class P1(Protocol): @property def foo(self) -> B1: ... @foo.setter def foo(self, x: C2) -> None: ... class P2(Protocol): @property def foo(self) -> B1: ... @foo.setter def foo(self, x: C1) -> None: ... class A1: foo: B1 class A2: foo: B2 class A3: foo: C2 class A4: foo: str def f1(x: P1) -> None: ... def f2(x: P2) -> None: ... a1: A1 a2: A2 a3: A3 a4: A4 f1(a1) # E: Argument 1 to "f1" has incompatible type "A1"; expected "P1" \ # N: Following member(s) of "A1" have conflicts: \ # N: foo: expected setter type "C2", got "B1" f1(a2) # E: Argument 1 to "f1" has incompatible type "A2"; expected "P1" \ # N: Following member(s) of "A2" have conflicts: \ # N: foo: expected "B1", got "B2" f1(a3) # E: Argument 1 to "f1" has incompatible type "A3"; expected "P1" \ # N: Following member(s) of "A3" have conflicts: \ # N: foo: expected "B1", got "C2" f1(a4) # E: Argument 1 to "f1" has incompatible type "A4"; expected "P1" \ # N: Following member(s) of "A4" have conflicts: \ # N: foo: expected "B1", got "str" \ # N: foo: expected setter type "C2", got "str" f2(a1) f2(a2) # E: Argument 1 to "f2" has incompatible type "A2"; expected "P2" \ # N: Following member(s) of "A2" have conflicts: \ # N: foo: expected "B1", got "B2" \ # N: foo: expected setter type "C1", got "B2" f2(a3) # E: Argument 1 to "f2" has incompatible type "A3"; expected "P2" \ # N: Following member(s) of "A3" have conflicts: \ # N: foo: expected "B1", got "C2" \ # N: foo: expected setter type "C1", got "C2" f2(a4) # E: Argument 1 to "f2" has incompatible type "A4"; expected "P2" \ # N: Following member(s) of "A4" have conflicts: \ # N: foo: expected "B1", got "str" \ # N: foo: expected setter type "C1", got "str" [builtins fixtures/property.pyi] [case testExplicitProtocolJoinPreference] from typing import Protocol, TypeVar T = TypeVar("T") class Proto1(Protocol): def foo(self) -> int: ... class Proto2(Proto1): def bar(self) -> str: ... class Proto3(Proto2): def baz(self) -> str: ... class Base: ... class A(Base, Proto3): ... class B(Base, Proto3): ... def join(a: T, b: T) -> T: ... def main(a: A, b: B) -> None: reveal_type(join(a, b)) # N: Revealed type is "__main__.Proto3" reveal_type(join(b, a)) # N: Revealed type is "__main__.Proto3" [case testProtocolImplementationWithDescriptors] from typing import Any, Protocol class Descr: def __get__(self, inst: Any, owner: Any) -> int: ... class DescrBad: def __get__(self, inst: Any, owner: Any) -> str: ... class Proto(Protocol): x: int class C: x = Descr() class CBad: x = DescrBad() a: Proto = C() b: Proto = CBad() # E: Incompatible types in assignment (expression has type "CBad", variable has type "Proto") \ # N: Following member(s) of "CBad" have conflicts: \ # N: x: expected "int", got "str" [case testProtocolCheckDefersNode] from typing import Any, Callable, Protocol class Proto(Protocol): def f(self) -> int: ... def defer(f: Callable[[Any], int]) -> Callable[[Any], str]: ... def bad() -> Proto: return Impl() # E: Incompatible return value type (got "Impl", expected "Proto") \ # N: Following member(s) of "Impl" have conflicts: \ # N: Expected: \ # N: def f(self) -> int \ # N: Got: \ # N: def f(self) -> str \ class Impl: @defer def f(self) -> int: ... [case testProtocolCheckDefersNode2] from typing import Any, Callable, Protocol, TypeVar class Proto(Protocol): def f(self) -> int: ... T = TypeVar("T") def defer(f: Callable[[T], int]) -> Callable[[T], list[int]]: ... def bad() -> Proto: return Impl() # E: Incompatible return value type (got "Impl", expected "Proto") \ # N: Following member(s) of "Impl" have conflicts: \ # N: Expected: \ # N: def f(self) -> int \ # N: Got: \ # N: def f(self) -> list[int] \ class Impl: @defer def f(self) -> int: ... [case testInferCallableProtoWithAnySubclass] from typing import Any, Generic, Protocol, TypeVar T = TypeVar("T", covariant=True) Unknown: Any class Mock(Unknown): def __init__(self, **kwargs: Any) -> None: ... def __call__(self, *args: Any, **kwargs: Any) -> Any: ... class Factory(Protocol[T]): def __call__(self, **kwargs: Any) -> T: ... class Test(Generic[T]): def __init__(self, f: Factory[T]) -> None: ... t = Test(Mock()) reveal_type(t) # N: Revealed type is "__main__.Test[Any]" [builtins fixtures/dict.pyi] [case testProtocolClassObjectDescriptor] from typing import Any, Protocol, overload class Desc: @overload def __get__(self, instance: None, owner: Any) -> Desc: ... @overload def __get__(self, instance: object, owner: Any) -> int: ... def __get__(self, instance, owner): pass class HasDesc(Protocol): attr: Desc class HasInt(Protocol): attr: int class C: attr = Desc() x: HasInt = C() y: HasDesc = C z: HasInt = C # E: Incompatible types in assignment (expression has type "type[C]", variable has type "HasInt") \ # N: Following member(s) of "C" have conflicts: \ # N: attr: expected "int", got "Desc" [case testProtocolErrorReportingNoDuplicates] from typing import Callable, Protocol, TypeVar class P(Protocol): def meth(self) -> int: ... class C: def meth(self) -> str: ... def foo() -> None: c: P = C() # E: Incompatible types in assignment (expression has type "C", variable has type "P") \ # N: Following member(s) of "C" have conflicts: \ # N: Expected: \ # N: def meth(self) -> int \ # N: Got: \ # N: def meth(self) -> str x = defer() T = TypeVar("T") def deco(fn: Callable[[], T]) -> Callable[[], list[T]]: ... @deco def defer() -> int: ... [builtins fixtures/list.pyi] [case testProtocolClassValDescriptor] from typing import Any, Protocol, overload, ClassVar, Type class Desc: @overload def __get__(self, instance: None, owner: object) -> Desc: ... @overload def __get__(self, instance: object, owner: object) -> int: ... def __get__(self, instance, owner): pass class P(Protocol): x: ClassVar[Desc] class C: x = Desc() t: P = C() reveal_type(t.x) # N: Revealed type is "builtins.int" tt: Type[P] = C reveal_type(tt.x) # N: Revealed type is "__main__.Desc" bad: P = C # E: Incompatible types in assignment (expression has type "type[C]", variable has type "P") \ # N: Following member(s) of "C" have conflicts: \ # N: x: expected "int", got "Desc" [case testProtocolClassValCallable] from typing import Any, Protocol, overload, ClassVar, Type, Callable class P(Protocol): foo: Callable[[object], int] bar: ClassVar[Callable[[object], int]] class C: foo: Callable[[object], int] bar: ClassVar[Callable[[object], int]] t: P = C() reveal_type(t.foo) # N: Revealed type is "def (builtins.object) -> builtins.int" reveal_type(t.bar) # N: Revealed type is "def () -> builtins.int" tt: Type[P] = C reveal_type(tt.foo) # N: Revealed type is "def (builtins.object) -> builtins.int" reveal_type(tt.bar) # N: Revealed type is "def (builtins.object) -> builtins.int" [case testProtocolDecoratedSelfBound] from abc import abstractmethod from typing import Protocol, Self class Proto(Protocol): @abstractmethod def foo(self, x: Self) -> None: ... class Impl: def foo(self, x: Self) -> None: pass x: Proto = Impl() [case testIndirectDependencyOnProtocolIncremental] import a [file a.py] from b import P class CNested: def f(self) -> int: ... class C: def f(self) -> CNested: ... x: P = C() [file b.py] from typing import Protocol from c import PNested class P(Protocol): def f(self) -> PNested: ... [file c.py] from typing import Protocol class PNested(Protocol): def f(self) -> str: ... [file c.py.2] from typing import Protocol class PNested(Protocol): def f(self) -> int: ... [file c.py.3] from typing import Protocol class PNested(Protocol): def f(self) -> str: ... [out] tmp/a.py:8: error: Incompatible types in assignment (expression has type "C", variable has type "P") tmp/a.py:8: note: Following member(s) of "C" have conflicts: tmp/a.py:8: note: Expected: tmp/a.py:8: note: def f(self) -> PNested tmp/a.py:8: note: Got: tmp/a.py:8: note: def f(self) -> CNested [out2] [out3] tmp/a.py:8: error: Incompatible types in assignment (expression has type "C", variable has type "P") tmp/a.py:8: note: Following member(s) of "C" have conflicts: tmp/a.py:8: note: Expected: tmp/a.py:8: note: def f(self) -> PNested tmp/a.py:8: note: Got: tmp/a.py:8: note: def f(self) -> CNested [case testProtocolCannotBeDisjointBase] from typing import Protocol from typing_extensions import disjoint_base @disjoint_base # E: @disjoint_base cannot be used with protocol class class A(Protocol): pass [builtins fixtures/tuple.pyi]