-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
No type widening on generic self argument #10517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I think the current behavior is correct. The type of You could special-case @t.overload
def concat(self: "Stream[str]") -> "Stream[str]":
...
@t.overload
def concat(self: "Stream[t.Iterable[T]]") -> "Stream[T]":
...
def concat(self: "t.Union[Stream[t.Iterable[t.Any]], Stream[str]]") -> t.Any:
return Stream(concat(self)) I verified that this type checks fine in both mypy and pyright. |
Thanks @erictraut , that seems to work in this scenario. I'm not 100% sure why I didn't notice it earlier, but it appears that for the normal case (ie. not import typing as t
T = t.TypeVar('T')
class Stream(t.Generic[T]):
def __init__(self, it: t.Iterable[T]) -> None:
self.it = iter(it)
def __iter__(self) -> t.Iterator[T]:
return self.it
def concat(self: 'Stream[t.Iterable[T]]') -> 'Stream[T]':
return Stream([]) # todo
s = Stream([[1, 2, 3], [4, 5]])
reveal_type(s) # note: Revealed type is 't.Stream[builtins.list*[builtins.int]]'
reveal_type(s.concat()) # error: Invalid self argument "Stream[List[int]]" to attribute function "concat" with type "Callable[[Stream[Iterable[T]]], Stream[T]]"
# \note: Revealed type is 't.Stream[builtins.list*[builtins.int]]' Is this not supposed to work or am I still missing a crucial element? Replacing |
No, I wouldn't expect this to work. The problem is that I'm not quite sure what you're intending to do with this code. Normally "concat" involves concatenating one stream to another, so perhaps you intended for |
In addition to what Eric mentioned, your TypeVar is invariant, so a |
Ah, that makes more sense if it's a "flatten" operation. Perhaps this addresses your needs? import typing as t
T = t.TypeVar("T", covariant=True)
class Stream(t.Generic[T]):
def __init__(self, it: t.Iterable[T]) -> None:
self.it = iter(it)
def __iter__(self) -> t.Iterator[T]:
return self.it
@staticmethod
def flatten(s: "Stream[t.Iterable[T]]") -> "Stream[T]":
...
s = Stream([[1, 2, 3], [4, 5]])
reveal_type(s)
reveal_type(Stream.flatten(s)) |
Hey @erictraut , I'm back at this again 😄 Why does it have to be a staticmethod? Shouldn't this be considered a bug? In a way This behavior definitely seems odd to me (note how Mypy accepts it without import typing as t
T = t.TypeVar("T", covariant=True)
class Stream(t.Generic[T]):
def __init__(self, it: t.Iterable[T]) -> None:
self.it = iter(it)
def __iter__(self) -> t.Iterator[T]:
return self.it
def flatten(s: "Stream[t.Iterable[T]]") -> "Stream[T]":
...
s = Stream([[1, 2, 3], [4, 5]])
reveal_type(s) # Revealed type is "test.Stream[builtins.list*[builtins.int]]"
reveal_type(Stream.flatten(s)) # Revealed type is "test.Stream[builtins.int*]"
reveal_type(s.flatten()) # Revealed type is "test.Stream[builtins.list*[builtins.int]]" |
In your sample above, you're invoking an instance method on an object with a specialized type. The type of object Here's a simpler example that might make it clearer what I mean. Mypy does generate an error in this case. T = TypeVar("T")
class A(Generic[T]):
def foo(self: "A[int]"):
...
A[int]().foo() # No error
A[str]().foo() # Error: Could not bind method "foo" because "A[str]" is not assignable to parameter "self" An instance method will work here if you use a different type variable in that method — one that is scoped to T = t.TypeVar("T", covariant=True)
U = t.TypeVar("U", covariant=True)
class Stream(t.Generic[T]):
def __init__(self, it: t.Iterable[T]) -> None:
self.it = iter(it)
def __iter__(self) -> t.Iterator[T]:
return self.it
def flatten(self: "Stream[t.Iterable[U]]") -> "Stream[U]":
... |
Bug Report
Sorry for the bad title, I've tried to come up with something short and descriptive here.
The issue I am facing occurs when specializing the type of a
self
argument on a generic class.To Reproduce
Expected Behavior
I expect the
s.concat()
call to be accepted by MyPy.It actually works when you decorate the
self
argument witht.Iterable[t.Iterable[T]]
instead.Your Environment
mypy test.py
mypy.ini
(and other config files): n/aThe text was updated successfully, but these errors were encountered: