bpo-31708: Allow async generator expressions in synchronous functions… · python/cpython@b8ab9d3 (original) (raw)
File tree
5 files changed
lines changed
- Misc/NEWS.d/next/Core and Builtins
5 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -326,14 +326,16 @@ range(10) for y in bar(x))``. | ||
326 | 326 | The parentheses can be omitted on calls with only one argument. See section |
327 | 327 | :ref:`calls` for details. |
328 | 328 | |
329 | -Since Python 3.6, if the generator appears in an :keyword:`async def` function, | |
330 | -then :keyword:`async for` clauses and :keyword:`await` expressions are permitted | |
331 | -as with an asynchronous comprehension. If a generator expression | |
332 | -contains either :keyword:`async for` clauses or :keyword:`await` expressions | |
333 | -it is called an :dfn:`asynchronous generator expression`. | |
334 | -An asynchronous generator expression yields a new asynchronous | |
335 | -generator object, which is an asynchronous iterator | |
336 | -(see :ref:`async-iterators`). | |
329 | +If a generator expression contains either :keyword:`async for` | |
330 | +clauses or :keyword:`await` expressions it is called an | |
331 | +:dfn:`asynchronous generator expression`. An asynchronous generator | |
332 | +expression returns a new asynchronous generator object, | |
333 | +which is an asynchronous iterator (see :ref:`async-iterators`). | |
334 | + | |
335 | +.. versionchanged:: 3.7 | |
336 | + Prior to Python 3.7, asynchronous generator expressions could | |
337 | + only appear in :keyword:`async def` coroutines. Starting | |
338 | + with 3.7, any function can use asynchronous generator expressions. | |
337 | 339 | |
338 | 340 | .. _yieldexpr: |
339 | 341 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1037,5 +1037,37 @@ async def wait(): | ||
1037 | 1037 | t.cancel() |
1038 | 1038 | self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop)) |
1039 | 1039 | |
1040 | +def test_async_gen_expression_01(self): | |
1041 | +async def arange(n): | |
1042 | +for i in range(n): | |
1043 | +await asyncio.sleep(0.01, loop=self.loop) | |
1044 | +yield i | |
1045 | + | |
1046 | +def make_arange(n): | |
1047 | +# This syntax is legal starting with Python 3.7 | |
1048 | +return (i * 2 async for i in arange(n)) | |
1049 | + | |
1050 | +async def run(): | |
1051 | +return [i async for i in make_arange(10)] | |
1052 | + | |
1053 | +res = self.loop.run_until_complete(run()) | |
1054 | +self.assertEqual(res, [i * 2 for i in range(10)]) | |
1055 | + | |
1056 | +def test_async_gen_expression_02(self): | |
1057 | +async def wrap(n): | |
1058 | +await asyncio.sleep(0.01, loop=self.loop) | |
1059 | +return n | |
1060 | + | |
1061 | +def make_arange(n): | |
1062 | +# This syntax is legal starting with Python 3.7 | |
1063 | +return (i * 2 for i in range(n) if await wrap(i)) | |
1064 | + | |
1065 | +async def run(): | |
1066 | +return [i async for i in make_arange(10)] | |
1067 | + | |
1068 | +res = self.loop.run_until_complete(run()) | |
1069 | +self.assertEqual(res, [i * 2 for i in range(1, 10)]) | |
1070 | + | |
1071 | + | |
1040 | 1072 | if __name__ == "__main__": |
1041 | 1073 | unittest.main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -149,6 +149,14 @@ def bar(): | ||
149 | 149 | [i async for i in els] |
150 | 150 | """, |
151 | 151 | |
152 | +"""def bar(): | |
153 | + {i: i async for i in els} | |
154 | + """, | |
155 | + | |
156 | +"""def bar(): | |
157 | + {i async for i in els} | |
158 | + """, | |
159 | + | |
152 | 160 | """def bar(): |
153 | 161 | [await i for i in els] |
154 | 162 | """, |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1 | +Allow use of asynchronous generator expressions in synchronous functions. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -3974,7 +3974,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, | ||
3974 | 3974 | |
3975 | 3975 | is_async_generator = c->u->u_ste->ste_coroutine; |
3976 | 3976 | |
3977 | -if (is_async_generator && !is_async_function) { | |
3977 | +if (is_async_generator && !is_async_function && type != COMP_GENEXP) { | |
3978 | 3978 | if (e->lineno > c->u->u_lineno) { |
3979 | 3979 | c->u->u_lineno = e->lineno; |
3980 | 3980 | c->u->u_lineno_set = 0; |