[issue41370] PEP 585 and ForwardRef

Niklas Rosenstein report at bugs.python.org
Tue Jan 25 17:07:42 EST 2022


Niklas Rosenstein <rosensteinniklas at gmail.com> added the comment:

Interesting! Representing the entire type hint as a string is something I haven't thought about, but it makes sense that it works.

It is my understanding that `get_type_hint()` already walks through the entire type hint recursively. If it weren't, it would not resolve `List['N']` to `List[__main__.N]` in the example below.


>>> from typing import get_type_hints, Mapping, List
>>>
>>> class N:
...   a: Mapping['str', list[List['N']]]
...
>>> get_type_hints(N)
{'a': typing.Mapping[str, list[typing.List[__main__.N]]]}


Upon closer inspection of the `typing` code, I can see that `_eval_type()` is doing that recursion. Applying the change your proposed in your previous message to that function seems to work at least in a trivial test case.


diff --git a/Lib/typing.py b/Lib/typing.py
index e3e098b1fc..ac56b545b4 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -331,6 +331,12 @@ def _eval_type(t, globalns, localns, recursive_guard=frozenset()):
     if isinstance(t, ForwardRef):
         return t._evaluate(globalns, localns, recursive_guard)
     if isinstance(t, (_GenericAlias, GenericAlias, types.UnionType)):
+        if isinstance(t, GenericAlias):
+            args = tuple(
+                ForwardRef(arg) if isinstance(arg, str) else arg
+                for arg in t.__args__
+            )
+            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


Testcase:


>>> from typing import get_type_hints, Mapping, List
>>> class N:
...  a: Mapping['str', List[list['N']]]
...
>>> get_type_hints(N)
{'a': typing.Mapping[str, typing.List[list[__main__.N]]]}


I believe that this would be enough, but then again I haven't yet had enough time to crack at other implications this might have.


> How will it interact with from __future__ import annotations?

I've never used this future, but from my current, possibly limited, understanding it should have no side effects on how `get_type_hints()` will evaluate fully stringified annotations (as you have already shown, a fully stringified type hint actually works fine with PEP 585 generics).


> And can we sell this as a bugfix for 3.10, or will this be a new feature in 3.11?

I will throw in my personal opinion that this could be a bugfix, but I'm obviously biased as being on the "experiencing end" of this behaviour we're trying to change.

----------

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue41370>
_______________________________________


More information about the Python-bugs-list mailing list