update async tests with less upython workaround and more cpython compatibility
This commit is contained in:
parent
5d96afc5c2
commit
98aa4b7943
12
py/compile.c
12
py/compile.c
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user