Skip to content

Commit 98aa4b7

Browse files
committed
update async tests with less upython workaround and more cpython compatibility
1 parent 5d96afc commit 98aa4b7

File tree

5 files changed

+55
-55
lines changed

5 files changed

+55
-55
lines changed

py/compile.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040

4141
#if MICROPY_ENABLE_COMPILER
4242

43+
#define DEBUG_PRINT(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__)
44+
4345
// TODO need to mangle __attr names
4446

4547
#define INVALID_LABEL (0xffff)
@@ -853,7 +855,7 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
853855
mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns_body->nodes[0];
854856
body_name = compile_funcdef_helper(comp, pns0, emit_options);
855857
scope_t *fscope = (scope_t*)pns0->nodes[4];
856-
fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
858+
fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_ASYNC;
857859
#endif
858860
} else {
859861
assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be
@@ -2655,11 +2657,13 @@ STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pn
26552657
compile_require_async_context(comp, pns);
26562658
compile_atom_expr_normal(comp, pns);
26572659

2658-
2660+
// If it's an awaitable thing, need to reach for the __await__ method for the coroutine.
2661+
// async def functions' __await__ return themselves, which are able to receive a send(),
2662+
// while other types with custom __await__ implementations return async generators.
26592663
EMIT_ARG(load_method, MP_QSTR___await__, false);
26602664
EMIT_ARG(call_method, 0, 0, 0);
2661-
// EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // don't yield anything from an awaitable; only return the final result.
2662-
// EMIT_ARG(yield, MP_EMIT_YIELD_FROM);
2665+
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
2666+
EMIT_ARG(yield, MP_EMIT_YIELD_FROM);
26632667
}
26642668
#endif
26652669

py/objgenerator.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,12 +234,8 @@ STATIC mp_obj_t gen_instance_await(mp_obj_t self_in) {
234234
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError,
235235
translate("type object 'generator' has no attribute '__await__'")));
236236
}
237-
mp_obj_t ret = gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL);
238-
if (ret == MP_OBJ_STOP_ITERATION) {
239-
nlr_raise(mp_obj_new_exception(&mp_type_StopIteration));
240-
} else {
241-
return ret;
242-
}
237+
// You can directly call send on a coroutine generator or you can __await__ then send on the return of that.
238+
return self;
243239
}
244240
STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_await_obj, gen_instance_await);
245241
#endif

tests/basics/async_await2.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
# test await expression
22

3-
import sys
4-
if sys.implementation.name in ('micropython', 'circuitpython'):
5-
# uPy allows normal generators to be awaitables
6-
coroutine = lambda f: f
7-
else:
8-
import types
9-
coroutine = types.coroutine
3+
# uPy allows normal generators to be awaitables.
4+
# CircuitPython does not.
5+
# In CircuitPython you need to have an __await__ method on an awaitable like in CPython;
6+
# and like in CPython, generators do not have __await__.
107

11-
@coroutine
12-
def wait(value):
13-
print('wait value:', value)
14-
msg = yield 'message from wait(%u)' % value
15-
print('wait got back:', msg)
16-
return 10
8+
class Awaitable:
9+
def __init__(self, value):
10+
self.value = value
11+
12+
def __await__(self):
13+
print('wait value:', self.value)
14+
msg = yield 'message from wait(%u)' % self.value
15+
print('wait got back:', msg)
16+
return 10
1717

1818
async def f():
19-
x = await wait(1)**2
19+
x = await Awaitable(1)**2
2020
print('x =', x)
2121

2222
coro = f()

tests/basics/async_for2.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
# test waiting within "async for" __anext__ function
22

3-
import sys
4-
if sys.implementation.name in ('micropython', 'circuitpython'):
5-
# uPy allows normal generators to be awaitables
6-
coroutine = lambda f: f
7-
else:
8-
import types
9-
coroutine = types.coroutine
10-
11-
@coroutine
12-
def f(x):
13-
print('f start:', x)
14-
yield x + 1
15-
yield x + 2
16-
return x + 3
3+
# uPy allows normal generators to be awaitables.
4+
# CircuitPython does not.
5+
# In CircuitPython you need to have an __await__ method on an awaitable like in CPython;
6+
# and like in CPython, generators do not have __await__.
7+
8+
class Awaitable:
9+
def __init__(self, x):
10+
self.x = x
11+
12+
def __await__(self):
13+
print('f start:', self.x)
14+
yield self.x + 1
15+
yield self.x + 2
16+
return self.x + 3
1717

1818
class ARange:
1919
def __init__(self, high):
@@ -27,7 +27,7 @@ def __aiter__(self):
2727

2828
async def __anext__(self):
2929
print('anext')
30-
print('f returned:', await f(20))
30+
print('f returned:', await Awaitable(20))
3131
if self.cur < self.high:
3232
val = self.cur
3333
self.cur += 1

tests/basics/async_with2.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
# test waiting within async with enter/exit functions
22

3-
import sys
4-
if sys.implementation.name in ('micropython', 'circuitpython'):
5-
# uPy allows normal generators to be awaitables
6-
coroutine = lambda f: f
7-
else:
8-
import types
9-
coroutine = types.coroutine
3+
# uPy allows normal generators to be awaitables.
4+
# CircuitPython does not.
5+
# In CircuitPython you need to have an __await__ method on an awaitable like in CPython;
6+
# and like in CPython, generators do not have __await__.
107

11-
@coroutine
12-
def f(x):
13-
print('f start:', x)
14-
yield x + 1
15-
yield x + 2
16-
return x + 3
8+
class Awaitable:
9+
def __init__(self, x):
10+
self.x = x
11+
12+
def __await__(self):
13+
print('f start:', self.x)
14+
yield self.x + 1
15+
yield self.x + 2
16+
return self.x + 3
1717

1818
class AContext:
1919
async def __aenter__(self):
2020
print('enter')
21-
print('f returned:', await f(10))
21+
print('f returned:', await Awaitable(10))
2222
async def __aexit__(self, exc_type, exc, tb):
2323
print('exit', exc_type, exc)
24-
print('f returned:', await f(20))
24+
print('f returned:', await Awaitable(20))
2525

2626
async def coro():
2727
async with AContext():
2828
print('body start')
29-
print('body f returned:', await f(30))
29+
print('body f returned:', await Awaitable(30))
3030
print('body end')
3131

3232
o = coro()

0 commit comments

Comments
 (0)