I have a Generic
base class that returns itself in one method (get_self
). I have type hinted it as such.
I then have a child class of that base class that passes in a type arg for the Generic
. In that child class, I call get_self
. I would like to update the type hint to just be the name of the child class.
However, mypy==0.782
is reporting error: Incompatible return value type (got "Foo[Bar]", expected "DFoo") [return-value]
. Is there some way to accomplish this?
**Edit**
I decided to re-explain the question upon further reflection. Sorry in advance for the verbosity.
- Base class (
Foo
) has a method (get_self
) type hinted to return an instance of itself - Child class (
DFoo
) does not override the method - Child class then uses the (
get_self
) method- And knows that the return type will actually be of the child class (
DFoo
)
- And knows that the return type will actually be of the child class (
- However, static type checkers (ex:
mypy
) do not know that the child class's method will actually return an object of the child class, as they are using the type hint from the base class
So my question may not be possible without re-declaring the method (get_self
) in the child class with a new type hint.
I could make the return of get_self
be a TypeVar
. However, since the base class Foo
is already a Generic
, that's currently not possible, because it would require the "Higher-Kinded TypeVars" mentioned in python/typing Higher-Kinded TypeVars #548.
Sample Script
I hope this clears up what I am trying to get at.
from __future__ import annotations
from typing import Generic, TypeVar, cast
T = TypeVar("T")
class Foo(Generic[T]):
def get_self(self) -> Foo[T]:
# Other stuff happens here before the return
return self
class Bar:
pass
class DFoo(Foo[Bar]):
def do_something_get_self(self) -> DFoo:
# mypy error: Incompatible return value type (got "Foo[Bar]",
# expected "DFoo")
return self.get_self()
class DFooCast(Foo[Bar]):
def do_something_get_self(self) -> DFooCast:
# This works, but I don't like this method. I don't want to use `cast`
# all over the place.
return cast(DFooCast, self.get_self())
class DFooNoUpdatedTypeHint(Foo[Bar]):
def do_something_get_self(self) -> Foo[Bar]:
# mypy doesn't error here, but later on it will raise an error
# when using method's added in Foo subclasses
return self.get_self()
def dfoo_adds_method(self) -> None:
"""DFoo also has additional methods."""
dfoo = DFooNoUpdatedTypeHint()
dfoo.do_something_get_self().dfoo_adds_method() # error: "Foo[Bar]" has no attribute "dfoo_adds_method"
And here is the complete mypy output:
path/to/ret_type_type_t_subclass.py: note: In member "do_something_get_self" of class "DFoo":
path/to/ret_type_type_t_subclass.py: error: Incompatible return value type (got "Foo[Bar]", expected "DFoo") [return-value]
path/to/ret_type_type_t_subclass.py: note: At top level:
path/to/ret_type_type_t_subclass.py: error: "Foo[Bar]" has no attribute "dfoo_adds_method" [attr-defined]
Versions
Python==3.8.5
mypy==0.782