Skip to content

Infer correct metaclass for protocols #13979

Open
@JukkaL

Description

@JukkaL

A subclass of Protocol is also an ABC:

import abc
from typing import Protocol

class P(Protocol):
    @abc.abstractmethod
    def f(self) -> None: pass

class C(P):
    pass

C()  # TypeError: Can't instantiate abstract class C with abstract method f

However, mypy doesn't detect a metaclass conflict here:

from typing import Protocol

class Meta(type): pass

# Metaclass conflict at runtime, but no mypy error
class P(Protocol, metaclass=Meta): pass

At runtime this will generate a metaclass conflict:

Traceback (most recent call last):
  File "/Users/jukka/src/mypy/t/t5.py", line 6, in <module>
    class P(Protocol, metaclass=Meta): pass
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

The actual metaclass is typing._ProtocolMeta:

>>> type(typing.Protocol)
<class 'typing._ProtocolMeta'>

Mypy should infer typing._ProtocolMeta as the metaclass of protocol classes. Maybe a custom metaclass should also be rejected, at least if it isn't a subclass of typing._ProtocolMeta.

More discussion here: python/typeshed#9058

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions