python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.52k stars 2.83k forks source link

metaclass/__init_subclass__ keyword checking #11057

Open esoma opened 3 years ago

esoma commented 3 years ago

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:

I'm happy to do the work if a solution can be found.

HimavarshaVS commented 1 year ago

I'm facing the above mentioned error because of __init__subclass. Curious if this has a solution ?