gh-156924: Try reifying lazy imports in `ForwarRef.evaluate()` (#156940) · python/cpython@52ffffe

GitHub

@@ -2179,6 +2179,118 @@ def test_evaluate_forwardref_format(self):

21792179support.EqualToForwardRef('"a" + 1'),

21802180 )

218121812182+deftest_evaluate_lazy_import(self):

2183+ns= {}

2184+exec(

2185+textwrap.dedent(

2186+"""

2187+ lazy from test.test_lazy_import.data.basic2 import x

2188+ lazy from test.test_lazy_import.data.broken_module import y

2189+2190+ class A:

2191+ a: x

2192+2193+ class B:

2194+ b: y

2195+ """

2196+ ),

2197+ns,

2198+ )

2199+self.addCleanup(

2200+import_helper.unload, "test.test_lazy_import.data.basic2"

2201+ )

2202+self.addCleanup(

2203+import_helper.unload, "test.test_lazy_import.data.broken_module"

2204+ )

2205+self.assertIs(type(ns["x"]), types.LazyImportType)

2206+self.assertIs(type(ns["y"]), types.LazyImportType)

2207+2208+# The lazy import resolves successfully:

2209+forformatin (Format.VALUE, Format.FORWARDREF):

2210+withself.subTest(format=format):

2211+self.assertEqual(

2212+ForwardRef("x").evaluate(globals=ns, format=format), 42

2213+ )

2214+self.assertEqual(

2215+ForwardRef("x").evaluate(locals=ns, format=format), 42

2216+ )

2217+self.assertEqual(

2218+get_annotations(ns["A"], format=Format.FORWARDREF), {"a": 42}

2219+ )

2220+2221+# The lazy import fails to resolve:

2222+fr=ForwardRef("y")

2223+withself.assertRaisesRegex(ValueError, "always fails to import"):

2224+fr.evaluate(globals=ns, format=Format.VALUE)

2225+withself.assertRaisesRegex(ValueError, "always fails to import"):

2226+fr.evaluate(locals=ns, format=Format.VALUE)

2227+self.assertIs(fr.evaluate(globals=ns, format=Format.FORWARDREF), fr)

2228+self.assertIs(fr.evaluate(locals=ns, format=Format.FORWARDREF), fr)

2229+2230+annos=get_annotations(ns["B"], format=Format.FORWARDREF)

2231+self.assertEqual(

2232+annos,

2233+ {"b": support.EqualToForwardRef("y", is_class=True, owner=ns["B"])},

2234+ )

2235+withself.assertRaisesRegex(ValueError, "always fails to import"):

2236+annos["b"].evaluate(format=Format.VALUE)

2237+withself.assertRaisesRegex(ValueError, "always fails to import"):

2238+get_annotations(ns["B"], format=Format.VALUE)

2239+2240+deftest_get_annotations_lazy_import(self):

2241+ns= {}

2242+exec(

2243+textwrap.dedent(

2244+"""

2245+ lazy from test.test_lazy_import.data.basic2 import x

2246+ lazy from test.test_lazy_import.data.broken_module import y

2247+2248+ class A:

2249+ a: object.fail

2250+ b: x

2251+2252+ class B:

2253+ a: object.fail

2254+ b: y

2255+ """

2256+ ),

2257+ns,

2258+ )

2259+self.addCleanup(

2260+import_helper.unload, "test.test_lazy_import.data.basic2"

2261+ )

2262+self.addCleanup(

2263+import_helper.unload, "test.test_lazy_import.data.broken_module"

2264+ )

2265+self.assertIs(type(ns["x"]), types.LazyImportType)

2266+self.assertIs(type(ns["y"]), types.LazyImportType)

2267+2268+annos=get_annotations(ns["A"], format=Format.FORWARDREF)

2269+self.assertEqual(

2270+annos,

2271+ {

2272+"a": support.EqualToForwardRef(

2273+"object.fail", is_class=True, owner=ns["A"]

2274+ ),

2275+"b": 42,

2276+ },

2277+ )

2278+2279+annos=get_annotations(ns["B"], format=Format.FORWARDREF)

2280+self.assertEqual(

2281+annos,

2282+ {

2283+"a": support.EqualToForwardRef(

2284+"object.fail", is_class=True, owner=ns["B"]

2285+ ),

2286+"b": support.EqualToForwardRef(

2287+"y", is_class=True, owner=ns["B"]

2288+ ),

2289+ },

2290+ )

2291+withself.assertRaisesRegex(ValueError, "always fails to import"):

2292+annos["b"].evaluate(format=Format.VALUE)

2293+21822294deftest_evaluate_notimplemented_format(self):

21832295classC:

21842296x: alias