diff options
author | Carl Meyer <carl@oddbird.net> | 2023-05-11 23:48:21 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-11 23:48:21 (GMT) |
commit | ac66cc17f21653b66321b50d0a1f792982fca21f (patch) | |
tree | 7a9b4ac1d0b55e685748ed65597a4acaef0c03c9 /Lib/test/test_listcomps.py | |
parent | 37a5d256b97bc9d2a0ff445997fec851e328ebad (diff) | |
download | cpython-ac66cc17f21653b66321b50d0a1f792982fca21f.zip cpython-ac66cc17f21653b66321b50d0a1f792982fca21f.tar.gz cpython-ac66cc17f21653b66321b50d0a1f792982fca21f.tar.bz2 |
gh-104377: fix cell in comprehension that is free in outer scope (#104394)
Diffstat (limited to 'Lib/test/test_listcomps.py')
-rw-r--r-- | Lib/test/test_listcomps.py | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 1cc202b..b2a3b7e 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -117,15 +117,15 @@ class ListComprehensionTest(unittest.TestCase): newcode = code def get_output(moddict, name): return moddict[name] - ns = ns or {} + newns = ns.copy() if ns else {} try: - exec(newcode, ns) + exec(newcode, newns) except raises as e: # We care about e.g. NameError vs UnboundLocalError self.assertIs(type(e), raises) else: for k, v in (outputs or {}).items(): - self.assertEqual(get_output(ns, k), v) + self.assertEqual(get_output(newns, k), v) def test_lambdas_with_iteration_var_as_default(self): code = """ @@ -180,6 +180,26 @@ class ListComprehensionTest(unittest.TestCase): z = [x() for x in items] """ outputs = {"z": [2, 2, 2, 2, 2]} + self._check_in_scopes(code, outputs, scopes=["module", "function"]) + + def test_cell_inner_free_outer(self): + code = """ + def f(): + return [lambda: x for x in (x, [1])[1]] + x = ... + y = [fn() for fn in f()] + """ + outputs = {"y": [1]} + self._check_in_scopes(code, outputs, scopes=["module", "function"]) + + def test_free_inner_cell_outer(self): + code = """ + g = 2 + def f(): + return g + y = [g for x in [1]] + """ + outputs = {"y": [2]} self._check_in_scopes(code, outputs) def test_inner_cell_shadows_outer_redefined(self): @@ -203,6 +223,37 @@ class ListComprehensionTest(unittest.TestCase): outputs = {"x": -1} self._check_in_scopes(code, outputs, ns={"g": -1}) + def test_explicit_global(self): + code = """ + global g + x = g + g = 2 + items = [g for g in [1]] + y = g + """ + outputs = {"x": 1, "y": 2, "items": [1]} + self._check_in_scopes(code, outputs, ns={"g": 1}) + + def test_explicit_global_2(self): + code = """ + global g + x = g + g = 2 + items = [g for x in [1]] + y = g + """ + outputs = {"x": 1, "y": 2, "items": [2]} + self._check_in_scopes(code, outputs, ns={"g": 1}) + + def test_explicit_global_3(self): + code = """ + global g + fns = [lambda: g for g in [2]] + items = [fn() for fn in fns] + """ + outputs = {"items": [2]} + self._check_in_scopes(code, outputs, ns={"g": 1}) + def test_assignment_expression(self): code = """ x = -1 @@ -250,7 +301,7 @@ class ListComprehensionTest(unittest.TestCase): g() """ outputs = {"x": 1} - self._check_in_scopes(code, outputs) + self._check_in_scopes(code, outputs, scopes=["module", "function"]) def test_introspecting_frame_locals(self): code = """ |