[3.14] gh-138425: Correctly partially evaluate global generics with undefined params in ref.evaluate(format=Format.FORWARDREF) (GH-138430) (#140927)

gh-138425: Correctly partially evaluate global generics with undefined params in `ref.evaluate(format=Format.FORWARDREF)` (GH-138430)
(cherry picked from commit e66f87ca73)

Co-authored-by: dr-carlos <77367421+dr-carlos@users.noreply.github.com>
Co-authored-by: sobolevn <mail@sobolevn.me>
This commit is contained in:
Miss Islington (bot) 2025-11-03 00:41:49 +01:00 committed by GitHub
parent 7e1bac6a1a
commit 23e3771045
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 32 additions and 1 deletions

View file

@ -187,8 +187,11 @@ def evaluate(
except Exception:
if not is_forwardref_format:
raise
# All variables, in scoping order, should be checked before
# triggering __missing__ to create a _Stringifier.
new_locals = _StringifierDict(
{**builtins.__dict__, **locals},
{**builtins.__dict__, **globals, **locals},
globals=globals,
owner=owner,
is_class=self.__forward_is_class__,

View file

@ -1877,6 +1877,32 @@ def test_name_lookup_without_eval(self):
self.assertEqual(exc.exception.name, "doesntexist")
def test_evaluate_undefined_generic(self):
# Test the codepath where have to eval() with undefined variables.
class C:
x: alias[int, undef]
generic = get_annotations(C, format=Format.FORWARDREF)["x"].evaluate(
format=Format.FORWARDREF,
globals={"alias": dict}
)
self.assertNotIsInstance(generic, ForwardRef)
self.assertIs(generic.__origin__, dict)
self.assertEqual(len(generic.__args__), 2)
self.assertIs(generic.__args__[0], int)
self.assertIsInstance(generic.__args__[1], ForwardRef)
generic = get_annotations(C, format=Format.FORWARDREF)["x"].evaluate(
format=Format.FORWARDREF,
globals={"alias": Union},
locals={"alias": dict}
)
self.assertNotIsInstance(generic, ForwardRef)
self.assertIs(generic.__origin__, dict)
self.assertEqual(len(generic.__args__), 2)
self.assertIs(generic.__args__[0], int)
self.assertIsInstance(generic.__args__[1], ForwardRef)
def test_fwdref_invalid_syntax(self):
fr = ForwardRef("if")
with self.assertRaises(SyntaxError):

View file

@ -0,0 +1,2 @@
Fix partial evaluation of :class:`annotationlib.ForwardRef` objects which rely
on names defined as globals.