blob: 299074050baaf4575aea374547cca1dffd34d28a [file] [log] [blame] [edit]
-- 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