Skip to content

Commit 9166a87

Browse files
committed
fallback to using VALUE annotations instead of failing
1 parent c19bcbd commit 9166a87

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

Lib/annotationlib.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,8 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
671671
try:
672672
annotate(Format.VALUE_WITH_FAKE_GLOBALS)
673673
except NotImplementedError:
674-
raise
674+
# Both STRING and VALUE_WITH_FAKE_GLOBALS are not implemented fallback to VALUE
675+
return annotations_to_string(annotate(Format.VALUE))
675676
except Exception:
676677
pass
677678

@@ -734,9 +735,8 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
734735
try:
735736
result = func(Format.VALUE_WITH_FAKE_GLOBALS)
736737
except NotImplementedError:
737-
# If NotImplementedError is raised, don't try to call again with
738-
# no globals.
739-
raise
738+
# FORWARDREF and VALUE_WITH_FAKE_GLOBALS not supported, fall back to VALUE
739+
return annotate(Format.VALUE)
740740
except Exception:
741741
pass
742742
else:

Lib/test/test_annotationlib.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import itertools
99
import pickle
1010
from string.templatelib import Template
11+
import types
1112
import typing
1213
import unittest
1314
import unittest.mock
@@ -1248,30 +1249,49 @@ def test_user_annotate_value(self):
12481249
def test_user_annotate_forwardref(self):
12491250
annotate = self._annotate_mock()
12501251

1251-
with self.assertRaises(NotImplementedError):
1252+
new_annotate = None
1253+
functype = types.FunctionType
1254+
1255+
def functiontype(*args, **kwargs):
1256+
nonlocal new_annotate
1257+
new_func = unittest.mock.MagicMock(wraps=functype(*args, **kwargs))
1258+
new_annotate = new_func
1259+
return new_func
1260+
1261+
with unittest.mock.patch("types.FunctionType", new=functiontype):
12521262
annotations = annotationlib.call_annotate_function(
12531263
annotate,
12541264
Format.FORWARDREF,
12551265
)
12561266

1257-
# The annotate function itself is not called the second time
1258-
# A new function built from the code is called instead
1259-
annotate.assert_called_once_with(Format.FORWARDREF)
1267+
# The call with Format.VALUE_WITH_FAKE_GLOBALS is not
1268+
# on the original function.
1269+
annotate.assert_has_calls([
1270+
unittest.mock.call(Format.FORWARDREF),
1271+
unittest.mock.call(Format.VALUE),
1272+
])
1273+
1274+
new_annotate.assert_called_once_with(Format.VALUE_WITH_FAKE_GLOBALS)
1275+
1276+
self.assertEqual(annotations, {"x": str})
1277+
12601278

12611279
def test_user_annotate_string(self):
12621280
annotate = self._annotate_mock()
12631281

1264-
with self.assertRaises(NotImplementedError):
1265-
annotations = annotationlib.call_annotate_function(
1266-
annotate,
1267-
Format.STRING,
1268-
)
1282+
annotations = annotationlib.call_annotate_function(
1283+
annotate,
1284+
Format.STRING,
1285+
)
12691286

12701287
annotate.assert_has_calls([
12711288
unittest.mock.call(Format.STRING),
12721289
unittest.mock.call(Format.VALUE_WITH_FAKE_GLOBALS),
1290+
unittest.mock.call(Format.VALUE),
12731291
])
12741292

1293+
self.assertEqual(annotations, {"x": "str"})
1294+
12751295

12761296
class MetaclassTests(unittest.TestCase):
12771297
def test_annotated_meta(self):

0 commit comments

Comments
 (0)