summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/reference/expressions.rst18
-rw-r--r--Lib/test/test_asyncgen.py32
-rw-r--r--Lib/test/test_coroutines.py8
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2017-10-06-02-10-48.bpo-31708.66CCVU.rst1
-rw-r--r--Python/compile.c2
5 files changed, 52 insertions, 9 deletions
diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst
index 094b928..1cff8a5 100644
--- a/Doc/reference/expressions.rst
+++ b/Doc/reference/expressions.rst
@@ -326,14 +326,16 @@ range(10) for y in bar(x))``.
The parentheses can be omitted on calls with only one argument. See section
:ref:`calls` for details.
-Since Python 3.6, if the generator appears in an :keyword:`async def` function,
-then :keyword:`async for` clauses and :keyword:`await` expressions are permitted
-as with an asynchronous comprehension. If a generator expression
-contains either :keyword:`async for` clauses or :keyword:`await` expressions
-it is called an :dfn:`asynchronous generator expression`.
-An asynchronous generator expression yields a new asynchronous
-generator object, which is an asynchronous iterator
-(see :ref:`async-iterators`).
+If a generator expression contains either :keyword:`async for`
+clauses or :keyword:`await` expressions it is called an
+:dfn:`asynchronous generator expression`. An asynchronous generator
+expression returns a new asynchronous generator object,
+which is an asynchronous iterator (see :ref:`async-iterators`).
+
+.. versionchanged:: 3.7
+ Prior to Python 3.7, asynchronous generator expressions could
+ only appear in :keyword:`async def` coroutines. Starting
+ with 3.7, any function can use asynchronous generator expressions.
.. _yieldexpr:
diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py
index 8c69d2b..5a36423 100644
--- a/Lib/test/test_asyncgen.py
+++ b/Lib/test/test_asyncgen.py
@@ -1037,5 +1037,37 @@ class AsyncGenAsyncioTest(unittest.TestCase):
t.cancel()
self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop))
+ def test_async_gen_expression_01(self):
+ async def arange(n):
+ for i in range(n):
+ await asyncio.sleep(0.01, loop=self.loop)
+ yield i
+
+ def make_arange(n):
+ # This syntax is legal starting with Python 3.7
+ return (i * 2 async for i in arange(n))
+
+ async def run():
+ return [i async for i in make_arange(10)]
+
+ res = self.loop.run_until_complete(run())
+ self.assertEqual(res, [i * 2 for i in range(10)])
+
+ def test_async_gen_expression_02(self):
+ async def wrap(n):
+ await asyncio.sleep(0.01, loop=self.loop)
+ return n
+
+ def make_arange(n):
+ # This syntax is legal starting with Python 3.7
+ return (i * 2 for i in range(n) if await wrap(i))
+
+ async def run():
+ return [i async for i in make_arange(10)]
+
+ res = self.loop.run_until_complete(run())
+ self.assertEqual(res, [i * 2 for i in range(1, 10)])
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py
index 0803517..d7d38a3 100644
--- a/Lib/test/test_coroutines.py
+++ b/Lib/test/test_coroutines.py
@@ -150,6 +150,14 @@ class AsyncBadSyntaxTest(unittest.TestCase):
""",
"""def bar():
+ {i: i async for i in els}
+ """,
+
+ """def bar():
+ {i async for i in els}
+ """,
+
+ """def bar():
[await i for i in els]
""",
diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-10-06-02-10-48.bpo-31708.66CCVU.rst b/Misc/NEWS.d/next/Core and Builtins/2017-10-06-02-10-48.bpo-31708.66CCVU.rst
new file mode 100644
index 0000000..f732fee
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2017-10-06-02-10-48.bpo-31708.66CCVU.rst
@@ -0,0 +1 @@
+Allow use of asynchronous generator expressions in synchronous functions.
diff --git a/Python/compile.c b/Python/compile.c
index 431e753..58a708c 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -3974,7 +3974,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
is_async_generator = c->u->u_ste->ste_coroutine;
- if (is_async_generator && !is_async_function) {
+ if (is_async_generator && !is_async_function && type != COMP_GENEXP) {
if (e->lineno > c->u->u_lineno) {
c->u->u_lineno = e->lineno;
c->u->u_lineno_set = 0;