Skip to content

typing._eval_type is not preserving GenericAlias subclasses #130870

Closed
@Viicos

Description

@Viicos

Bug report

Bug description:

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

cpython/Lib/typing.py

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

No one assigned

    Labels

    stdlibPython modules in the Lib dirtopic-typingtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy