Consider the following scenario:
from dataclasses import dataclass
from typing import Generic, Protocol, TypeVar
T = TypeVar("T")
class HasFoo(Protocol):
foo: str
class Mixin(HasFoo):
foo = "test"
@dataclass()
class MyClass(Generic[T], Mixin):
t: T
If you execute this code, you get the following error:
Traceback (most recent call last):
File "/home/veith/.config/JetBrains/PyCharm2022.2/scratches/scratch_4.py", line 16, in <module>
class MyClass(Generic[T], FooMixin):
File "/home/veith/.pyenv/versions/3.8.3/lib/python3.8/abc.py", line 85, in __new__
cls = super().__new__(mcls, name, bases, namespace, **kwargs)
TypeError: Cannot create a consistent method resolution
order (MRO) for bases Generic, Mixin
Process finished with exit code 1
I guess this has something to do with the fact that Protocol can also take generic arguments like this:
class HasT(Protocol[T]):
t: T
# sugar for
class HasT(Protocol, Generic[T]):
t: T
# also works like this, which I would have expected to cause the same issue, but doesn't
class HasT(Generic[T], Protocol):
t: T
I could not find info on this in the PEP for protocols.
The answer to make it work is actually rather simple: Just reverse the order of inheritance in your code, so it looks like this:
@dataclass()
class MyClass(Mixin, Generic[T]):
t: T
So why is this happening, and why does it type-check using mypy 0.980?
The linked question does not answer my question about why it type-checks.
Generic inherits nothing, and Protocol inherits Generic.
So I see how the inheritance "tree" has a loop, but why does mypy not recognize this?