Labels
stdlibPython modules in the Lib dirtopic-typing type-bugAn unexpected behavior, bug, or error

Comments

@Viicos

Bug report

Bug description:

In typing._eval_type, generic aliases are reconstructed this way:

if isinstance(t, GenericAlias):
return GenericAlias(t.__origin__, ev_args)

As GenericAlias is subclassable, we can loose the actual subclass in some cases:

from typing import get_type_hints

from collections.abc import Callable

C = Callable[[str, 'int'], int]

C.__class__
#> <class 'collections.abc._CallableGenericAlias'>

C.__class__.__bases__
#> (<class 'types.GenericAlias'>,)

class A:
    c: C

hints = get_type_hints(A)
hints['c'].__class__
#> <class 'types.GenericAlias'>

I couldn't find a way to get actual bugs from it, but the repr is different:

hints['c']
#> collections.abc.Callable[str, int, int]
C
#> collections.abc.Callable[[str, 'int'], int]

The issue is also relevant for typing._strip_annotations().

Proposed fix

diff --git a/Lib/typing.py b/Lib/typing.py
index 4b3c63b25ae..25e0576839f 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -486,7 +486,9 @@ def _eval_type(t, globalns, localns, type_params=_sentinel, *, recursive_guard=f
         if ev_args == t.__args__:
             return t
         if isinstance(t, GenericAlias):
-            return GenericAlias(t.__origin__, ev_args)
+            if _should_unflatten_callable_args(t, ev_args):
+                return t.__class__(t.__origin__, (ev_args[:-1], ev_args[-1]))
+            return t.__class__(t.__origin__, ev_args)
         if isinstance(t, Union):
             return functools.reduce(operator.or_, ev_args)
         else:

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

@ViicosViicos added the type-bugAn unexpected behavior, bug, or errorlabel Mar 5, 2025
@sharktide

I'll make a pr on this branch

@ZeroIntensity

@Viicos How does this cause a problem in practice? Changing get_type_hints in this way will end up exposing implementation details, and I'm not sure it's worth the hassle if all we're after is getting a nicer repr().

@Viicos

collections.abc.Callable is such an example because the generic alias used is a GenericAlias subclass, but this can happen with any GenericAlias subclass (for instance with Pydantic, where we are trying to see how to use a GenericAlias subclass for parameterized generic Pydantic models). With this bug, it won't be possible to use generic Pydantic models in forward annotations.

Changing get_type_hints in this way will end up exposing implementation details

If you are referring to _should_unflatten_callable_args(), it is already there in the existing code. See my PR (the second one) for more details. I'll take a look at CI failures shortly.

@ZeroIntensity

If you are referring to _should_unflatten_callable_args(), it is already there in the existing code.

I'm referring to the _CallableGenericAlias instance, which isn't available or documented anywhere else. My concern is that we'll encouraging people to do introspection on the private API, which isn't fun for us when we want to change things. (But maybe this isn't a huge issue for typing?)

IMO, if you want this level of introspection, you should just use __annotations__ and parse things on your own. You're correctly opting in to extra maintenance by doing that.

@Viicos

I'm referring to the _CallableGenericAlias instance, which isn't available or documented anywhere else.

I just used this as an example to illustrate the bug. _CallableGenericAlias is a private type, but subclassing GenericAlias is publicly documented and currently such aliases are lost during type evaluation in typing._eval_type() (relied on by the public functions such as typing.get_type_hints()). See also the added test in my PR.

@ZeroIntensity

Hm, ok, that makes more sense. For clarity: how is your PR (#131583) different from the first PR (#130897)?

@sharktide

Viicos added a commit to Viicos/cpython that referenced this issue Jun 10, 2025
Sign up for free to join this conversation on . Already have an account? Sign in to comment
stdlibPython modules in the Lib dirtopic-typing type-bugAn unexpected behavior, bug, or error
None yet

No branches or pull requests