update async tests with less upython workaround and more cpython compatibility

This commit is contained in:
Kenny 2020-10-10 23:39:32 -07:00
parent 5d96afc5c2
commit 98aa4b7943
5 changed files with 54 additions and 54 deletions

View File

@ -40,6 +40,8 @@
#if MICROPY_ENABLE_COMPILER #if MICROPY_ENABLE_COMPILER
#define DEBUG_PRINT(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__)
// TODO need to mangle __attr names // TODO need to mangle __attr names
#define INVALID_LABEL (0xffff) #define INVALID_LABEL (0xffff)
@ -853,7 +855,7 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns_body->nodes[0]; mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns_body->nodes[0];
body_name = compile_funcdef_helper(comp, pns0, emit_options); body_name = compile_funcdef_helper(comp, pns0, emit_options);
scope_t *fscope = (scope_t*)pns0->nodes[4]; scope_t *fscope = (scope_t*)pns0->nodes[4];
fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_ASYNC;
#endif #endif
} else { } else {
assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be 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
compile_require_async_context(comp, pns); compile_require_async_context(comp, pns);
compile_atom_expr_normal(comp, pns); compile_atom_expr_normal(comp, pns);
// If it's an awaitable thing, need to reach for the __await__ method for the coroutine.
// async def functions' __await__ return themselves, which are able to receive a send(),
// while other types with custom __await__ implementations return async generators.
EMIT_ARG(load_method, MP_QSTR___await__, false); EMIT_ARG(load_method, MP_QSTR___await__, false);
EMIT_ARG(call_method, 0, 0, 0); EMIT_ARG(call_method, 0, 0, 0);
// EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // don't yield anything from an awaitable; only return the final result. EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
// EMIT_ARG(yield, MP_EMIT_YIELD_FROM); EMIT_ARG(yield, MP_EMIT_YIELD_FROM);
} }
#endif #endif

View File

@ -234,12 +234,8 @@ STATIC mp_obj_t gen_instance_await(mp_obj_t self_in) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError,
translate("type object 'generator' has no attribute '__await__'"))); translate("type object 'generator' has no attribute '__await__'")));
} }
mp_obj_t ret = gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL); // You can directly call send on a coroutine generator or you can __await__ then send on the return of that.
if (ret == MP_OBJ_STOP_ITERATION) { return self;
nlr_raise(mp_obj_new_exception(&mp_type_StopIteration));
} else {
return ret;
}
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_await_obj, gen_instance_await); STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_await_obj, gen_instance_await);
#endif #endif

View File

@ -1,22 +1,22 @@
# test await expression # test await expression
import sys # uPy allows normal generators to be awaitables.
if sys.implementation.name in ('micropython', 'circuitpython'): # CircuitPython does not.
# uPy allows normal generators to be awaitables # In CircuitPython you need to have an __await__ method on an awaitable like in CPython;
coroutine = lambda f: f # and like in CPython, generators do not have __await__.
else:
import types
coroutine = types.coroutine
@coroutine class Awaitable:
def wait(value): def __init__(self, value):
print('wait value:', value) self.value = value
msg = yield 'message from wait(%u)' % value
def __await__(self):
print('wait value:', self.value)
msg = yield 'message from wait(%u)' % self.value
print('wait got back:', msg) print('wait got back:', msg)
return 10 return 10
async def f(): async def f():
x = await wait(1)**2 x = await Awaitable(1)**2
print('x =', x) print('x =', x)
coro = f() coro = f()

View File

@ -1,19 +1,19 @@
# test waiting within "async for" __anext__ function # test waiting within "async for" __anext__ function
import sys # uPy allows normal generators to be awaitables.
if sys.implementation.name in ('micropython', 'circuitpython'): # CircuitPython does not.
# uPy allows normal generators to be awaitables # In CircuitPython you need to have an __await__ method on an awaitable like in CPython;
coroutine = lambda f: f # and like in CPython, generators do not have __await__.
else:
import types
coroutine = types.coroutine
@coroutine class Awaitable:
def f(x): def __init__(self, x):
print('f start:', x) self.x = x
yield x + 1
yield x + 2 def __await__(self):
return x + 3 print('f start:', self.x)
yield self.x + 1
yield self.x + 2
return self.x + 3
class ARange: class ARange:
def __init__(self, high): def __init__(self, high):
@ -27,7 +27,7 @@ class ARange:
async def __anext__(self): async def __anext__(self):
print('anext') print('anext')
print('f returned:', await f(20)) print('f returned:', await Awaitable(20))
if self.cur < self.high: if self.cur < self.high:
val = self.cur val = self.cur
self.cur += 1 self.cur += 1

View File

@ -1,32 +1,32 @@
# test waiting within async with enter/exit functions # test waiting within async with enter/exit functions
import sys # uPy allows normal generators to be awaitables.
if sys.implementation.name in ('micropython', 'circuitpython'): # CircuitPython does not.
# uPy allows normal generators to be awaitables # In CircuitPython you need to have an __await__ method on an awaitable like in CPython;
coroutine = lambda f: f # and like in CPython, generators do not have __await__.
else:
import types
coroutine = types.coroutine
@coroutine class Awaitable:
def f(x): def __init__(self, x):
print('f start:', x) self.x = x
yield x + 1
yield x + 2 def __await__(self):
return x + 3 print('f start:', self.x)
yield self.x + 1
yield self.x + 2
return self.x + 3
class AContext: class AContext:
async def __aenter__(self): async def __aenter__(self):
print('enter') print('enter')
print('f returned:', await f(10)) print('f returned:', await Awaitable(10))
async def __aexit__(self, exc_type, exc, tb): async def __aexit__(self, exc_type, exc, tb):
print('exit', exc_type, exc) print('exit', exc_type, exc)
print('f returned:', await f(20)) print('f returned:', await Awaitable(20))
async def coro(): async def coro():
async with AContext(): async with AContext():
print('body start') print('body start')
print('body f returned:', await f(30)) print('body f returned:', await Awaitable(30))
print('body end') print('body end')
o = coro() o = coro()