Skip to content

mypy complains if itertools.chain.from_iterable is given an iterator, tuple, or list. #521

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

Closed
fgregg opened this issue Sep 3, 2016 · 10 comments

Comments

@fgregg
Copy link

fgregg commented Sep 3, 2016

chunks = ([1] * 3 for _ in range(10))
flattened = itertools.chain.from_iterable(chunks)

Is valid python code, but mypy throws this error:

error: Argument 1 to "from_iterable" of "chain" has incompatible type Iterator[Iterable[...]]; expected Iterable[Iterable[...]]
@gvanrossum
Copy link
Member

Hm... Maybe Iterable should be covariant?

On Saturday, September 3, 2016, Forest Gregg [email protected]
wrote:

chunks = ([1] * 3 for _ in range(10))
flattened = itertools.chain.from_iterable(chunks)

Is valid python code, but mypy throws this error:

error: Argument 1 to "from_iterable" of "chain" has incompatible type Iterator[Iterable[...]]; expected Iterable[Iterable[...]]


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#521, or mute the thread
https://github.com/notifications/unsubscribe-auth/ACwrMlsjou1jgo7_9WlbSPodSDHT-0zsks5qmcmqgaJpZM4J0YD3
.

--Guido (mobile)

@fgregg
Copy link
Author

fgregg commented Sep 3, 2016

Also failing:

> chunks = tuple([1] * 3 for _ in range(10))
> flattened = itertools.chain.from_iterable(chunks)
error: Argument 1 to "from_iterable" of "chain" has incompatible type Tuple[Iterable[...], ...]; expected Iterable[Iterable[...]]
> chunks = list([1] * 3 for _ in range(10))
> flattened = itertools.chain.from_iterable(chunks)
error: Argument 1 to "from_iterable" of "chain" has incompatible type List[Iterable[...]]; expected Iterable[Iterable[...]]

@fgregg fgregg changed the title mypy complains if itertools.chain.from_iterable is given an iterator. mypy complains if itertools.chain.from_iterable is given an iterator, tuple, or list. Sep 3, 2016
@gvanrossum
Copy link
Member

gvanrossum commented Sep 3, 2016 via email

@fgregg fgregg closed this as completed Sep 4, 2016
@fgregg
Copy link
Author

fgregg commented Sep 4, 2016

Here's code that reproduces the problem I ran into.

import itertools
from typing import Iterable, Sequence, Tuple

def flat_pairs(blocks : Iterable[Sequence[int]]) -> Iterable[Tuple[int, int]]:
    pairs = (itertools.combinations(block, 2) for block in blocks)
    return itertools.chain.from_iterable(pairs)

print(list(flat_pairs([[1, 2, 3], [4, 5, 6]])))

error: Argument 1 to "from_iterable" of "chain" has incompatible type Iterator[...]; expected Iterable[...]

mypy 0.4.4

@fgregg fgregg reopened this Sep 4, 2016
@gvanrossum
Copy link
Member

I can repro, and I've reduced it to:

from typing import *

def flat_pairs(pairs: Iterator[Sequence[int]]) -> Iterable[Tuple[int, int]]:
    return pairs

The type of pairs here is what is returned by the genexpr in your original repro.

The error message from mypy is about the return, and the reason is that Sequence[int] is not a subtype of Tuple[int, int].

That doesn't seem to be a bug in mypy or typeshed, but in your code (or in your expectations of how mypy would work).

Note that the error is the same if I change Iterator to Iterable, so that's not the reason either.

Also note that putting reveal_type() calls in various places will help show the exact type (in case the error message suppresses some of the type).

@fgregg
Copy link
Author

fgregg commented Sep 8, 2016

In my flat_pairs, if the function is given a iterable of sequences of integers it will return a iterable of 2-tuples of integers. This is not true of your flat_pairs

It does seem strange that I can't express that fact with typing and mypy. Strange things are often true, and I accept that it is my expectation that is buggy.

It would be very good to have documentation of what types of things are inexpressible.

@fgregg
Copy link
Author

fgregg commented Sep 8, 2016

It seems like the breakdown is in itertools.combinations(iterable, r) which produces an iterable of r-tuples. The current typeshed stub for combinations is:

def combinations(iterable: Iterable[_T], r: int) -> Iterable[Sequence[_T]]: ...

My expectations would be met if it was possible to do something like

def combinations(iterable: Iterable[_T], r: int) -> Iterable[Tuple[_T * r]]: ...

Where the n of the n-tuples in the return type depends upon r.

I can imagine why that would be quite difficult.

@gvanrossum
Copy link
Member

I think that would require a concept named "dependent types" where the
type of a return value (or another argument) depends on the value of an
argument. This is not something that can be expressed in PEP 484.

@fgregg
Copy link
Author

fgregg commented Sep 9, 2016

In documentation, itertool's product might be an excellent examples of how dependent types are not supported. This is a commonly used function that's easy to explain (slightly easier, I think, then combinations or permutations).

@gvanrossum
Copy link
Member

Opened python/mypy#2115

hswong3i pushed a commit to alvistack/python-typeshed that referenced this issue May 25, 2025
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

No branches or pull requests

2 participants