Search code examples
pythonpython-3.xprotocolspython-typing

In Python issubclass() unexpectedly complains about "Protocols with non-method members"


I have tried the obvious way to check my protocol:

from typing import Any, Protocol, runtime_checkable

@runtime_checkable
class SupportsComparison(Protocol):
    def __eq__(self, other: Any) -> bool:
        ...

issubclass(int, SupportsComparison)

Unfortunately the issubclass() call ends with an exception (Python 3.10.6 in Ubuntu 22.04):

$ python3.10 protocol_test.py
Traceback (most recent call last):
  File "protocol_test.py", line 8, in <module>
    issubclass(object, SupportsComparison)
  File "/usr/lib/python3.10/abc.py", line 123, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
  File "/usr/lib/python3.10/typing.py", line 1570, in _proto_hook
    raise TypeError("Protocols with non-method members"
TypeError: Protocols with non-method members don't support issubclass()

As you can see I added no non-method members to SupportsComparison. Is this a bug in the standard library?


Solution

  • From the documentation:

    A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None.

    Therefore, in your case, you have the implicit non-method member SupportsComparison.__hash__ = None. You can fix it by declaring __hash__ explicitly:

    from typing import Any, Protocol, runtime_checkable
    
    @runtime_checkable
    class SupportsComparison(Protocol):
        def __eq__(self, other: Any) -> bool:
            ...
    
        def __hash__(self) -> int:
            ...
    
    issubclass(int, SupportsComparison)