Skip to content

Type annotation for map with abstract classes as values #3048

Closed
@sybrenstuvel

Description

@sybrenstuvel

Hello there,

I'm working on a framework with various storage backends. Those backends all implement an abstract base class. The backend classes are stored in a mapping from the backend name to the class implementing that backend.

We want to be able to perform type checking with mypy, and annotate as follows:

import abc
import typing


class A(metaclass=abc.ABCMeta):  # The abstract base class
    def __init__(self, name: str) -> None:
        self.name = name

    @abc.abstractmethod
    def get_name(self):
        pass


class B(A):  # Some non-abstract backend
    def get_name(self):
        return f'B: {self.name}'


class C(A):  # Another non-abstract backend
    def get_name(self):
        return f'C: {self.name}'


backends: typing.Mapping[str, typing.Type[A]] = {
    'backend-b': B,
    'backend-c': C,
}


if __name__ == '__main__':
    backend_cls = backends['backend-c']
    # The following line causes an error with mypy:
    instance = backend_cls('demo-name')
    print(f'Name is: {instance.get_name()}')

Running mypy-0.501 gives this error:

typingtest.py:32: error: Cannot instantiate abstract class 'A' with abstract attribute 'get_name'

My question: How can we annotate the mapping backends such that mypy understands it only contains non-abstract subclasses of A?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions