Skip to content

Commit 63c911b

Browse files
bpo-33346: Allow async comprehensions inside implicit asyns comprehensions.
1 parent 686b4b5 commit 63c911b

File tree

4 files changed

+73
-3
lines changed

4 files changed

+73
-3
lines changed

Lib/test/test_coroutines.py

+57
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ def __await__(self):
2727
yield self.value
2828

2929

30+
async def asynciter(iterable):
31+
"""Convert an iterable to an asynchronous iterator."""
32+
for x in iterable:
33+
yield x
34+
35+
3036
def run_async(coro):
3137
assert coro.__class__ in {types.GeneratorType, types.CoroutineType}
3238

@@ -124,6 +130,11 @@ def bar():
124130
for c in b]
125131
""",
126132

133+
"""async def foo():
134+
def bar():
135+
[[async for i in b] for b in els]
136+
""",
137+
127138
"""async def foo():
128139
def bar():
129140
[i for i in els
@@ -2002,6 +2013,52 @@ async def f():
20022013
run_async(f()),
20032014
([], {1: 1, 2: 2, 3: 3}))
20042015

2016+
def test_nested_comp(self):
2017+
async def run_list_inside_list():
2018+
return [[i + j async for i in asynciter([1, 2])] for j in [10, 20]]
2019+
self.assertEqual(
2020+
run_async(run_list_inside_list()),
2021+
([], [[11, 12], [21, 22]]))
2022+
2023+
async def run_set_inside_list():
2024+
return [{i + j async for i in asynciter([1, 2])} for j in [10, 20]]
2025+
self.assertEqual(
2026+
run_async(run_set_inside_list()),
2027+
([], [{11, 12}, {21, 22}]))
2028+
2029+
async def run_list_inside_set():
2030+
return {sum([i async for i in asynciter(range(j))]) for j in [3, 5]}
2031+
self.assertEqual(
2032+
run_async(run_list_inside_set()),
2033+
([], {3, 10}))
2034+
2035+
async def run_dict_inside_dict():
2036+
return {j: {i: i + j async for i in asynciter([1, 2])} for j in [10, 20]}
2037+
self.assertEqual(
2038+
run_async(run_dict_inside_dict()),
2039+
([], {10: {1: 11, 2: 12}, 20: {1: 21, 2: 22}}))
2040+
2041+
async def run_list_inside_gen():
2042+
gen = ([i + j async for i in asynciter([1, 2])] for j in [10, 20])
2043+
return [x async for x in gen]
2044+
self.assertEqual(
2045+
run_async(run_list_inside_gen()),
2046+
([], [[11, 12], [21, 22]]))
2047+
2048+
async def run_gen_inside_list():
2049+
gens = [(i async for i in asynciter(range(j))) for j in [3, 5]]
2050+
return [x for g in gens async for x in g]
2051+
self.assertEqual(
2052+
run_async(run_gen_inside_list()),
2053+
([], [0, 1, 2, 0, 1, 2, 3, 4]))
2054+
2055+
async def run_gen_inside_gen():
2056+
gens = ((i async for i in asynciter(range(j))) for j in [3, 5])
2057+
return [x for g in gens async for x in g]
2058+
self.assertEqual(
2059+
run_async(run_gen_inside_gen()),
2060+
([], [0, 1, 2, 0, 1, 2, 3, 4]))
2061+
20052062
def test_copy(self):
20062063
async def func(): pass
20072064
coro = func()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Asynchronous comprehensions are now allowed inside comprehensions in
2+
asynchronous functions. Outer comprehensions implicitly become
3+
asynchronous.

Python/compile.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -4075,7 +4075,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
40754075
PyCodeObject *co = NULL;
40764076
comprehension_ty outermost;
40774077
PyObject *qualname = NULL;
4078-
int is_async_function = c->u->u_ste->ste_coroutine;
4078+
int scope_type = c->u->u_scope_type;
40794079
int is_async_generator = 0;
40804080

40814081
outermost = (comprehension_ty) asdl_seq_GET(generators, 0);
@@ -4088,7 +4088,10 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
40884088

40894089
is_async_generator = c->u->u_ste->ste_coroutine;
40904090

4091-
if (is_async_generator && !is_async_function && type != COMP_GENEXP) {
4091+
if (is_async_generator && type != COMP_GENEXP &&
4092+
scope_type != COMPILER_SCOPE_ASYNC_FUNCTION &&
4093+
scope_type != COMPILER_SCOPE_COMPREHENSION)
4094+
{
40924095
if (e->lineno > c->u->u_lineno) {
40934096
c->u->u_lineno = e->lineno;
40944097
c->u->u_lineno_set = 0;

Python/symtable.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -1741,7 +1741,14 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e,
17411741
return 0;
17421742
}
17431743
st->st_cur->ste_generator = is_generator;
1744-
return symtable_exit_block(st, (void *)e);
1744+
int is_async = st->st_cur->ste_coroutine && !is_generator;
1745+
if (!symtable_exit_block(st, (void *)e)) {
1746+
return 0;
1747+
}
1748+
if (is_async) {
1749+
st->st_cur->ste_coroutine = 1;
1750+
}
1751+
return 1;
17451752
}
17461753

17471754
static int

0 commit comments

Comments
 (0)