Closed
Description
import abc
class MyAbstractType(metaclass=abc.ABCMeta):
@abc.abstractmethod
def do(self): pass
class MyConcreteA(MyAbstractType):
def do(self):
print('A')
class MyConcreteB(MyAbstractType):
def do(self):
print('B')
my_types = {
'A': MyConcreteA,
'B': MyConcreteB,
}
reveal_type(my_types) # Revealed type is 'builtins.dict[builtins.str*, def () -> test-abc.MyAbstractType]'
a = my_types['A']() # Cannot instantiate abstract class 'MyAbstractType' with abstract attribute 'do'
a.do()
b = my_types['B']() # Cannot instantiate abstract class 'MyAbstractType' with abstract attribute 'do'
b.do()
The above example does not pass the type check as-is.
I need to change it to pass the type check as follows:
import abc
from typing import Mapping, Type
class MyAbstractType(metaclass=abc.ABCMeta):
@abc.abstractmethod
def do(self): pass
class MyConcreteA(MyAbstractType):
def do(self):
print('A')
class MyConcreteB(MyAbstractType):
def do(self):
print('B')
my_types: Mapping[str, Type[MyAbstractType]] = { # explicit annotation
'A': MyConcreteA,
'B': MyConcreteB,
}
reveal_type(my_types) # Revealed type is 'typing.Mapping[builtins.str, Type[test-abc.MyAbstractType]]'
a = my_types['A']()
a.do()
b = my_types['B']()
b.do()
Since mypy is able to infer MyAbstractType
from the dictionary in the first snippet, I believe that it should be also able to infer Type[MyAbstractType]
since the dictionary values are not instances but class names.
My setup: Python 3.8.0 + mypy 0.750
Related issues/PRs:
- Error when choosing subclass of ABC from more than one option in a dictionary #5135 looks like a similar issue as the author did not use explicit annotation for the dictionaries.
- Allow instantiation of Type[A], if A is abstract #2853 allowed using explicit annotation above.