summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_listcomps.py
diff options
context:
space:
mode:
authorCarl Meyer <carl@oddbird.net>2023-05-11 23:48:21 (GMT)
committerGitHub <noreply@github.com>2023-05-11 23:48:21 (GMT)
commitac66cc17f21653b66321b50d0a1f792982fca21f (patch)
tree7a9b4ac1d0b55e685748ed65597a4acaef0c03c9 /Lib/test/test_listcomps.py
parent37a5d256b97bc9d2a0ff445997fec851e328ebad (diff)
downloadcpython-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.py59
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 = """