Skip to content

Empty typing.Tuple #91137

Description

@serhiy-storchaka
BPO 46981
Nosy @gvanrossum, @serhiy-storchaka, @JelleZijlstra, @Fidget-Spinner
PRs
  • bpo-46981: Remove typing._TypingEmpty #31836
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2022-03-17.08:20:59.454>
    created_at = <Date 2022-03-11.08:21:12.398>
    labels = ['library', '3.11']
    title = 'Empty typing.Tuple'
    updated_at = <Date 2022-04-08.05:07:15.239>
    user = 'https://github.com/serhiy-storchaka'

    bugs.python.org fields:

    activity = <Date 2022-04-08.05:07:15.239>
    actor = 'JelleZijlstra'
    assignee = 'none'
    closed = True
    closed_date = <Date 2022-03-17.08:20:59.454>
    closer = 'serhiy.storchaka'
    components = ['Library (Lib)']
    creation = <Date 2022-03-11.08:21:12.398>
    creator = 'serhiy.storchaka'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 46981
    keywords = ['patch']
    message_count = 5.0
    messages = ['414892', '414947', '414986', '415391', '416958']
    nosy_count = 4.0
    nosy_names = ['gvanrossum', 'serhiy.storchaka', 'JelleZijlstra', 'kj']
    pr_nums = ['31836']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue46981'
    versions = ['Python 3.11']

    Activity

    1. serhiy-storchaka commented on Mar 11, 2022

      @serhiy-storchaka
      MemberAuthor

      There are two empty typing.Tuple. They have the same repr but are not equal.

      >>> from typing import *
      >>> t1 = Tuple[()]
      >>> t2 = t1.copy_with(())
      >>> t1
      typing.Tuple[()]
      >>> t2
      typing.Tuple[()]
      >>> t1 == t2
      False
      >>> t1.__args__
      ((),)
      >>> t2.__args__
      ()

      The only differences is that one has empty __args__, while other has __args__ containing an empty tuple. There is a code purposed to make __args__ containing an empty tuple in this case. What is the purpose?

      It is not pure theoretical question. This affects unpacked TypeVarTuple substitution. With natural implementation Tuple[Unpack[Ts]][()] is not equal to Tuple[()] and I still have not figured which and where code should be added to handle this special case. It would be easier if such special case did not exist.

      Built-in tuple does not have a special case:

      >>> tuple[()].__args__
      ()
    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      on Mar 11, 2022
    3. gvanrossum commented on Mar 11, 2022

      @gvanrossum
      Member

      Alas, I have no idea. I don't even recall what copy_with() is for (it was apparently introduced in 3.7). Possibly vopy_with() is wrong here? I imaging some of this has to do with the special casing needed so that repr() of an empty Tuple type doesn't print "Tuple[]" (which IIRC it did, long ago).

    4. serhiy-storchaka commented on Mar 12, 2022

      @serhiy-storchaka
      MemberAuthor

      If for repr(Tuple[()]), it is no longer needed.

    5. serhiy-storchaka commented on Mar 17, 2022

      @serhiy-storchaka
      MemberAuthor

      New changeset 15df8f8 by Serhiy Storchaka in branch 'main':
      bpo-46981: Remove typing._TypingEmpty (GH-31836)
      15df8f8

    6. JelleZijlstra commented on Apr 8, 2022

      @JelleZijlstra
      Member

      I tried out 3.11 on my pyanalyze type checker and got some failures because of this change, because my previous trick for distinguishing between Tuple and Tuple[()] failed.

      3.10:

      >>> from typing import get_args, Tuple
      >>> get_args(Tuple[()])
      ((),)
      >>> get_args(Tuple)
      ()

      3.11:

      >>> from typing import get_args, Tuple
      >>> get_args(Tuple[()])
      ()
      >>> get_args(Tuple)
      ()

      However, the new behavior is more consistent: get_args(tuple[()]) always returned (). It's also easy enough to work around (just check ... is Tuple).

      I'll put a note in the What's New for 3.11 about this change.

    7. transferred this issue fromon Apr 10, 2022
    8. serhiy-storchaka commented on Jun 25, 2022

      @serhiy-storchaka
      MemberAuthor

      We get a report about broken pickling of empty typing.Tuple #94245. Shallow and deep copying are broken too.

      >>> copy.copy(Tuple[()])
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/home/serhiy/py/cpython3.10/Lib/copy.py", line 102, in copy
          return _reconstruct(x, None, *rv)
        File "/home/serhiy/py/cpython3.10/Lib/copy.py", line 265, in _reconstruct
          y = func(*args)
        File "/home/serhiy/py/cpython3.10/Lib/typing.py", line 312, in inner
          return func(*args, **kwds)
        File "/home/serhiy/py/cpython3.10/Lib/typing.py", line 1233, in __getitem__
          params = tuple(_type_check(p, msg) for p in params)
        File "/home/serhiy/py/cpython3.10/Lib/typing.py", line 1233, in <genexpr>
          params = tuple(_type_check(p, msg) for p in params)
        File "/home/serhiy/py/cpython3.10/Lib/typing.py", line 176, in _type_check
          raise TypeError(f"{msg} Got {arg!r:.100}.")
      TypeError: Tuple[t0, t1, ...]: each t must be a type. Got ().
      >>> copy.deepcopy(Tuple[()])
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/home/serhiy/py/cpython3.10/Lib/copy.py", line 172, in deepcopy
          y = _reconstruct(x, memo, *rv)
        File "/home/serhiy/py/cpython3.10/Lib/copy.py", line 265, in _reconstruct
          y = func(*args)
        File "/home/serhiy/py/cpython3.10/Lib/typing.py", line 312, in inner
          return func(*args, **kwds)
        File "/home/serhiy/py/cpython3.10/Lib/typing.py", line 1233, in __getitem__
          params = tuple(_type_check(p, msg) for p in params)
        File "/home/serhiy/py/cpython3.10/Lib/typing.py", line 1233, in <genexpr>
          params = tuple(_type_check(p, msg) for p in params)
        File "/home/serhiy/py/cpython3.10/Lib/typing.py", line 176, in _type_check
          raise TypeError(f"{msg} Got {arg!r:.100}.")
      TypeError: Tuple[t0, t1, ...]: each t must be a type. Got ().
      

      All this can be fixed by backporting this change. But it will break pyanalyze.

    9. amitbad commented on Feb 20, 2024

      @amitbad

      I was using python 3.10 and getting the same error while using Gemini-Pro-Vision.

      This resolved my issue - pip install pydantic==1.10.13

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.11only security fixesstdlibStandard Library Python modules in the Lib/ directory

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions