Skip to content

Commit ed24ee4

Browse files
committed
more tests
1 parent 9f2c07d commit ed24ee4

2 files changed

Lines changed: 113 additions & 0 deletions

File tree

‎Lib/test/test_listcomps.py‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,34 @@ def g(n):
530530
self.assertEqual(g.__code__.co_cellvars, ("x",))
531531
self.assertEqual([fn() for fn in g(2)[1]], [1, 1])
532532

533+
def test_nested_inlined_async_comp_iter_var_is_fast_local(self):
534+
import asyncio
535+
536+
async def agen(n):
537+
for i in range(n):
538+
yield i
539+
540+
async def f(n):
541+
return [[x async for _ in agen(2)] async for x in agen(n)]
542+
543+
self.assertEqual(f.__code__.co_cellvars, ())
544+
self.assertEqual(asyncio.run(f(2)), [[0, 0], [1, 1]])
545+
546+
async def g(n):
547+
return [[(lambda: x) async for _ in agen(2)] async for x in agen(n)]
548+
549+
self.assertEqual(g.__code__.co_cellvars, ("x",))
550+
out = asyncio.run(g(2))
551+
self.assertEqual([fn() for fn in out[1]], [1, 1])
552+
553+
def test_inlined_comprehension_name_mangling_in_method_scope(self):
554+
class C:
555+
def f(self):
556+
__x = 42
557+
return [__x for _ in (0,)]
558+
559+
self.assertEqual(C().f(), [42])
560+
533561
def test_nested_references___class__(self):
534562
code = """
535563
res = [[__class__ for _ in (0,)] for _ in (1,)]
@@ -914,6 +942,46 @@ def inner():
914942
{"snaps": [1, 2], "vals": [2, 2], "consistent": [True, True]},
915943
ns={"sys": sys}, scopes=["module", "function"])
916944

945+
def test_frame_locals_nested_comp_cell_and_enclosing_free(self):
946+
# Stress a nested inlined shape where a comp cell and enclosing free
947+
# share a name; all f_locals views must stay consistent.
948+
code = """
949+
def outer(x):
950+
def inner():
951+
return [(
952+
lambda: x,
953+
[[x for _ in (0,)] for _ in (0,)][0][0],
954+
dict(**sys._getframe().f_locals),
955+
len(sys._getframe().f_locals),
956+
list(sys._getframe().f_locals.keys()),
957+
list(sys._getframe().f_locals.values()),
958+
list(sys._getframe().f_locals.items()),
959+
dict(sys._getframe().f_locals.items()))
960+
for x in x]
961+
return inner()
962+
result = outer([1, 2])
963+
snaps = [d['x'] for _, _, d, *_ in result]
964+
vals = [fn() for fn, *_ in result]
965+
nested_vals = [nested for _, nested, *_ in result]
966+
consistent = []
967+
for _, _, d, n, ks, vs, it, d_items in result:
968+
consistent.append(
969+
n == len(ks) == len(vs) == len(it)
970+
and ks.count('x') == 1
971+
and d == d_items == dict(zip(ks, vs))
972+
)
973+
"""
974+
import sys
975+
self._check_in_scopes(
976+
code,
977+
{
978+
"snaps": [1, 2],
979+
"vals": [2, 2],
980+
"nested_vals": [1, 2],
981+
"consistent": [True, True],
982+
},
983+
ns={"sys": sys}, scopes=["module", "function"])
984+
917985
def _recursive_replace(self, maybe_code):
918986
if not isinstance(maybe_code, types.CodeType):
919987
return maybe_code

‎Lib/test/test_symtable.py‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,36 @@ def test_inlined_comprehension_use_of_enclosing_free_in_function(self):
558558
self.assertTrue(comp.lookup("x").is_free())
559559
self.assertTrue(comp.lookup("x").is_referenced())
560560

561+
def test_inlined_comprehension_use_of_nonlocal_in_function(self):
562+
st = symtable.symtable(
563+
"def outer():\n"
564+
" x = 1\n"
565+
" def inner():\n"
566+
" nonlocal x\n"
567+
" return [x for _ in ()]",
568+
"?", "exec")
569+
inner = find_block(find_block(st, "outer"), "inner")
570+
self.assertTrue(inner.lookup("x").is_nonlocal())
571+
self.assertTrue(inner.lookup("x").is_free())
572+
self.assertTrue(inner.lookup("x").is_referenced())
573+
comp, = inner.get_children()
574+
self.assertTrue(comp.lookup("x").is_free())
575+
self.assertTrue(comp.lookup("x").is_referenced())
576+
577+
def test_inlined_comprehension_use_of_explicit_global_in_function(self):
578+
st = symtable.symtable(
579+
"def f():\n"
580+
" global g\n"
581+
" return [g for _ in ()]",
582+
"?", "exec")
583+
f = find_block(st, "f")
584+
self.assertTrue(f.lookup("g").is_global())
585+
self.assertTrue(f.lookup("g").is_declared_global())
586+
self.assertFalse(f.lookup("g").is_referenced())
587+
comp, = f.get_children()
588+
self.assertTrue(comp.lookup("g").is_global())
589+
self.assertTrue(comp.lookup("g").is_referenced())
590+
561591
def test_inlined_comprehension_nested_function_use_not_on_enclosing(self):
562592
# The load of x is in the lambda's code object, not inner's.
563593
st = symtable.symtable(
@@ -661,6 +691,21 @@ def test_inlined_nested_comprehension_iter_var_is_fast_local(self):
661691
self.assertTrue(inner.lookup("x").is_free())
662692
self.assertTrue(inner.lookup("x").is_referenced())
663693

694+
def test_inlined_nested_mixed_comprehension_iter_var_is_referenced(self):
695+
st = symtable.symtable(
696+
"def f():\n"
697+
" return [{x for _ in (0,)} for x in (42,)]",
698+
"?", "exec")
699+
f = find_block(st, "f")
700+
with self.assertRaises(KeyError):
701+
f.lookup("x")
702+
outer, = f.get_children()
703+
self.assertTrue(outer.lookup("x").is_local())
704+
self.assertTrue(outer.lookup("x").is_referenced())
705+
inner, = outer.get_children()
706+
self.assertTrue(inner.lookup("x").is_free())
707+
self.assertTrue(inner.lookup("x").is_referenced())
708+
664709
def test_inlined_nested_comprehension_captured_iter_is_cell(self):
665710
st = symtable.symtable(
666711
"def f():\n"

0 commit comments

Comments
 (0)