Skip to content
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

improve type for zip_longest #7655

Merged
merged 3 commits into from Apr 17, 2022
Merged

Conversation

JelleZijlstra
Copy link
Member

Our stub for zip_longest just returned Any for everything. This PR creates a
more precise stub inspired by that for zip(). I had to add additional
overloads to account for the fillvalue parameter.

@JelleZijlstra
Copy link
Member Author

Test case:

from itertools import zip_longest
from typing_extensions import assert_type

assert_type(list(zip_longest([1])), list[tuple[int]])
assert_type(list(zip_longest([1], fillvalue="x")), list[tuple[int]])

assert_type(list(zip_longest([1], ["x"])), list[tuple[int | None, str | None]])
assert_type(list(zip_longest([1], ["x"], fillvalue=1.5)), list[tuple[int | float, str | float]])

assert_type(list(zip_longest([1], ["x"], [1])), list[tuple[int | None, str | None, int | None]])
assert_type(list(zip_longest([1], ["x"], [1], fillvalue=1.5)), list[tuple[int | float, str | float, int | float]])

assert_type(list(zip_longest([1], ["x"], [1], ["x"])), list[tuple[int | None, str | None, int | None, str | None]])
assert_type(
    list(zip_longest([1], ["x"], [1], ["x"], fillvalue=1.5)), list[tuple[int | float, str | float, int | float, str | float]]
)

assert_type(
    list(zip_longest([1], ["x"], [1], ["x"], [1])), list[tuple[int | None, str | None, int | None, str | None, int | None]]
)
assert_type(
    list(zip_longest([1], ["x"], [1], ["x"], [1], fillvalue=1.5)),
    list[tuple[int | float, str | float, int | float, str | float, int | float]],
)

assert_type(list(zip_longest([1], ["x"], [1], ["x"], [1], ["x"])), list[tuple[int | str | None, ...]])
assert_type(list(zip_longest([1], ["x"], [1], ["x"], [1], ["x"], fillvalue=1.5)), list[tuple[int | str | float, ...]])

This passes pyright, but mypy infers list[Any] for all of them, probably because of a type context bug. I'll investigate that further.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

JelleZijlstra added a commit to JelleZijlstra/mypy that referenced this pull request Apr 17, 2022
Noticed in python/typeshed#7655 that it was incorrectly inferring list[Any]
in all cases. This is because I incorrectly put Any as the type context
in the assert_type implementation. Use the current context instead, like
for reveal_type().
@AlexWaygood
Copy link
Member

AlexWaygood commented Apr 17, 2022

If we take the rich hit as an example, it seems a little unfortunate:

for index, (word, next_word) in enumerate(
    zip_longest(words, words[1:])
):
    tokens.append(word)

Mypy thinks that word could be None here, because fillvalue hasn't been specified, so it assumes the Iterator will be yielding (str | None, str | None) tuples. But in actual fact, we know that word can only ever be str, as word will always be taken from the longer iterable.

This seems like pretty idiomatic usage of zip_longest :/

@JelleZijlstra
Copy link
Member Author

With python/mypy#12612 instead mypy passes my tests except for the last one, where it infers List[Tuple[object, ...]] because it uses a join instead of a union.

Looking at the mypy-primer output:

@github-actions
Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

kornia (https://github.com/kornia/kornia)
+ kornia/augmentation/container/image.py:331: error: Invalid index type "Union[str, Any]" for "List[ParamItem]"; expected type "SupportsIndex"  [index]
+ kornia/augmentation/container/image.py:340: error: Item "None" of "Union[ParamItem, Any, None]" has no attribute "data"  [union-attr]
+ kornia/augmentation/container/image.py:340: error: Argument 2 to "inverse" of "ImageSequential" has incompatible type "Union[Dict[Any, Any], List[Any], None, Any]"; expected "Optional[List[ParamItem]]"  [arg-type]
+ kornia/augmentation/container/augment.py:221: error: Invalid index type "Union[str, Any]" for "List[ParamItem]"; expected type "SupportsIndex"  [index]

@JelleZijlstra JelleZijlstra merged commit a24b765 into python:master Apr 17, 2022
@JelleZijlstra JelleZijlstra deleted the ziplongest branch April 17, 2022 22:49
hauntsaninja pushed a commit to python/mypy that referenced this pull request Apr 18, 2022
Noticed in python/typeshed#7655 that it was incorrectly inferring list[Any]
in all cases. This is because I incorrectly put Any as the type context
in the assert_type implementation. Use the current context instead, like
for reveal_type().
JukkaL pushed a commit to python/mypy that referenced this pull request Apr 20, 2022
Noticed in python/typeshed#7655 that it was incorrectly inferring list[Any]
in all cases. This is because I incorrectly put Any as the type context
in the assert_type implementation. Use the current context instead, like
for reveal_type().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants