From 37e1b5c891f9964bb6c95228bc2d718511507a69 Mon Sep 17 00:00:00 2001 From: Jonathan Hogg Date: Tue, 21 Jul 2020 18:47:28 +0100 Subject: [PATCH] py/compile: Don't await __aiter__ special method in async-for. MicroPython's original implementation of __aiter__ was correct for an earlier (provisional) version of PEP492 (CPython 3.5), where __aiter__ was an async-def function. But that changed in the final version of PEP492 (in CPython 3.5.2) where the function was changed to a normal one. See https://www.python.org/dev/peps/pep-0492/#why-aiter-does-not-return-an-awaitable See also the note at the end of this subsection in the docs: https://docs.python.org/3.5/reference/datamodel.html#asynchronous-iterators And for completeness the BPO: https://bugs.python.org/issue27243 To be consistent with the Python spec as it stands today (and now that PEP492 is final) this commit changes MicroPython's behaviour to match CPython: __aiter__ should return an async-iterable object, but is not itself awaitable. The relevant tests are updated to match. See #6267. --- py/compile.c | 3 ++- tests/basics/async_for.py | 2 +- tests/basics/async_for2.py | 5 ++--- tests/basics/async_for2.py.exp | 4 ---- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/py/compile.c b/py/compile.c index 53108b7062..d1a4d65c8b 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1798,7 +1798,8 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns uint try_finally_label = comp_next_label(comp); compile_node(comp, pns->nodes[1]); // iterator - compile_await_object_method(comp, MP_QSTR___aiter__); + EMIT_ARG(load_method, MP_QSTR___aiter__, false); + EMIT_ARG(call_method, 0, 0, 0); compile_store_id(comp, context); START_BREAK_CONTINUE_BLOCK diff --git a/tests/basics/async_for.py b/tests/basics/async_for.py index 6b4e136d59..5fd0540828 100644 --- a/tests/basics/async_for.py +++ b/tests/basics/async_for.py @@ -6,7 +6,7 @@ class AsyncIteratorWrapper: print('init') self._it = iter(obj) - async def __aiter__(self): + def __aiter__(self): print('aiter') return self diff --git a/tests/basics/async_for2.py b/tests/basics/async_for2.py index 89584fcb10..aad23a3e5a 100644 --- a/tests/basics/async_for2.py +++ b/tests/basics/async_for2.py @@ -1,4 +1,4 @@ -# test waiting within "async for" aiter/anext functions +# test waiting within "async for" __anext__ function import sys if sys.implementation.name == 'micropython': @@ -21,9 +21,8 @@ class ARange: self.cur = 0 self.high = high - async def __aiter__(self): + def __aiter__(self): print('aiter') - print('f returned:', await f(10)) return self async def __anext__(self): diff --git a/tests/basics/async_for2.py.exp b/tests/basics/async_for2.py.exp index 886232f7ba..52bbe90c85 100644 --- a/tests/basics/async_for2.py.exp +++ b/tests/basics/async_for2.py.exp @@ -1,9 +1,5 @@ init aiter -f start: 10 -coro yielded: 11 -coro yielded: 12 -f returned: 13 anext f start: 20 coro yielded: 21