Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong Metaclass Conflict Error #17213

Open
gaotako opened this issue May 3, 2024 · 0 comments
Open

Wrong Metaclass Conflict Error #17213

gaotako opened this issue May 3, 2024 · 0 comments
Labels
bug mypy got something wrong

Comments

@gaotako
Copy link

gaotako commented May 3, 2024

Bug Report

I want to create a generic metaclass base which will automatically register all classes under it by their identifiers into a tracking dictionary of the metaclass.
Then, all the real metaclasses and base classes will inherit that, and can do this registration automatically and independently for each metaclass.
However, mypy raises an unexpected error.

from typing import Generic, Dict, TypeVar, Any, Type, cast


SelfProtoMeta = TypeVar("SelfProtoMeta", bound="ProtoMeta[Any]")
VartBase = TypeVar("VartBase", bound="Any")


class ProtoMeta(type, Generic[VartBase]):
    REGISTRY: Dict[str, VartBase]

    @staticmethod
    def __new__(
        cls: Type[SelfProtoMeta], /, *args: Any, **kwargs: Any
    ) -> Type[VartBase]:
        obj = cast(Type[VartBase], type.__new__(cls, *args, **kwargs))
        cls.registrate(obj)
        return obj

    @classmethod
    def registrate(cls: Type[SelfProtoMeta], obj: VartBase, /) -> None:
        pass


class ProtoBase(object, metaclass=ProtoMeta):
    IDENTIFIER: str


SelfMeta1 = TypeVar("SelfMeta1", bound="Meta1")


class Meta1(ProtoMeta["Base1"]):
    REGISTRY = {}

    @classmethod
    def registrate(cls: Type[SelfMeta1], obj: "Base1", /) -> None:
        cls.REGISTRY[obj.IDENTIFIER] = obj


class Base1(ProtoBase, metaclass=Meta1):
    IDENTIFIER = "base1"


assert issubclass(Meta1, type)
assert issubclass(Meta1, ProtoMeta)
assert issubclass(Base1, object)
assert issubclass(Base1, ProtoBase)
$ mypy yard.py --strict
yard.py:39: error: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases  [misc]
Found 1 error in 1 file (checked 1 source file)

I think the error message means that Meta1, the metaclass of Base1, is not a subclass of ProtoMeta, the metaclass of ProtoBase (parent of Base1).
But as you can see, I have verified that Meta1 is a subclass of ProtoMeta, so I don't think this error is raised (or reported) correctly.

To Reproduce

mypy yard.py --strict

Expected Behavior

No error should be raised, or a different error message should be raised.

Actual Behavior

Get unexpected error message: error: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases [misc].

Your Environment

  • Mypy version used: mypy 1.10.0 (compiled: yes)
  • Mypy command-line flags: --strict --verbose
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: Python 3.8.19
@gaotako gaotako added the bug mypy got something wrong label May 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

1 participant