pythonpython-3.xmypystructural-typing

Python and mypy: creating a generic collection with typebound based on a Protocol


I'd like to create a generic container class, where the bounds on the type are based on implementing a protocol, like this:

class Nameable(Protocol):
    def name(self) -> str:
        ...


T = TypeVar("T", bound=Nameable)


class NameableList(Generic[T]):
   ...


class Foo:
    _name: str
    def name(self) -> str:
        return self._name


x = NameableList[Foo]

In doing this, mypy insists that Foo must be a subtype of Nameable -- which is not what I want (Foo just implements the Nameable protocol)

Any help would be appreciated.


Solution

  • As fas as I can see and understand this already does what you want.

    For example when I try

    y = NameableList[int]
    

    I get the following mypy error:

    protocols.py:22: error: Type argument "builtins.int" of "NameableList" must be a subtype of "Nameable"
    protocols.py:22: error: Value of type variable "T" of "NameableList" cannot be "int"
    Found 2 errors in 1 file (checked 1 source file)
    

    I.e. the generic allows Foo because it adheres to the protocol (not because it inherits from Nameable), but does not allow int because it does not.

    I'm using Python 3.9.2 and mypy==0.812. Perhaps you're using an older version which does not support this properly yet?