From e6f609a2cb9cd8ddf839c6c11e99726157f1dd4f Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 5 Jul 2025 06:56:23 -0700 Subject: [PATCH 1/2] gh-136316: Make typing.evaluate_forward_ref better at evaluating nested forwardrefs --- Lib/test/test_typing.py | 6 ++++++ Lib/typing.py | 12 +++++++++--- .../2025-07-05-06-56-16.gh-issue-136316.3zj_Do.rst | 2 ++ 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-07-05-06-56-16.gh-issue-136316.3zj_Do.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ef02e8202fc829..30e1827435881d 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7327,6 +7327,12 @@ def test_partial_evaluation(self): list[EqualToForwardRef('A')], ) + def test_with_module(self): + from test.typinganndata import fwdref_module + + typing.evaluate_forward_ref( + fwdref_module.fw,) + class CollectionsAbcTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py index ed1dd4fc6413a5..dc52f793eb1e37 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -430,7 +430,7 @@ def __repr__(self): def _eval_type(t, globalns, localns, type_params=_sentinel, *, recursive_guard=frozenset(), - format=None, owner=None): + format=None, owner=None, parent_fwdref=None): """Evaluate all forward references in the given type t. For use of globalns and localns see the docstring for get_type_hints(). @@ -451,7 +451,7 @@ def _eval_type(t, globalns, localns, type_params=_sentinel, *, recursive_guard=f if isinstance(t, (_GenericAlias, GenericAlias, Union)): if isinstance(t, GenericAlias): args = tuple( - _make_forward_ref(arg) if isinstance(arg, str) else arg + _make_forward_ref(arg, parent_fwdref=parent_fwdref) if isinstance(arg, str) else arg for arg in t.__args__ ) is_unpacked = t.__unpacked__ @@ -936,7 +936,12 @@ def run(arg: Child | Unrelated): return _GenericAlias(self, (item,)) -def _make_forward_ref(code, **kwargs): +def _make_forward_ref(code, *, parent_fwdref=None, **kwargs): + if parent_fwdref is not None: + if parent_fwdref.__forward_module__ is not None: + kwargs['module'] = parent_fwdref.__forward_module__ + if parent_fwdref.__owner__ is not None: + kwargs['owner'] = parent_fwdref.__owner__ forward_ref = _lazy_annotationlib.ForwardRef(code, **kwargs) # For compatibility, eagerly compile the forwardref's code. forward_ref.__forward_code__ @@ -1001,6 +1006,7 @@ def evaluate_forward_ref( recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, format=format, owner=owner, + parent_fwdref=forward_ref, ) diff --git a/Misc/NEWS.d/next/Library/2025-07-05-06-56-16.gh-issue-136316.3zj_Do.rst b/Misc/NEWS.d/next/Library/2025-07-05-06-56-16.gh-issue-136316.3zj_Do.rst new file mode 100644 index 00000000000000..dd5cecdf3a1209 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-05-06-56-16.gh-issue-136316.3zj_Do.rst @@ -0,0 +1,2 @@ +Improve support for evaluating nested forward references in +:func:`typing.evaluate_forward_ref`. From ca1a18f489bb20f6fb0f7bf68ad069220fbd86f1 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 5 Jul 2025 07:08:41 -0700 Subject: [PATCH 2/2] missing file --- Lib/test/typinganndata/fwdref_module.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Lib/test/typinganndata/fwdref_module.py diff --git a/Lib/test/typinganndata/fwdref_module.py b/Lib/test/typinganndata/fwdref_module.py new file mode 100644 index 00000000000000..7347a7a42455c2 --- /dev/null +++ b/Lib/test/typinganndata/fwdref_module.py @@ -0,0 +1,6 @@ +from typing import ForwardRef + +MyList = list[int] +MyDict = dict[str, 'MyList'] + +fw = ForwardRef('MyDict', module=__name__)