A minimal test case:
[case testClassMethod]
from typing import Generic, TypeVar
T = TypeVar("T", int, None)
class A(Generic[T]):
@classmethod
def func(cls, arg: int):
return cls(arg)
def __init__(self, arg: T):
self.attr = arg
[builtins fixtures/classmethod.pyi]
This gives an error complaining that cls(arg) expects None, due to it expanding the TypeVar on the class object.
Expected behaviour is that no error is produced, and that the type of cls does not have the expanded TypeVar (i.e. it should receive the same type that would be seen on a separate line of code like: a = A(5).
One catch to changing this behaviour is correct handling when subclassing with a defined type: #9456 (comment)
I've had a go at this, but was unable to figure out how to fix it. This is what I've figured out though:
https://github.com/python/mypy/blob/master/mypy/semanal.py#L641
Within prepare_method_signature(), cls gets changed from Any to the class type.
This is done by calling fill_typevars(), which results in the type including T, rather than just remaining as a TypeInfo (which appears to be the type in an example such as a = A(5)).
I've tried just removing the fill_typevars(), but then it runs into an unimplemented RuntimeError.
Because it includes T at this point, when it later tries to typecheck the code, it will check the class method twice, once as A[int] and again as A[None], which obviously throws the error we see.
So, it seems like there needs to be some way to stop class methods getting the TypeVars filled out on the cls argument.
A minimal test case:
This gives an error complaining that
cls(arg)expectsNone, due to it expanding the TypeVar on the class object.Expected behaviour is that no error is produced, and that the type of
clsdoes not have the expandedTypeVar(i.e. it should receive the same type that would be seen on a separate line of code like:a = A(5).One catch to changing this behaviour is correct handling when subclassing with a defined type: #9456 (comment)
I've had a go at this, but was unable to figure out how to fix it. This is what I've figured out though:
https://github.com/python/mypy/blob/master/mypy/semanal.py#L641
Within
prepare_method_signature(),clsgets changed fromAnyto the class type.This is done by calling
fill_typevars(), which results in the type includingT, rather than just remaining as aTypeInfo(which appears to be the type in an example such asa = A(5)).I've tried just removing the
fill_typevars(), but then it runs into an unimplementedRuntimeError.Because it includes
Tat this point, when it later tries to typecheck the code, it will check the class method twice, once asA[int]and again asA[None], which obviously throws the error we see.So, it seems like there needs to be some way to stop class methods getting the
TypeVars filled out on theclsargument.