Skip to content

typing.get_type_hints() works for Callable[[], None] from the typing module, but not collections.abc #91621

Description

@Zac-HD

Bug report

typing.get_type_hints() works for Callable[[], None] from the typing module, but not collections.abc. This is the standard way to annotate a callable which takes no arguments, and the generic types from typing should behave identically to those in collections.abc.

import collections.abc
import typing

def f1(x: typing.Callable[[], None]):
    pass

def f2(x: collections.abc.Callable[[], None]):
    pass

assert "x" in typing.get_type_hints(f1)
typing.get_type_hints(f2)  # Raises TypeError!

Your environment

CPython 3.11.0a7 (and I believe back to a3), found via CI for Hypothesis, and reproduced in Ubuntu/WSL2 locally.
I'm skipping that test for now, and will re-enable when this is fixed.

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Apr 16, 2022
  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    3.11only security fixes
    on Apr 16, 2022
  3. AlexWaygood commented on Apr 16, 2022

    @AlexWaygood
    Member

    Reproduced, and I agree that this looks like a regression in 3.11. On 3.10:

    C:\Users\alexw\coding>python
    Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import typing, collections.abc
    >>> def f(x: collections.abc.Callable[[], None]): ...
    ...
    >>> typing.get_type_hints(f)
    {'x': collections.abc.Callable[[], None]}

    On 3.11:

    C:\Users\alexw\coding>python
    Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import typing, collections.abc
    >>> def f(x: collections.abc.Callable[[], None]): ...
    ...
    >>> typing.get_type_hints(f)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\Users\alexw\coding\cpython\Lib\typing.py", line 2277, in get_type_hints
        hints[name] = _eval_type(value, globalns, localns)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "C:\Users\alexw\coding\cpython\Lib\typing.py", line 353, in _eval_type
        t = t.__origin__[args]
            ~~~~~~~~~~~~^^^^^^
      File "<frozen _collections_abc>", line 430, in __new__
    TypeError: Callable must be used as Callable[[arg, ...], result].
  4. hauntsaninja commented on Apr 17, 2022

    @hauntsaninja
    Contributor

    Looks like this is a result of #30900 cc @NiklasRosenstein @JelleZijlstra

  5. hauntsaninja commented on Apr 17, 2022

    @hauntsaninja
    Contributor

    The complexity here traces back to some of the decisions made in https://bugs.python.org/issue42195

    We do this kind of thing a couple times in typing.py, I can open a PR:

    diff --git a/Lib/typing.py b/Lib/typing.py
    index 3e0fbdb989..af424c2109 100644
    --- a/Lib/typing.py
    +++ b/Lib/typing.py
    @@ -350,7 +350,11 @@ def _eval_type(t, globalns, localns, recursive_guard=frozenset()):
                     ForwardRef(arg) if isinstance(arg, str) else arg
                     for arg in t.__args__
                 )
    -            t = t.__origin__[args]
    +            if (t.__origin__ is collections.abc.Callable
    +                and not (len(args) == 2 and _is_param_expr(args[0]))):
    +                t = t.__origin__[(args[:-1], args[-1])]
    +            else:
    +                t = t.__origin__[args]
             ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)
             if ev_args == t.__args__:
                 return t
    
  6. Fidget-Spinner commented on Apr 17, 2022

    @Fidget-Spinner
    Member

    The complexity here traces back to some of the decisions made in https://bugs.python.org/issue42195

    We do this kind of thing a couple times in typing.py, I can open a PR:

    🤦 . Seeing this again, I'm sad that the special case has to exist. Unfortunately, this seems like an easy way to trip up new contributors. Please open a PR.

  7. added a commit that references this issue on Apr 18, 2022
  8. added a commit that references this issue on May 2, 2022
  9. JelleZijlstra commented on May 2, 2022

    @JelleZijlstra
    Member

    Thanks @Zac-HD for the pre-beta testing and @hauntsaninja for the patch!

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/ directorytopic-typingtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions