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

All instances of types.GenericAlias are iterable on Python 3.11+ #103450

Closed
AlexWaygood opened this issue Apr 11, 2023 · 5 comments
Closed

All instances of types.GenericAlias are iterable on Python 3.11+ #103450

AlexWaygood opened this issue Apr 11, 2023 · 5 comments
Labels
3.11 only security fixes 3.12 bugs and security fixes topic-typing type-bug An unexpected behavior, bug, or error

Comments

@AlexWaygood
Copy link
Member

All generic aliases appear to be iterable on Python 3.11+, meaning you can do some fairly bizarre things that don't really make any sense:

>>> list(dict[int, int])
[*dict[int, int]]
>>> import collections.abc
>>> list(collections.abc.Generator[int, str, bytes])
[*collections.abc.Generator[int, str, bytes]]

This is due to the implementation of PEP 646 that was added in #31019 by @mrahtz. It was a deliberate decision at the time: 4aa94df is the commit in that PR branch that removes the restriction that only tuple can be unpacked (the commit was done in response to a review comment here: #31019 (comment)). However, there wasn't much discussion at the time.

Do we want to stick with this behaviour, on the basis that the runtime usually prefers to be lenient when it comes to typing constructs, leaving it to type checkers to point out invalid usage? Or should this be considered a bug?

@AlexWaygood AlexWaygood added type-bug An unexpected behavior, bug, or error 3.11 only security fixes topic-typing 3.12 bugs and security fixes labels Apr 11, 2023
@hauntsaninja
Copy link
Contributor

the runtime usually prefers to be lenient when it comes to typing constructs, leaving it to type checkers to point out invalid usage

I vote for this option!

@JelleZijlstra
Copy link
Member

My thinking at the time was that this could be useful for allowing something like tuple[*Iterable[int]], or something related to the TypeVarDict idea that was recently brought up on typing-sig. I don't see a need to forbid this again, especially since we've already had a series of releases allowing it.

@AlexWaygood
Copy link
Member Author

AlexWaygood commented Apr 11, 2023

It's probably not really a big deal, but one impact of this is that there's yet another way in which collections.abc.Callable and typing.Callable are slightly different from each other:

>>> import collections.abc, typing
>>> list(collections.abc.Callable[..., int])
[*collections.abc.Callable[..., int]]
>>> list(typing.Callable[..., int])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '_CallableGenericAlias' object is not iterable

@AlexWaygood AlexWaygood changed the title All generic aliases are iterable on Python 3.11+ All instances of types.GenericAlias are iterable on Python 3.11+ Apr 11, 2023
@sobolevn
Copy link
Member

@AlexWaygood yes, this happens because most of the typing constructs directly inherit from

class _NotIterable:
    """Mixin to prevent iteration, without being compatible with Iterable.

    That is, we could do:
        def __iter__(self): raise TypeError()
    But this would make users of this mixin duck type-compatible with
    collections.abc.Iterable - isinstance(foo, Iterable) would be True.

    Luckily, we can instead prevent iteration by setting __iter__ to None, which
    is treated specially.
    """

    __slots__ = ()
    __iter__ = None

@AlexWaygood
Copy link
Member Author

Seems like there's little appetite for changing this

@AlexWaygood AlexWaygood closed this as not planned Won't fix, can't repro, duplicate, stale Apr 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.11 only security fixes 3.12 bugs and security fixes topic-typing type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants