All bases of a protocol must be protocols- is typing.MutableMapping not a Protocol?

615 Views Asked by At

I want to define a typing protocol for a custom mapping class. This class needs to be very similar to a MutableMapping, except that it has a couple of additional methods beyond those those that collections.abc.MutableMapping defines as abstract methods (specifically .copy()), and I also want to specify in advance which types any implementations of the custom mapping class must use as keys and values.

After reading through PEP 544 I thought I should be able to do this:

from typing import Hashable, MutableMapping, Protocol, TypeVar


TVarMapProt = TypeVar("TVarMapProt", bound="VariableMappingProtocol")


class VariableMappingProtocol(MutableMapping[Hashable, int], Protocol):
    """
    Protocol for the type behaviour of a class which
    acts basically like a dict of int objects.
    """

    def copy(self: TVarMapProt) -> TVarMapProt:
         # TODO replace return type with Self if PEP 673 goes through
        ...

The idea being that in my code I can state that a type VariableMappingProtocol is expected, and then the user would have to use their own class that was defined like this in order to avoid a typing error:

TCusVarMap = TypeVar("CusVarMap", bound="CustomVariableMapping")


class CustomVariableMapping
    """Defines all the methods that a MutableMapping does, but mapping Hashables to ints"""

    def __getitem__(self, key: Hashable) -> int:
        # implementation goes here
        ...

    # etc. for __setitem__, and so on...

    def copy(self) -> TCusVarMap:
        # implementation goes here
        ...

The problem is that when I run mypy on the code defining VariableMappingProtocol I get this error:

test.py:7: error: All bases of a protocol must be protocols
Found 1 error in 1 file (checked 1 source file)

If I delete MutableMapping so that VariableMappingProtocol only inherits from Protocol then the error goes away. But then I'm not getting the structural typing I want for all the abstract methods from MutableMapping.

So it seems the problem is that typing.MutableMapping is not considered a Protocol? But that's weird, especially as I can treat some of the other types in typing as Protocols, e.g. this example (from PEP 544)

from typing import Protocol, Sized


class SizedProtocol(Sized, Protocol):
    """
    Protocol for the type behaviour of a class which has a __len__ method.
    """
    ...

which doesn't throw any mypy errors.

How can I inherit from MutableMapping as a Protocol, and thus avoid the need to write out all the methods of MutableMapping in my VariableMappingProtocol definition?

0

There are 0 best solutions below