You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Inconsistent Treatment of Class Constructor by Protocol #10482
In the code below we define one protocol which, when called, returns another. In effect we're describing a "factory". However, while MyPy is able to recognize incorrect protocol implementations when given a function, it fails to do the same for class constructors.
Hm, this is because in typeshed type.__call__ is annotated as returning (*Any, **Any) -> Any, making all class objects implementing arbitrary callback protocols. Mypy uses metaclass as a fallback for protocol implementation if implementation is a class object, so we will need to either tighten definition in typeshed, or ignore metaclass __call__ if constructor didn't match.
Problem is not much in what it takes, but in what it returns, it should be object, not Any. I guess this will fix 95% of relevant use cases. But maybe we can try ignoring __call__, it is just that it is a bit of pain, is_(proper)_subtype() already have like a dozen random flags, this will need one more. Unless, we just want to always skip __call__ on a metaclass (or only on builtins.type?)
Btw funny thing is that we have exactly a test like the original repro, but it passes, because we use test fixtures for most protocol tests, not full typeshed stubs.
@JelleZijlstra Hm, it looks like it didn't work (see mypy_primer). People often want to instantiate items in list of unrelated class objects. I guess we need to come up with some skipping/ignoring rules.
The return type being a protocol isn't important. I think that we should compare the signature of __init__ from the actual type object against the callable protocol, instead of type.__call__ from typeshed. I don't think that we can fix this in typeshed.
Activity
ilevkivskyi commentedon Nov 16, 2022
Hm, this is because in typeshed
type.__call__is annotated as returning(*Any, **Any) -> Any, making all class objects implementing arbitrary callback protocols. Mypy uses metaclass as a fallback for protocol implementation if implementation is a class object, so we will need to either tighten definition in typeshed, or ignore metaclass__call__if constructor didn't match.TBH I am not sure which one is better.
JelleZijlstra commentedon Nov 16, 2022
Typeshed is technically right there:
type.__call__takes arbitrary arguments (https://github.com/python/cpython/blob/5cfb7d19f5242c9b8ffd2fe30a24569e85a99e1d/Objects/typeobject.c#L1235). So it's probably best to handle this case specially in mypy.ilevkivskyi commentedon Nov 16, 2022
Problem is not much in what it takes, but in what it returns, it should be
object, notAny. I guess this will fix 95% of relevant use cases. But maybe we can try ignoring__call__, it is just that it is a bit of pain,is_(proper)_subtype()already have like a dozen random flags, this will need one more. Unless, we just want to always skip__call__on a metaclass (or only onbuiltins.type?)builtins: make type.__call__ return object
JelleZijlstra commentedon Nov 16, 2022
I see, opened python/typeshed#9215 to change it. Let's see if there's any negative effects.
ilevkivskyi commentedon Nov 16, 2022
Btw funny thing is that we have exactly a test like the original repro, but it passes, because we use test fixtures for most protocol tests, not full typeshed stubs.
ilevkivskyi commentedon Nov 16, 2022
@JelleZijlstra Hm, it looks like it didn't work (see
mypy_primer). People often want to instantiate items in list of unrelated class objects. I guess we need to come up with some skipping/ignoring rules.JukkaL commentedon Nov 16, 2022
The return type being a protocol isn't important. I think that we should compare the signature of
__init__from the actual type object against the callable protocol, instead oftype.__call__from typeshed. I don't think that we can fix this in typeshed.Another example:
Fix class objects falling back to metaclass for callback protocol (#1…