Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Lib/annotationlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__,
Expand Down
18 changes: 18 additions & 0 deletions Lib/test/test_annotationlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,24 @@ 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.
generic = ForwardRef("glob[int, undef]").evaluate(format=Format.FORWARDREF, globals={"glob": dict})
self.assertNotIsInstance(generic, ForwardRef)
self.assertIs(generic.__origin__, dict)
self.assertIs(generic.__args__[0], int)

generic = ForwardRef("loc[int, undef]").evaluate(format=Format.FORWARDREF, locals={"loc": dict})
self.assertNotIsInstance(generic, ForwardRef)
self.assertIs(generic.__origin__, dict)
self.assertIs(generic.__args__[0], int)

# Ensure that globals overwrite builtins
generic = ForwardRef("list[int, undef]").evaluate(format=Format.FORWARDREF, globals={"list": dict})
self.assertNotIsInstance(generic, ForwardRef)
self.assertIs(generic.__origin__, dict)
self.assertIs(generic.__args__[0], int)

def test_fwdref_invalid_syntax(self):
fr = ForwardRef("if")
with self.assertRaises(SyntaxError):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Partially evaluate undefined global generics in
:py:meth:`annotationlib.ForwardRef.evaluate`
Loading