Repository navigation
Closed
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-typingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Bug description:
In typing._eval_type, generic aliases are reconstructed this way:
Lines 488 to 489 in e53d105
| 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
Metadata
Metadata
Assignees
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-typingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
sharktide commentedon Mar 5, 2025
I'll make a pr on this branch
pythongh-130870: Preserve `GenericAlias` subclasses in `typing.get_ty…
pythongh-130870: Preserve `GenericAlias` subclasses in `typing.get_ty…
pythongh-130870: Preserve `GenericAlias` subclasses in `typing.get_ty…
Add new test to test_typing.py to demonstrate fixed behaviour in pyth…
ZeroIntensity commentedon Jun 7, 2025
@Viicos How does this cause a problem in practice? Changing
get_type_hintsin 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 nicerrepr().Viicos commentedon Jun 8, 2025
collections.abc.Callableis such an example because the generic alias used is aGenericAliassubclass, but this can happen with anyGenericAliassubclass (for instance with Pydantic, where we are trying to see how to use aGenericAliassubclass for parameterized generic Pydantic models). With this bug, it won't be possible to use generic Pydantic models in forward annotations.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 commentedon Jun 8, 2025
I'm referring to the
_CallableGenericAliasinstance, 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 commentedon Jun 9, 2025
I just used this as an example to illustrate the bug.
_CallableGenericAliasis a private type, but subclassingGenericAliasis publicly documented and currently such aliases are lost during type evaluation intyping._eval_type()(relied on by the public functions such astyping.get_type_hints()). See also the added test in my PR.ZeroIntensity commentedon Jun 9, 2025
Hm, ok, that makes more sense. For clarity: how is your PR (#131583) different from the first PR (#130897)?
sharktide commentedon Jun 9, 2025
pythongh-130870: Preserve `GenericAlias` subclasses in `typing.get_ty…
gh-130870: Preserve `GenericAlias` subclasses in `typing.get_type_hin…
Viicos commentedon Jul 6, 2025
No backport required, so the issue along with the initial fix (#130897) can be closed.
pythongh-130870: Preserve `GenericAlias` subclasses in `typing.get_ty…
pythongh-130870: Preserve `GenericAlias` subclasses in `typing.get_ty…
pythongh-130870: Preserve `GenericAlias` subclasses in `typing.get_ty…
pythongh-130870: Preserve `GenericAlias` subclasses in `typing.get_ty…
pythongh-130870: Preserve `GenericAlias` subclasses in `typing.get_ty…