Description
Feature
A way for plugins to mark a metaclass as safely passing keyword arguments to __init_subclass__
.
Pitch
The current situation
Currently, if a class is inherited from that both has a custom metaclass and __init_subclass__
defined then there is no type checking done for the keyword arguments in __init_subclass__
. For example the following is an error:
class Base:
def __init_subclass__(cls, keyword: int = 0): ...
class Derived(Base, keyword='fail'): ...
error: Argument "keyword" to "__init_subclass__" of "Base" has incompatible type "str"; expected "int"
But this is not:
class Meta(type): ...
class Base(metaclass=Meta):
def __init_subclass__(cls, keyword: int = 0): ...
class Derived(Base, keyword='fail'): ...
The specifics around this are in #7723.
My issue
I have a base class that operates similar to dataclass
object. I have a plugin that provides the semantics to mypy already. However, this class uses a metaclass and __init_subclass__
and I would like type checking on the __init_subclass__
keyword arguments. The metaclass __new__
does not do anything with the keyword arguments but pass them along, so I know it's safe to do the type checking. I would like for my plugin to be able to tell mypy that this metaclass is safe.
Unfortunately I can't just get rid of the metaclass as it provides a class level __await__
.
My current solution is just to hack the TypeInfo._fullname
for the metaclass to be builtins.type
.
The solutions that come to mind would be either:
- A boolean on
TypeInfo
that says that the metaclass is__init_subclass__
safe (plugins just need to flip this in one of the existing hooks) - A way for plugins to manipulate the set of safe metaclasses that
Checker
uses (hook to customizeChecker
prior to run?)
I'm happy to do the work if a solution can be found.