| -- 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 testUnrelatedGenericProtocolsEquivalent] | |
| 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 testMutuallyRecursiveProtocolsTypesWithSubtleMismatch] | |
| 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__.<subclass of "__main__.C1[builtins.int]" and "__main__.P">" | |
| 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__.<subclass of "__main__.C2" and "__main__.P">" | |
| 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] | |
| 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[<type>] = ...") | |
| 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 | |
| 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 | |
| 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] | |
| 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] | |
| [case testTupleTypeSelfTypeProto] | |
| from typing import Protocol, TypeVar | |
| R = TypeVar("R", covariant=True) | |
| class P(Protocol[R]): | |
| def rep(self) -> R: ... | |
| T = TypeVar("T") | |
| def rep(x: P[T]) -> T: ... | |
| class C(tuple[int, str]): | |
| def rep(self: T) -> T: ... | |
| t: C | |
| reveal_type(t) # N: Revealed type is "tuple[builtins.int, builtins.str, fallback=__main__.C]" | |
| reveal_type(rep(t)) # N: Revealed type is "tuple[builtins.int, builtins.str, fallback=__main__.C]" | |
| def ok_rep(x: P[tuple[int, str]]) -> None: ... | |
| ok_rep(t) | |
| def bad_rep(x: P[tuple[str, int]]) -> None: ... | |
| bad_rep(t) # E: Argument 1 to "bad_rep" has incompatible type "C"; expected "P[tuple[str, int]]" \ | |
| # N: Following member(s) of "C" have conflicts: \ | |
| # N: Expected: \ | |
| # N: def rep(self) -> tuple[str, int] \ | |
| # N: Got: \ | |
| # N: def rep(self) -> C | |
| [builtins fixtures/tuple.pyi] | |
| [case testDivergingProtocol] | |
| from typing import Protocol, TypeVar, List | |
| T = TypeVar("T") | |
| class P(Protocol[T]): | |
| def meth(self) -> P[List[T]]: ... | |
| class C: | |
| def meth(self) -> C: ... | |
| # This should not cause infinite recursion. | |
| x: P[int] = C() | |
| [builtins fixtures/tuple.pyi] |