| -- Type checker test cases for abstract classes. |
| |
| |
| -- Subtyping with abstract classes |
| -- ------------------------------- |
| |
| |
| [case testAbstractClassSubclasses] |
| |
| from abc import abstractmethod, ABCMeta |
| |
| i: I |
| j: J |
| a: A |
| b: B |
| c: C |
| |
| def f(): i, j, a, b, c # Prevent redefinition |
| |
| j = c # E: Incompatible types in assignment (expression has type "C", variable has type "J") |
| a = i # E: Incompatible types in assignment (expression has type "I", variable has type "A") |
| a = j # E: Incompatible types in assignment (expression has type "J", variable has type "A") |
| b = i # E: Incompatible types in assignment (expression has type "I", variable has type "B") |
| |
| i = a |
| i = b |
| i = c |
| j = a |
| j = b |
| a = b |
| |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self): pass |
| class J(metaclass=ABCMeta): |
| @abstractmethod |
| def g(self): pass |
| class A(I, J): pass |
| class B(A): pass |
| class C(I): pass |
| [builtins fixtures/tuple.pyi] |
| |
| [case testAbstractClassSubtypingViaExtension] |
| |
| from abc import abstractmethod, ABCMeta |
| |
| i: I |
| j: J |
| a: A |
| o: object |
| |
| def f(): i, j, a, o # Prevent redefinition |
| |
| j = i # E: Incompatible types in assignment (expression has type "I", variable has type "J") |
| a = i # E: Incompatible types in assignment (expression has type "I", variable has type "A") |
| a = j # E: Incompatible types in assignment (expression has type "J", variable has type "A") |
| i = o # E: Incompatible types in assignment (expression has type "object", variable has type "I") |
| j = o # E: Incompatible types in assignment (expression has type "object", variable has type "J") |
| |
| i = a |
| j = a |
| i = j |
| o = i |
| o = j |
| |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self): pass |
| class J(I): pass |
| class A(J): pass |
| [builtins fixtures/tuple.pyi] |
| |
| [case testInheritingAbstractClassInSubclass] |
| from abc import abstractmethod, ABCMeta |
| |
| i: I |
| a: A |
| b: B |
| |
| if int(): |
| i = a # E: Incompatible types in assignment (expression has type "A", variable has type "I") |
| if int(): |
| b = a # E: Incompatible types in assignment (expression has type "A", variable has type "B") |
| |
| if int(): |
| a = b |
| if int(): |
| i = b |
| |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self): pass |
| class A: pass |
| class B(A, I): pass |
| |
| |
| -- Abstract class objects |
| -- ---------------------- |
| |
| |
| [case testAbstractClassAsTypeObject] |
| |
| from abc import abstractmethod, ABCMeta |
| |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self): pass |
| |
| o: object |
| t: type |
| |
| o = I |
| t = I |
| |
| [case testAbstractClassInCasts] |
| from typing import cast |
| from abc import abstractmethod, ABCMeta |
| |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self): pass |
| class A(I): pass |
| class B: pass |
| |
| i: I |
| a: A |
| b: B |
| o: object |
| |
| if int(): |
| a = cast(I, o) # E: Incompatible types in assignment (expression has type "I", variable has type "A") |
| if int(): |
| b = cast(B, i) # Ok; a subclass of B might inherit I |
| if int(): |
| i = cast(I, b) # Ok; a subclass of B might inherit I |
| |
| if int(): |
| i = cast(I, o) |
| if int(): |
| i = cast(I, a) |
| [builtins fixtures/tuple.pyi] |
| |
| [case testInstantiatingClassThatImplementsAbstractMethod] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self): pass |
| class B(A): |
| def f(self): pass |
| B() |
| [out] |
| |
| [case testInstantiatingAbstractClass] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class A(metaclass=ABCMeta): pass |
| class B(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self): pass |
| A() # OK |
| B() # E: Cannot instantiate abstract class "B" with abstract attribute "f" |
| [out] |
| |
| [case testInstantiatingClassWithInheritedAbstractMethod] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self): pass |
| @abstractmethod |
| def g(self): pass |
| class B(A): pass |
| B() # E: Cannot instantiate abstract class "B" with abstract attributes "f" and "g" |
| [out] |
| |
| [case testInstantiationAbstractsInTypeForFunctions] |
| from typing import Type |
| from abc import abstractmethod |
| |
| class A: |
| @abstractmethod |
| def m(self) -> None: pass |
| class B(A): pass |
| class C(B): |
| def m(self) -> None: |
| pass |
| |
| def f(cls: Type[A]) -> A: |
| return cls() # OK |
| def g() -> A: |
| return A() # E: Cannot instantiate abstract class "A" with abstract attribute "m" |
| |
| f(A) # E: Only concrete class can be given where "Type[A]" is expected |
| f(B) # E: Only concrete class can be given where "Type[A]" is expected |
| f(C) # OK |
| x: Type[B] |
| f(x) # OK |
| [out] |
| |
| [case testAbstractTypeInADict] |
| from typing import Dict, Type |
| from abc import abstractmethod |
| |
| class Class: |
| @abstractmethod |
| def method(self) -> None: |
| pass |
| |
| my_dict_init: Dict[int, Type[Class]] = {0: Class} # E: Only concrete class can be given where "Tuple[int, Type[Class]]" is expected |
| |
| class Child(Class): |
| def method(self) -> None: ... |
| |
| other_dict_init: Dict[int, Type[Class]] = {0: Child} # ok |
| [builtins fixtures/dict.pyi] |
| [out] |
| |
| [case testInstantiationAbstractsInTypeForAliases] |
| from typing import Type |
| from abc import abstractmethod |
| |
| class A: |
| @abstractmethod |
| def m(self) -> None: pass |
| class B(A): pass |
| class C(B): |
| def m(self) -> None: |
| pass |
| |
| def f(cls: Type[A]) -> A: |
| return cls() # OK |
| |
| Alias = A |
| GoodAlias = C |
| Alias() # E: Cannot instantiate abstract class "A" with abstract attribute "m" |
| GoodAlias() |
| f(Alias) # E: Only concrete class can be given where "Type[A]" is expected |
| f(GoodAlias) |
| [out] |
| |
| [case testInstantiationAbstractsInTypeForVariables] |
| # flags: --no-strict-optional |
| from typing import Type |
| from abc import abstractmethod |
| |
| class A: |
| @abstractmethod |
| def m(self) -> None: pass |
| class B(A): pass |
| class C(B): |
| def m(self) -> None: |
| pass |
| |
| var: Type[A] |
| var() |
| if int(): |
| var = A # E: Can only assign concrete classes to a variable of type "Type[A]" |
| if int(): |
| var = B # E: Can only assign concrete classes to a variable of type "Type[A]" |
| if int(): |
| var = C # OK |
| |
| var_old = None # type: Type[A] # Old syntax for variable annotations |
| var_old() |
| if int(): |
| var_old = A # E: Can only assign concrete classes to a variable of type "Type[A]" |
| if int(): |
| var_old = B # E: Can only assign concrete classes to a variable of type "Type[A]" |
| if int(): |
| var_old = C # OK |
| [out] |
| |
| [case testInstantiationAbstractsInTypeForClassMethods] |
| from typing import Type |
| from abc import abstractmethod |
| |
| class Logger: |
| @staticmethod |
| def log(a: Type[C]): |
| pass |
| class C: |
| @classmethod |
| def action(cls) -> None: |
| cls() #OK for classmethods |
| Logger.log(cls) #OK for classmethods |
| @abstractmethod |
| def m(self) -> None: |
| pass |
| [builtins fixtures/classmethod.pyi] |
| [out] |
| |
| [case testInstantiatingClassWithInheritedAbstractMethodAndSuppression] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def a(self): pass |
| @abstractmethod |
| def b(self): pass |
| @abstractmethod |
| def c(self): pass |
| @abstractmethod |
| def d(self): pass |
| @abstractmethod |
| def e(self): pass |
| @abstractmethod |
| def f(self): pass |
| @abstractmethod |
| def g(self): pass |
| @abstractmethod |
| def h(self): pass |
| @abstractmethod |
| def i(self): pass |
| @abstractmethod |
| def j(self): pass |
| a = A() # E: Cannot instantiate abstract class "A" with abstract attributes "a", "b", ... and "j" (7 methods suppressed) |
| [out] |
| |
| |
| -- Implementing abstract methods |
| -- ----------------------------- |
| |
| |
| [case testImplementingAbstractMethod] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, x: int) -> int: pass |
| @abstractmethod |
| def g(self, x: int) -> int: pass |
| class B(A): |
| def f(self, x: str) -> int: \ |
| # E: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int" \ |
| # N: This violates the Liskov substitution principle \ |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides |
| return 0 |
| def g(self, x: int) -> int: return 0 |
| [out] |
| |
| [case testImplementingAbstractMethodWithMultipleBaseClasses] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, x: int) -> int: pass |
| class J(metaclass=ABCMeta): |
| @abstractmethod |
| def g(self, x: str) -> str: pass |
| class A(I, J): |
| def f(self, x: str) -> int: return 0 \ |
| # E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "int" \ |
| # N: This violates the Liskov substitution principle \ |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides |
| def g(self, x: str) -> int: return 0 \ |
| # E: Return type "int" of "g" incompatible with return type "str" in supertype "J" |
| def h(self) -> int: return 0 # Not related to any base class |
| [out] |
| |
| [case testImplementingAbstractMethodWithExtension] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class J(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, x: int) -> int: pass |
| class I(J): pass |
| class A(I): |
| def f(self, x: str) -> int: return 0 \ |
| # E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "int" \ |
| # N: This violates the Liskov substitution principle \ |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides |
| [out] |
| |
| [case testInvalidOverridingAbstractMethod] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class J(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, x: 'J') -> None: pass |
| class I(J): |
| @abstractmethod |
| def f(self, x: 'I') -> None: pass # E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "J" \ |
| # N: This violates the Liskov substitution principle \ |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides |
| [out] |
| |
| [case testAbstractClassCoAndContraVariance] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, a: A) -> 'I': pass |
| @abstractmethod |
| def g(self, a: A) -> 'I': pass |
| @abstractmethod |
| def h(self, a: 'I') -> A: pass |
| class A(I): |
| def h(self, a: 'A') -> 'I': # Fail |
| return A() |
| def f(self, a: 'I') -> 'I': |
| return A() |
| def g(self, a: 'A') -> 'A': |
| return A() |
| [out] |
| main:11: error: Return type "I" of "h" incompatible with return type "A" in supertype "I" |
| main:11: error: Argument 1 of "h" is incompatible with supertype "I"; supertype defines the argument type as "I" |
| main:11: note: This violates the Liskov substitution principle |
| main:11: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides |
| |
| |
| -- Accessing abstract members |
| -- -------------------------- |
| |
| |
| [case testAccessingAbstractMethod] |
| from abc import abstractmethod, ABCMeta |
| |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, a: int) -> str: pass |
| |
| i: I |
| a: int |
| b: str |
| |
| if int(): |
| a = i.f(a) # E: Incompatible types in assignment (expression has type "str", variable has type "int") |
| if int(): |
| b = i.f(b) # E: Argument 1 to "f" of "I" has incompatible type "str"; expected "int" |
| i.g() # E: "I" has no attribute "g" |
| |
| if int(): |
| b = i.f(a) |
| [builtins fixtures/tuple.pyi] |
| |
| [case testAccessingInheritedAbstractMethod] |
| from abc import abstractmethod, ABCMeta |
| |
| class J(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, a: int) -> str: pass |
| class I(J): pass |
| |
| i: I |
| a: int |
| b: str |
| |
| if int(): |
| a = i.f(1) # E: Incompatible types in assignment (expression has type "str", variable has type "int") |
| if int(): |
| b = i.f(1) |
| |
| |
| -- Any (dynamic) types |
| -- ------------------- |
| [builtins fixtures/tuple.pyi] |
| |
| |
| [case testAbstractClassWithAllDynamicTypes] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, x): pass |
| @abstractmethod |
| def g(self, x): pass |
| class A(I): |
| def f(self, x): pass |
| def g(self, x, y) -> None: pass # Fail |
| [out] |
| main:10: error: Signature of "g" incompatible with supertype "I" |
| main:10: note: Superclass: |
| main:10: note: def g(self, x: Any) -> Any |
| main:10: note: Subclass: |
| main:10: note: def g(self, x: Any, y: Any) -> None |
| |
| [case testAbstractClassWithAllDynamicTypes2] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, x): pass |
| @abstractmethod |
| def g(self, x): pass |
| class A(I): |
| def f(self, x): pass |
| def g(self, x, y): pass |
| [out] |
| |
| [case testAbstractClassWithImplementationUsingDynamicTypes] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class I(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, x: int) -> None: pass |
| @abstractmethod |
| def g(self, x: int) -> None: pass |
| class A(I): |
| def f(self, x): pass |
| def g(self, x, y): pass |
| [out] |
| |
| |
| -- Special cases |
| -- ------------- |
| |
| |
| [case testMultipleAbstractBases] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self) -> None: pass |
| class B(metaclass=ABCMeta): |
| @abstractmethod |
| def g(self) -> None: pass |
| class C(A, B): |
| @abstractmethod |
| def h(self) -> None: pass |
| |
| [case testMemberAccessWithMultipleAbstractBaseClasses] |
| |
| from abc import abstractmethod, ABCMeta |
| |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self) -> None: pass |
| class B(metaclass=ABCMeta): |
| @abstractmethod |
| def g(self) -> None: pass |
| class C(A, B): pass |
| x: C |
| x.f() |
| x.g() |
| x.f(x) # E: Too many arguments for "f" of "A" |
| x.g(x) # E: Too many arguments for "g" of "B" |
| |
| [case testInstantiatingAbstractClassWithMultipleBaseClasses] |
| |
| from abc import abstractmethod, ABCMeta |
| |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self) -> None: pass |
| class B(metaclass=ABCMeta): |
| @abstractmethod |
| def g(self) -> None: pass |
| class C(A, B): |
| def f(self) -> None: pass |
| class D(A, B): |
| def g(self) -> None: pass |
| class E(A, B): |
| def f(self) -> None: pass |
| def g(self) -> None: pass |
| C() # E: Cannot instantiate abstract class "C" with abstract attribute "g" |
| D() # E: Cannot instantiate abstract class "D" with abstract attribute "f" |
| E() |
| |
| [case testInconsistentMro] |
| from abc import abstractmethod, ABCMeta |
| import typing |
| |
| class A(metaclass=ABCMeta): pass |
| class B(object, A): pass \ |
| # E: Cannot determine consistent method resolution order (MRO) for "B" |
| |
| [case testOverloadedAbstractMethod] |
| from foo import * |
| [file foo.pyi] |
| from abc import abstractmethod, ABCMeta |
| from typing import overload |
| |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| @overload |
| def f(self, x: int) -> int: pass |
| @abstractmethod |
| @overload |
| def f(self, x: str) -> str: pass |
| |
| class B(A): |
| @overload |
| def f(self, x: int) -> int: pass |
| @overload |
| def f(self, x: str) -> str: pass |
| A() # E: Cannot instantiate abstract class "A" with abstract attribute "f" |
| B() |
| B().f(1) |
| a = B() # type: A |
| a.f(1) |
| a.f('') |
| a.f(B()) # E: No overload variant of "f" of "A" matches argument type "B" \ |
| # N: Possible overload variants: \ |
| # N: def f(self, x: int) -> int \ |
| # N: def f(self, x: str) -> str |
| |
| [case testOverloadedAbstractMethodWithAlternativeDecoratorOrder] |
| from foo import * |
| [file foo.pyi] |
| from abc import abstractmethod, ABCMeta |
| from typing import overload |
| |
| class A(metaclass=ABCMeta): |
| @overload |
| @abstractmethod |
| def f(self, x: int) -> int: pass |
| @overload |
| @abstractmethod |
| def f(self, x: str) -> str: pass |
| |
| class B(A): |
| @overload |
| def f(self, x: int) -> int: pass |
| @overload |
| def f(self, x: str) -> str: pass |
| A() # E: Cannot instantiate abstract class "A" with abstract attribute "f" |
| B() |
| B().f(1) |
| a = B() # type: A |
| a.f(1) |
| a.f('') |
| a.f(B()) # E: No overload variant of "f" of "A" matches argument type "B" \ |
| # N: Possible overload variants: \ |
| # N: def f(self, x: int) -> int \ |
| # N: def f(self, x: str) -> str |
| |
| [case testOverloadedAbstractMethodVariantMissingDecorator0] |
| from foo import * |
| [file foo.pyi] |
| from abc import abstractmethod, ABCMeta |
| from typing import overload |
| |
| class A(metaclass=ABCMeta): |
| @abstractmethod \ |
| # E: Overloaded method has both abstract and non-abstract variants |
| @overload |
| def f(self, x: int) -> int: pass |
| @overload |
| def f(self, x: str) -> str: pass |
| [out] |
| |
| [case testOverloadedAbstractMethodVariantMissingDecorator1] |
| from foo import * |
| [file foo.pyi] |
| from abc import abstractmethod, ABCMeta |
| from typing import overload |
| |
| class A(metaclass=ABCMeta): |
| @overload \ |
| # E: Overloaded method has both abstract and non-abstract variants |
| def f(self, x: int) -> int: pass |
| @abstractmethod |
| @overload |
| def f(self, x: str) -> str: pass |
| [out] |
| |
| [case testMultipleInheritanceAndAbstractMethod] |
| import typing |
| from abc import abstractmethod, ABCMeta |
| class A: |
| def f(self, x: str) -> None: pass |
| class B(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, x: str) -> None: pass |
| class C(A, B): pass |
| |
| [case testMultipleInheritanceAndAbstractMethod2] |
| import typing |
| from abc import abstractmethod, ABCMeta |
| class A: |
| def f(self, x: str) -> None: pass |
| class B(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self, x: int) -> None: pass |
| class C(A, B): pass |
| [out] |
| main:8: error: Definition of "f" in base class "A" is incompatible with definition in base class "B" |
| |
| [case testCallAbstractMethodBeforeDefinition] |
| import typing |
| from abc import abstractmethod, ABCMeta |
| class A(metaclass=ABCMeta): |
| def f(self) -> None: |
| self.g(1) # E: Argument 1 to "g" of "A" has incompatible type "int"; expected "str" |
| @abstractmethod |
| def g(self, x: str) -> None: pass |
| [out] |
| |
| [case testAbstractOperatorMethods1] |
| import typing |
| from abc import abstractmethod, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def __lt__(self, other: 'A') -> int: pass |
| @abstractmethod |
| def __gt__(self, other: 'A') -> int: pass |
| |
| [case testAbstractOperatorMethods2] |
| from typing import cast, Any |
| from abc import abstractmethod, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def __radd__(self, other: 'C') -> str: pass # Error |
| class B: |
| @abstractmethod |
| def __add__(self, other: 'A') -> int: pass |
| class C: |
| def __add__(self, other: int) -> B: |
| return cast(Any, None) |
| [out] |
| |
| [case testAbstractClassWithAnyBase] |
| from typing import Any |
| from abc import abstractmethod, ABCMeta |
| |
| A: Any |
| |
| class D(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self) -> None: pass |
| |
| class C(A, D): |
| pass |
| |
| C() # A might implement 'f' |
| |
| |
| -- Abstract properties |
| -- ------------------- |
| |
| |
| [case testReadOnlyAbstractProperty] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| def f(a: A) -> None: |
| a.x() # E: "int" not callable |
| a.x = 1 # E: Property "x" defined in "A" is read-only |
| [out] |
| |
| [case testReadOnlyAbstractPropertyForwardRef] |
| from abc import abstractproperty, ABCMeta |
| def f(a: A) -> None: |
| a.x() # E: "int" not callable |
| a.x = 1 # E: Property "x" defined in "A" is read-only |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| [out] |
| |
| [case testReadWriteAbstractProperty] |
| from abc import abstractproperty, ABCMeta |
| def f(a: A) -> None: |
| a.x.y # E: "int" has no attribute "y" |
| a.x = 1 |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| @x.setter |
| def x(self, x: int) -> None: pass |
| |
| [case testReadWriteDeleteAbstractProperty] |
| # flags: --no-strict-optional |
| from abc import ABC, abstractmethod |
| class Abstract(ABC): |
| @property |
| @abstractmethod |
| def prop(self) -> str: ... |
| |
| @prop.setter |
| @abstractmethod |
| def prop(self, code: str) -> None: ... |
| |
| @prop.deleter |
| @abstractmethod |
| def prop(self) -> None: ... |
| |
| class Good(Abstract): |
| @property |
| def prop(self) -> str: ... |
| @prop.setter |
| def prop(self, code: str) -> None: ... |
| @prop.deleter |
| def prop(self) -> None: ... |
| |
| class Bad1(Abstract): |
| @property # E: Read-only property cannot override read-write property |
| def prop(self) -> str: ... |
| |
| class ThisShouldProbablyError(Abstract): |
| @property |
| def prop(self) -> str: ... |
| @prop.setter |
| def prop(self, code: str) -> None: ... |
| |
| a = Good() |
| reveal_type(a.prop) # N: Revealed type is "builtins.str" |
| a.prop = 123 # E: Incompatible types in assignment (expression has type "int", variable has type "str") |
| [builtins fixtures/property.pyi] |
| |
| [case testInstantiateClassWithReadOnlyAbstractProperty] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| class B(A): pass |
| b = B() # E: Cannot instantiate abstract class "B" with abstract attribute "x" |
| |
| [case testInstantiateClassWithReadWriteAbstractProperty] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| @x.setter |
| def x(self, x: int) -> None: pass |
| class B(A): pass |
| b = B() # E: Cannot instantiate abstract class "B" with abstract attribute "x" |
| |
| [case testImplementAbstractPropertyViaProperty] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| class B(A): |
| @property |
| def x(self) -> int: return 0 |
| b = B() |
| b.x() # E: "int" not callable |
| [builtins fixtures/property.pyi] |
| |
| [case testImplementReadWriteAbstractPropertyViaProperty] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| @x.setter |
| def x(self, v: int) -> None: pass |
| class B(A): |
| @property |
| def x(self) -> int: return 0 |
| @x.setter |
| def x(self, v: int) -> None: pass |
| b = B() |
| b.x.y # E: "int" has no attribute "y" |
| [builtins fixtures/property.pyi] |
| |
| [case testImplementAbstractPropertyViaPropertyInvalidType] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| class B(A): |
| @property |
| def x(self) -> str: return "no" # E: Signature of "x" incompatible with supertype "A" \ |
| # N: Superclass: \ |
| # N: int \ |
| # N: Subclass: \ |
| # N: str |
| b = B() |
| b.x() # E: "str" not callable |
| [builtins fixtures/property.pyi] |
| |
| [case testCantImplementAbstractPropertyViaInstanceVariable] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| class B(A): |
| def __init__(self) -> None: |
| self.x = 1 # E |
| b = B() # E |
| b.x.y # E |
| [builtins fixtures/property.pyi] |
| [out] |
| main:7: error: Property "x" defined in "A" is read-only |
| main:8: error: Cannot instantiate abstract class "B" with abstract attribute "x" |
| main:9: error: "int" has no attribute "y" |
| |
| [case testSuperWithAbstractProperty] |
| # flags: --no-strict-optional |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| class B(A): |
| @property |
| def x(self) -> int: |
| return super().x.y # E: "int" has no attribute "y" |
| [builtins fixtures/property.pyi] |
| [out] |
| |
| [case testSuperWithReadWriteAbstractProperty] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| @x.setter |
| def x(self, v: int) -> None: pass |
| class B(A): |
| @property |
| def x(self) -> int: |
| return super().x.y # E |
| @x.setter |
| def x(self, v: int) -> None: |
| super().x = '' # E |
| [builtins fixtures/property.pyi] |
| [out] |
| main:10: error: "int" has no attribute "y" |
| main:13: error: Invalid assignment target |
| |
| [case testOnlyImplementGetterOfReadWriteAbstractProperty] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self) -> int: pass |
| @x.setter |
| def x(self, v: int) -> None: pass |
| class B(A): |
| @property # E |
| def x(self) -> int: return 0 |
| b = B() |
| b.x.y # E |
| [builtins fixtures/property.pyi] |
| [out] |
| main:8: error: Read-only property cannot override read-write property |
| main:11: error: "int" has no attribute "y" |
| |
| [case testDynamicallyTypedReadOnlyAbstractProperty] |
| from abc import abstractproperty, ABCMeta |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self): pass |
| def f(a: A) -> None: |
| a.x.y |
| a.x = 1 # E: Property "x" defined in "A" is read-only |
| [out] |
| |
| [case testDynamicallyTypedReadOnlyAbstractPropertyForwardRef] |
| from abc import abstractproperty, ABCMeta |
| def f(a: A) -> None: |
| a.x.y |
| a.x = 1 # E: Property "x" defined in "A" is read-only |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self): pass |
| [out] |
| |
| [case testDynamicallyTypedReadWriteAbstractProperty] |
| from abc import abstractproperty, ABCMeta |
| def f(a: A) -> None: |
| a.x.y |
| a.x = 1 |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def x(self): pass |
| @x.setter |
| def x(self, x): pass |
| [out] |
| |
| [case testMixinTypedAbstractProperty] |
| from abc import ABCMeta, abstractproperty |
| class A(metaclass=ABCMeta): |
| @abstractproperty |
| def foo(cls) -> str: |
| pass |
| class Mixin: |
| foo = "foo" |
| class C(Mixin, A): |
| pass |
| [out] |
| |
| [case testMixinTypedProperty] |
| class A: |
| @property |
| def foo(cls) -> str: |
| return "yes" |
| class Mixin: |
| foo = "foo" |
| class C(Mixin, A): |
| pass |
| [builtins fixtures/property.pyi] |
| [out] |
| |
| [case testMixinSubtypedProperty] |
| class X: |
| pass |
| class Y(X): |
| pass |
| class A: |
| @property |
| def foo(cls) -> X: |
| return X() |
| class Mixin: |
| foo = Y() |
| class C(Mixin, A): |
| pass |
| [builtins fixtures/property.pyi] |
| [out] |
| |
| [case testMixinTypedPropertyReversed] |
| class A: |
| @property |
| def foo(cls) -> str: |
| return "no" |
| class Mixin: |
| foo = "foo" |
| class C(A, Mixin): # E: Definition of "foo" in base class "A" is incompatible with definition in base class "Mixin" |
| pass |
| [builtins fixtures/property.pyi] |
| [out] |
| |
| -- Special cases |
| -- ------------- |
| |
| |
| [case testNestedAbstractClass] |
| from abc import abstractmethod, ABCMeta |
| |
| class A: |
| class B(metaclass=ABCMeta): |
| @abstractmethod |
| def f(self) -> None: pass |
| |
| class C(B): pass |
| |
| A.B() # E: Cannot instantiate abstract class "B" with abstract attribute "f" |
| A.C() # E: Cannot instantiate abstract class "C" with abstract attribute "f" |
| |
| [case testAbstractNewTypeAllowed] |
| from typing import NewType, Mapping |
| |
| Config = NewType('Config', Mapping[str, str]) |
| |
| bad = Mapping[str, str]() # E: Cannot instantiate abstract class "Mapping" with abstract attribute "__iter__" |
| default = Config({'cannot': 'modify'}) # OK |
| |
| default[1] = 2 # E: Unsupported target for indexed assignment ("Config") |
| [builtins fixtures/dict.pyi] |
| [typing fixtures/typing-full.pyi] |
| |
| [case testSubclassOfABCFromDictionary] |
| from abc import abstractmethod, ABCMeta |
| |
| class MyAbstractType(metaclass=ABCMeta): |
| @abstractmethod |
| def do(self): pass |
| |
| class MyConcreteA(MyAbstractType): |
| def do(self): |
| print('A') |
| |
| class MyConcreteB(MyAbstractType): |
| def do(self): |
| print('B') |
| |
| class MyAbstractA(MyAbstractType): |
| @abstractmethod |
| def do(self): pass |
| |
| class MyAbstractB(MyAbstractType): |
| @abstractmethod |
| def do(self): pass |
| |
| my_concrete_types = { |
| 'A': MyConcreteA, |
| 'B': MyConcreteB, |
| } |
| |
| my_abstract_types = { |
| 'A': MyAbstractA, |
| 'B': MyAbstractB, |
| } |
| |
| reveal_type(my_concrete_types) # N: Revealed type is "builtins.dict[builtins.str, def () -> __main__.MyAbstractType]" |
| reveal_type(my_abstract_types) # N: Revealed type is "builtins.dict[builtins.str, def () -> __main__.MyAbstractType]" |
| |
| a = my_concrete_types['A']() |
| a.do() |
| b = my_concrete_types['B']() |
| b.do() |
| |
| c = my_abstract_types['A']() # E: Cannot instantiate abstract class "MyAbstractType" with abstract attribute "do" |
| c.do() |
| d = my_abstract_types['B']() # E: Cannot instantiate abstract class "MyAbstractType" with abstract attribute "do" |
| d.do() |
| |
| [builtins fixtures/dict.pyi] |
| |
| [case testAbstractClassesWorkWithGenericDecorators] |
| from abc import abstractmethod, ABCMeta |
| from typing import Type, TypeVar |
| |
| T = TypeVar("T") |
| def deco(cls: Type[T]) -> Type[T]: return cls |
| |
| @deco |
| class A(metaclass=ABCMeta): |
| @abstractmethod |
| def foo(self, x: int) -> None: ... |
| |
| [case testAbstractPropertiesAllowed] |
| from abc import abstractmethod |
| |
| class B: |
| @property |
| @abstractmethod |
| def x(self) -> int: ... |
| @property |
| @abstractmethod |
| def y(self) -> int: ... |
| @y.setter |
| @abstractmethod |
| def y(self, value: int) -> None: ... |
| |
| B() # E: Cannot instantiate abstract class "B" with abstract attributes "x" and "y" |
| b: B |
| b.x = 1 # E: Property "x" defined in "B" is read-only |
| b.y = 1 |
| [builtins fixtures/property.pyi] |
| |
| |
| -- Treatment of empty bodies in ABCs and protocols |
| -- ----------------------------------------------- |
| |
| [case testEmptyBodyProhibitedFunction] |
| from typing import overload, Union |
| |
| def func1(x: str) -> int: pass # E: Missing return statement |
| def func2(x: str) -> int: ... # E: Missing return statement |
| def func3(x: str) -> int: # E: Missing return statement |
| """Some function.""" |
| |
| @overload |
| def func4(x: int) -> int: ... |
| @overload |
| def func4(x: str) -> str: ... |
| def func4(x: Union[int, str]) -> Union[int, str]: # E: Missing return statement |
| pass |
| |
| @overload |
| def func5(x: int) -> int: ... |
| @overload |
| def func5(x: str) -> str: ... |
| def func5(x: Union[int, str]) -> Union[int, str]: # E: Missing return statement |
| """Some function.""" |
| |
| [case testEmptyBodyProhibitedMethodNonAbstract] |
| from typing import overload, Union |
| |
| class A: |
| def func1(self, x: str) -> int: pass # E: Missing return statement |
| def func2(self, x: str) -> int: ... # E: Missing return statement |
| def func3(self, x: str) -> int: # E: Missing return statement |
| """Some function.""" |
| |
| class B: |
| @classmethod |
| def func1(cls, x: str) -> int: pass # E: Missing return statement |
| @classmethod |
| def func2(cls, x: str) -> int: ... # E: Missing return statement |
| @classmethod |
| def func3(cls, x: str) -> int: # E: Missing return statement |
| """Some function.""" |
| |
| class C: |
| @overload |
| def func4(self, x: int) -> int: ... |
| @overload |
| def func4(self, x: str) -> str: ... |
| def func4(self, x: Union[int, str]) -> Union[int, str]: # E: Missing return statement |
| pass |
| |
| @overload |
| def func5(self, x: int) -> int: ... |
| @overload |
| def func5(self, x: str) -> str: ... |
| def func5(self, x: Union[int, str]) -> Union[int, str]: # E: Missing return statement |
| """Some function.""" |
| [builtins fixtures/classmethod.pyi] |
| |
| [case testEmptyBodyProhibitedPropertyNonAbstract] |
| class A: |
| @property |
| def x(self) -> int: ... # E: Missing return statement |
| @property |
| def y(self) -> int: ... # E: Missing return statement |
| @y.setter |
| def y(self, value: int) -> None: ... |
| |
| class B: |
| @property |
| def x(self) -> int: pass # E: Missing return statement |
| @property |
| def y(self) -> int: pass # E: Missing return statement |
| @y.setter |
| def y(self, value: int) -> None: pass |
| |
| class C: |
| @property |
| def x(self) -> int: # E: Missing return statement |
| """Some property.""" |
| @property |
| def y(self) -> int: # E: Missing return statement |
| """Some property.""" |
| @y.setter |
| def y(self, value: int) -> None: pass |
| [builtins fixtures/property.pyi] |
| |
| [case testEmptyBodyNoteABCMeta] |
| from abc import ABC |
| |
| class A(ABC): |
| def foo(self) -> int: # E: Missing return statement \ |
| # N: If the method is meant to be abstract, use @abc.abstractmethod |
| ... |
| |
| [case testEmptyBodyAllowedFunctionStub] |
| import stub |
| [file stub.pyi] |
| from typing import overload, Union |
| |
| def func1(x: str) -> int: pass |
| def func2(x: str) -> int: ... |
| def func3(x: str) -> int: |
| """Some function.""" |
| |
| [case testEmptyBodyAllowedMethodNonAbstractStub] |
| import stub |
| [file stub.pyi] |
| from typing import overload, Union |
| |
| class A: |
| def func1(self, x: str) -> int: pass |
| def func2(self, x: str) -> int: ... |
| def func3(self, x: str) -> int: |
| """Some function.""" |
| |
| class B: |
| @classmethod |
| def func1(cls, x: str) -> int: pass |
| @classmethod |
| def func2(cls, x: str) -> int: ... |
| @classmethod |
| def func3(cls, x: str) -> int: |
| """Some function.""" |
| [builtins fixtures/classmethod.pyi] |
| |
| [case testEmptyBodyAllowedPropertyNonAbstractStub] |
| import stub |
| [file stub.pyi] |
| class A: |
| @property |
| def x(self) -> int: ... |
| @property |
| def y(self) -> int: ... |
| @y.setter |
| def y(self, value: int) -> None: ... |
| |
| class B: |
| @property |
| def x(self) -> int: pass |
| @property |
| def y(self) -> int: pass |
| @y.setter |
| def y(self, value: int) -> None: pass |
| |
| class C: |
| @property |
| def x(self) -> int: |
| """Some property.""" |
| @property |
| def y(self) -> int: |
| """Some property.""" |
| @y.setter |
| def y(self, value: int) -> None: pass |
| [builtins fixtures/property.pyi] |
| |
| [case testEmptyBodyAllowedMethodAbstract] |
| from typing import overload, Union |
| from abc import abstractmethod |
| |
| class A: |
| @abstractmethod |
| def func1(self, x: str) -> int: pass |
| @abstractmethod |
| def func2(self, x: str) -> int: ... |
| @abstractmethod |
| def func3(self, x: str) -> int: |
| """Some function.""" |
| |
| class B: |
| @classmethod |
| @abstractmethod |
| def func1(cls, x: str) -> int: pass |
| @classmethod |
| @abstractmethod |
| def func2(cls, x: str) -> int: ... |
| @classmethod |
| @abstractmethod |
| def func3(cls, x: str) -> int: |
| """Some function.""" |
| |
| class C: |
| @overload |
| @abstractmethod |
| def func4(self, x: int) -> int: ... |
| @overload |
| @abstractmethod |
| def func4(self, x: str) -> str: ... |
| @abstractmethod |
| def func4(self, x: Union[int, str]) -> Union[int, str]: |
| pass |
| |
| @overload |
| @abstractmethod |
| def func5(self, x: int) -> int: ... |
| @overload |
| @abstractmethod |
| def func5(self, x: str) -> str: ... |
| @abstractmethod |
| def func5(self, x: Union[int, str]) -> Union[int, str]: |
| """Some function.""" |
| [builtins fixtures/classmethod.pyi] |
| |
| [case testEmptyBodyAllowedPropertyAbstract] |
| from abc import abstractmethod |
| class A: |
| @property |
| @abstractmethod |
| def x(self) -> int: ... |
| @property |
| @abstractmethod |
| def y(self) -> int: ... |
| @y.setter |
| @abstractmethod |
| def y(self, value: int) -> None: ... |
| |
| class B: |
| @property |
| @abstractmethod |
| def x(self) -> int: pass |
| @property |
| @abstractmethod |
| def y(self) -> int: pass |
| @y.setter |
| @abstractmethod |
| def y(self, value: int) -> None: pass |
| |
| class C: |
| @property |
| @abstractmethod |
| def x(self) -> int: |
| """Some property.""" |
| @property |
| @abstractmethod |
| def y(self) -> int: |
| """Some property.""" |
| @y.setter |
| @abstractmethod |
| def y(self, value: int) -> None: pass |
| [builtins fixtures/property.pyi] |
| |
| [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: ... |
| 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 testEmptyBodyUnsafeAbstractSuper] |
| from stub import StubProto, StubAbstract |
| from typing import Protocol |
| from abc import abstractmethod |
| |
| class Proto(Protocol): |
| def meth(self) -> int: ... |
| class ProtoDef(Protocol): |
| def meth(self) -> int: return 0 |
| |
| class Abstract: |
| @abstractmethod |
| def meth(self) -> int: ... |
| class AbstractDef: |
| @abstractmethod |
| def meth(self) -> int: return 0 |
| |
| class SubProto(Proto): |
| def meth(self) -> int: |
| return super().meth() # E: Call to abstract method "meth" of "Proto" with trivial body via super() is unsafe |
| class SubProtoDef(ProtoDef): |
| def meth(self) -> int: |
| return super().meth() |
| |
| class SubAbstract(Abstract): |
| def meth(self) -> int: |
| return super().meth() # E: Call to abstract method "meth" of "Abstract" with trivial body via super() is unsafe |
| class SubAbstractDef(AbstractDef): |
| def meth(self) -> int: |
| return super().meth() |
| |
| class SubStubProto(StubProto): |
| def meth(self) -> int: |
| return super().meth() |
| class SubStubAbstract(StubAbstract): |
| def meth(self) -> int: |
| return super().meth() |
| |
| [file stub.pyi] |
| from typing import Protocol |
| from abc import abstractmethod |
| |
| class StubProto(Protocol): |
| def meth(self) -> int: ... |
| class StubAbstract: |
| @abstractmethod |
| def meth(self) -> int: ... |
| |
| [case testEmptyBodyUnsafeAbstractSuperProperty] |
| from stub import StubProto, StubAbstract |
| from typing import Protocol |
| from abc import abstractmethod |
| |
| class Proto(Protocol): |
| @property |
| def attr(self) -> int: ... |
| class SubProto(Proto): |
| @property |
| def attr(self) -> int: return super().attr # E: Call to abstract method "attr" of "Proto" with trivial body via super() is unsafe |
| |
| class ProtoDef(Protocol): |
| @property |
| def attr(self) -> int: return 0 |
| class SubProtoDef(ProtoDef): |
| @property |
| def attr(self) -> int: return super().attr |
| |
| class Abstract: |
| @property |
| @abstractmethod |
| def attr(self) -> int: ... |
| class SubAbstract(Abstract): |
| @property |
| @abstractmethod |
| def attr(self) -> int: return super().attr # E: Call to abstract method "attr" of "Abstract" with trivial body via super() is unsafe |
| |
| class AbstractDef: |
| @property |
| @abstractmethod |
| def attr(self) -> int: return 0 |
| class SubAbstractDef(AbstractDef): |
| @property |
| @abstractmethod |
| def attr(self) -> int: return super().attr |
| |
| class SubStubProto(StubProto): |
| @property |
| def attr(self) -> int: return super().attr |
| class SubStubAbstract(StubAbstract): |
| @property |
| def attr(self) -> int: return super().attr |
| |
| [file stub.pyi] |
| from typing import Protocol |
| from abc import abstractmethod |
| |
| class StubProto(Protocol): |
| @property |
| def attr(self) -> int: ... |
| class StubAbstract: |
| @property |
| @abstractmethod |
| def attr(self) -> int: ... |
| [builtins fixtures/property.pyi] |
| |
| [case testEmptyBodyUnsafeAbstractSuperOverloads] |
| from stub import StubProto |
| from typing import Protocol, overload, Union |
| |
| class ProtoEmptyImpl(Protocol): |
| @overload |
| def meth(self, x: str) -> str: ... |
| @overload |
| def meth(self, x: int) -> int: ... |
| def meth(self, x: Union[int, str]) -> Union[int, str]: |
| raise NotImplementedError |
| class ProtoDefImpl(Protocol): |
| @overload |
| def meth(self, x: str) -> str: ... |
| @overload |
| def meth(self, x: int) -> int: ... |
| def meth(self, x: Union[int, str]) -> Union[int, str]: |
| return 0 |
| class ProtoNoImpl(Protocol): |
| @overload |
| def meth(self, x: str) -> str: ... |
| @overload |
| def meth(self, x: int) -> int: ... |
| |
| class SubProtoEmptyImpl(ProtoEmptyImpl): |
| @overload |
| def meth(self, x: str) -> str: ... |
| @overload |
| def meth(self, x: int) -> int: ... |
| def meth(self, x: Union[int, str]) -> Union[int, str]: |
| return super().meth(0) # E: Call to abstract method "meth" of "ProtoEmptyImpl" with trivial body via super() is unsafe |
| class SubProtoDefImpl(ProtoDefImpl): |
| @overload |
| def meth(self, x: str) -> str: ... |
| @overload |
| def meth(self, x: int) -> int: ... |
| def meth(self, x: Union[int, str]) -> Union[int, str]: |
| return super().meth(0) |
| class SubStubProto(StubProto): |
| @overload |
| def meth(self, x: str) -> str: ... |
| @overload |
| def meth(self, x: int) -> int: ... |
| def meth(self, x: Union[int, str]) -> Union[int, str]: |
| return super().meth(0) |
| |
| # TODO: it would be good to also give an error in this case. |
| class SubProtoNoImpl(ProtoNoImpl): |
| @overload |
| def meth(self, x: str) -> str: ... |
| @overload |
| def meth(self, x: int) -> int: ... |
| def meth(self, x: Union[int, str]) -> Union[int, str]: |
| return super().meth(0) |
| |
| [file stub.pyi] |
| from typing import Protocol, overload |
| |
| class StubProto(Protocol): |
| @overload |
| def meth(self, x: str) -> str: ... |
| @overload |
| def meth(self, x: int) -> int: ... |
| |
| [builtins fixtures/exception.pyi] |
| |
| [case testEmptyBodyNoSuperWarningWithoutStrict] |
| # flags: --no-strict-optional |
| from typing import Protocol |
| from abc import abstractmethod |
| |
| class Proto(Protocol): |
| def meth(self) -> int: ... |
| class Abstract: |
| @abstractmethod |
| def meth(self) -> int: ... |
| |
| class SubProto(Proto): |
| def meth(self) -> int: |
| return super().meth() |
| class SubAbstract(Abstract): |
| def meth(self) -> int: |
| return super().meth() |
| |
| [case testEmptyBodyNoSuperWarningOptionalReturn] |
| from typing import Protocol, Optional |
| from abc import abstractmethod |
| |
| class Proto(Protocol): |
| def meth(self) -> Optional[int]: pass |
| class Abstract: |
| @abstractmethod |
| def meth(self) -> Optional[int]: pass |
| |
| class SubProto(Proto): |
| def meth(self) -> Optional[int]: |
| return super().meth() |
| class SubAbstract(Abstract): |
| def meth(self) -> Optional[int]: |
| return super().meth() |
| |
| [case testEmptyBodyTypeCheckingOnly] |
| from typing import TYPE_CHECKING |
| |
| class C: |
| if TYPE_CHECKING: |
| def dynamic(self) -> int: ... # OK |