Closed
Description
Bug Report
Since mypy 0.990 I am getting a "Metaclass conflict" error for the definition of a class derived from a base class which uses a metaclass imported from a third-party library that doesn't provide type annotations.
To Reproduce
# Import metaclass from external module which doesn't provide type annotations
from mymodule import MyMeta
class Base(metaclass=MyMeta):
pass
# This generates the error: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases [misc]
class Derived(Base):
pass
# If there is type annotation for the metaclass, no issue.
class MyMeta2(type):
pass
class Base2(metaclass=MyMeta2):
pass
class Derived2(Base2):
pass
Also available as gist at: https://mypy-play.net/?mypy=latest&python=3.11&gist=6d41ba53b2226e3bef16df71554b10b1
Expected Behavior
No errors.
Actual Behavior
metaclass_conflict.py:10: error: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases [misc]
class Derived(Base):
^
Found 1 error in 1 file (checked 1 source file)
Your Environment
- Mypy version used: 0.911
- Mypy command-line flags:
- Mypy configuration options from
mypy.ini
(and other config files):show_error_codes = True ignore_missing_imports = True pretty = True
- Python version used: 3.8
More info
I tried some debugging and found out that:
- the error comes from the TypeChecker.check_metaclass_compatibility() method in
mypy/checker.py
- Using the reproducer example above, when mypy enters the
check_metaclass_compatibility()
method for the derived classes, the main difference betweenDerived
(which errors) andDerived2
(which doesn't) is thattyp.metaclass_type
isNone
in the first case (instead of the expectedMyMeta
) andMyMeta2
in the second (correctly). - This pointed me to look at the TypeInfo.calculate_metaclass_type() method in
mypy/nodes.py
. When run for theDerived
object, the only candidate metaclass isMyMeta
(correctly), but then this is excluded in the followingfor
loop becauseMyMeta.type.mro
is[]
(I supposed because it's missing type annotation).