Daniel Severo
Daniel Severo

Reputation: 1848

mypy issues with abstract classes and dictionaries

Greatings, consider the following code.

from abc import ABC, abstractmethod


class Interface(ABC):
    @abstractmethod
    def method(self) -> None:
        pass


class A(Interface):
    def method(self) -> None:
        pass


class B(Interface):
    def method(self) -> None:
        pass


mapping = {'A': A, 'B': B}


# does NOT pass mypy checks
def create_map(param: str) -> Interface:
    if param in mapping:
        return mapping[param]()
    else:
        raise NotImplementedError()

# passes mypy checks
def create_if(param: str) -> Interface:
    if param == 'A':
        return A()
    elif param == 'B':
        return B()
    else:
        raise NotImplementedError()

For some reason, create_if passes all mypy type checking, but create_map does not. The reveal_type for both functions is 'def (param: builtins.str) -> test.Interface'.

The error I get is the same as if I were trying to instantiate an abstract class directly, which is weird considering this reference for mypy.

error: Cannot instantiate abstract class 'Interface' with abstract attribute 'method'

Also, if I make mapping = {'A': A} (i.e. remove 'B': B) now create_map also passes.

Can someone shed some light on this?

Upvotes: 5

Views: 4718

Answers (1)

Daniel Severo
Daniel Severo

Reputation: 1848

Apparently all I was missing was the type annotation for the mapping.

mapping: Mapping[str, Type[Interface]] = {'A': A, 'B': B}

Thanks @jonafato

Credit to mypy issues 1843 and 3048 for showing this syntax.

Upvotes: 15

Related Questions