gh-104377: fix cell in comprehension that is free in outer scope (#104394)

This commit is contained in:
Carl Meyer 2023-05-11 17:48:21 -06:00 committed by GitHub
parent 37a5d256b9
commit ac66cc17f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 7 deletions

View file

@ -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 = """