Reputation: 22660
Consider a simple pair of generic classes:
T = TypeVar("T", str, int)
class Base(Generic[T]):
def __init__(self, v: T):
self.v: T = v
@property
def value(self) -> T:
return self.v
class Child(Base[T]):
def __init__(self, v: T):
super().__init__(v)
x = Child(123)
reveal_type(x.value)
While using T = TypeVar("T")
works as expected. The restricted TypeVar
as shown yields the following errors:
error: Argument 1 to "__init__" of "Base" has incompatible type "str"; expected "T"
error: Argument 1 to "__init__" of "Base" has incompatible type "int"; expected "T"
note: Revealed type is 'builtins.int*'
Note that reveal_type
still works.
Another difference, is that the restricted TypeVar
requires the type annotation for self.v
assignment whereas the unrestricted does not.
In the full use-case, I actually have Callable[[Any], T]
, but the issue is the same.
This is with mypy 0.910
and Python 3.9.7
.
Upvotes: 6
Views: 2177
Reputation: 1920
Bounding T
to an Union[int,str]
should do the job:
T = TypeVar("T", bound=Union[str, int])
class Base(Generic[T]):
def __init__(self, v: T):
self.v: T = v
@property
def value(self) -> T:
return self.v
class Child(Base[T]):
def __init__(self, v: T):
super().__init__(v)
x = Child(123)
reveal_type(x.value)
y = Child('a')
reveal_type(y.value)
Upvotes: 2
Reputation: 4209
This seems to happen anytime you call super()
and pass the a generic restricted TypeVar
argument to any function not just init. On those cases, I believe we can ask mypy to leave this poor thing as it is, by including # type: ignore
in those lines:
...
super().__init__(v) # type: ignore
...
It is not so bad as it seems because type checking will still be done on other lines, differently of what would happen if you remove the : T
from the parameter on parent function or on the child function (any of those would suffice to suppress complains, but would also stop checking inside those functions as well).
Upvotes: 1