Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
8b7b23f9dc
@ -175,7 +175,7 @@ msgstr ""
|
|||||||
msgid "%q must be of type %q"
|
msgid "%q must be of type %q"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: shared-bindings/digitalio/Pull.c
|
#: py/objexcept.c shared-bindings/digitalio/Pull.c
|
||||||
msgid "%q must be of type %q or None"
|
msgid "%q must be of type %q or None"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -894,6 +894,10 @@ msgstr ""
|
|||||||
msgid "Drive mode not used when direction is input."
|
msgid "Drive mode not used when direction is input."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/obj.c
|
||||||
|
msgid "During handling of the above exception, another exception occurred:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: shared-bindings/aesio/aes.c
|
#: shared-bindings/aesio/aes.c
|
||||||
msgid "ECB only operates on 16 bytes at a time"
|
msgid "ECB only operates on 16 bytes at a time"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -2011,6 +2015,10 @@ msgid ""
|
|||||||
"exit safe mode."
|
"exit safe mode."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/obj.c
|
||||||
|
msgid "The above exception was the direct cause of the following exception:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h
|
#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h
|
||||||
msgid "The central button was pressed at start up.\n"
|
msgid "The central button was pressed at start up.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -3341,10 +3349,6 @@ msgstr ""
|
|||||||
msgid "invalid syntax for number"
|
msgid "invalid syntax for number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/objexcept.c
|
|
||||||
msgid "invalid traceback"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/objtype.c
|
#: py/objtype.c
|
||||||
msgid "issubclass() arg 1 must be a class"
|
msgid "issubclass() arg 1 must be a class"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
#define MICROPY_PY_UCRYPTOLIB (1)
|
#define MICROPY_PY_UCRYPTOLIB (1)
|
||||||
#define MICROPY_PY_UCRYPTOLIB_CTR (1)
|
#define MICROPY_PY_UCRYPTOLIB_CTR (1)
|
||||||
#define MICROPY_PY_MICROPYTHON_HEAP_LOCKED (1)
|
#define MICROPY_PY_MICROPYTHON_HEAP_LOCKED (1)
|
||||||
|
#define MICROPY_CPYTHON_EXCEPTION_CHAIN (1)
|
||||||
|
|
||||||
// use vfs's functions for import stat and builtin open
|
// use vfs's functions for import stat and builtin open
|
||||||
#define mp_import_stat mp_vfs_import_stat
|
#define mp_import_stat mp_vfs_import_stat
|
||||||
|
@ -224,6 +224,9 @@ typedef long mp_off_t;
|
|||||||
#ifndef MICROPY_CPYTHON_COMPAT
|
#ifndef MICROPY_CPYTHON_COMPAT
|
||||||
#define MICROPY_CPYTHON_COMPAT (CIRCUITPY_FULL_BUILD)
|
#define MICROPY_CPYTHON_COMPAT (CIRCUITPY_FULL_BUILD)
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
#define MICROPY_CPYTHON_EXCEPTION_CHAIN (CIRCUITPY_FULL_BUILD)
|
||||||
|
#endif
|
||||||
#define MICROPY_PY_BUILTINS_POW3 (CIRCUITPY_BUILTINS_POW3)
|
#define MICROPY_PY_BUILTINS_POW3 (CIRCUITPY_BUILTINS_POW3)
|
||||||
#define MICROPY_PY_FSTRINGS (1)
|
#define MICROPY_PY_FSTRINGS (1)
|
||||||
#define MICROPY_MODULE_WEAK_LINKS (0)
|
#define MICROPY_MODULE_WEAK_LINKS (0)
|
||||||
|
@ -773,6 +773,16 @@ typedef long long mp_longint_impl_t;
|
|||||||
#define MICROPY_WARNINGS (0)
|
#define MICROPY_WARNINGS (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Whether to support chained exceptions
|
||||||
|
#ifndef MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
#define MICROPY_CPYTHON_EXCEPTION_CHAIN (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Whether the statically allocated GeneratorExit exception may be const
|
||||||
|
#ifndef MICROPY_CONST_GENERATOREXIT_OBJ
|
||||||
|
#define MICROPY_CONST_GENERATOREXIT_OBJ (!MICROPY_CPYTHON_EXCEPTION_CHAIN)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Whether to support warning categories
|
// Whether to support warning categories
|
||||||
#ifndef MICROPY_WARNINGS_CATEGORY
|
#ifndef MICROPY_WARNINGS_CATEGORY
|
||||||
#define MICROPY_WARNINGS_CATEGORY (0)
|
#define MICROPY_WARNINGS_CATEGORY (0)
|
||||||
|
24
py/obj.c
24
py/obj.c
@ -142,9 +142,33 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
|
|||||||
mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind);
|
mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mp_obj_print_inner_exception(const mp_print_t *print, mp_obj_t self_in, mp_int_t limit) {
|
||||||
|
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
mp_obj_exception_t *self = mp_obj_exception_get_native(self_in);
|
||||||
|
const compressed_string_t *msg = MP_ERROR_TEXT("During handling of the above exception, another exception occurred:");
|
||||||
|
mp_obj_exception_t *inner = NULL;
|
||||||
|
if (self->cause) {
|
||||||
|
msg = MP_ERROR_TEXT("The above exception was the direct cause of the following exception:");
|
||||||
|
inner = self->cause;
|
||||||
|
} else if (!self->suppress_context) {
|
||||||
|
inner = self->context;
|
||||||
|
}
|
||||||
|
if (inner && !inner->marked) {
|
||||||
|
inner->marked = true;
|
||||||
|
mp_obj_print_exception_with_limit(print, MP_OBJ_FROM_PTR(inner), limit);
|
||||||
|
inner->marked = false;
|
||||||
|
mp_printf(print, "\n");
|
||||||
|
mp_cprintf(print, msg);
|
||||||
|
mp_printf(print, "\n\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// helper function to print an exception with traceback
|
// helper function to print an exception with traceback
|
||||||
void mp_obj_print_exception_with_limit(const mp_print_t *print, mp_obj_t exc, mp_int_t limit) {
|
void mp_obj_print_exception_with_limit(const mp_print_t *print, mp_obj_t exc, mp_int_t limit) {
|
||||||
if (mp_obj_is_exception_instance(exc) && stack_ok()) {
|
if (mp_obj_is_exception_instance(exc) && stack_ok()) {
|
||||||
|
mp_obj_print_inner_exception(print, exc, limit);
|
||||||
|
|
||||||
size_t n, *values;
|
size_t n, *values;
|
||||||
mp_obj_exception_get_traceback(exc, &n, &values);
|
mp_obj_exception_get_traceback(exc, &n, &values);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
|
4
py/obj.h
4
py/obj.h
@ -791,7 +791,9 @@ extern const struct _mp_obj_dict_t mp_const_empty_dict_obj;
|
|||||||
extern const struct _mp_obj_traceback_t mp_const_empty_traceback_obj;
|
extern const struct _mp_obj_traceback_t mp_const_empty_traceback_obj;
|
||||||
extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;
|
extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;
|
||||||
extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj;
|
extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj;
|
||||||
extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj;
|
#if MICROPY_CONST_GENERATOREXIT_OBJ
|
||||||
|
extern const struct _mp_obj_exception_t mp_static_GeneratorExit_obj;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Fixed empty map. Useful when calling keyword-receiving functions
|
// Fixed empty map. Useful when calling keyword-receiving functions
|
||||||
// without any keywords from C, etc.
|
// without any keywords from C, etc.
|
||||||
|
@ -218,19 +218,45 @@ void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
|||||||
mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
if (dest[0] != MP_OBJ_NULL) {
|
if (dest[0] != MP_OBJ_NULL) {
|
||||||
// store/delete attribute
|
// store/delete attribute
|
||||||
if (self == &mp_const_GeneratorExit_obj) {
|
#if MICROPY_CONST_GENERATOREXIT_OBJ
|
||||||
|
if (self == &mp_static_GeneratorExit_obj) {
|
||||||
mp_raise_AttributeError(MP_ERROR_TEXT("can't set attribute"));
|
mp_raise_AttributeError(MP_ERROR_TEXT("can't set attribute"));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (attr == MP_QSTR___traceback__) {
|
if (attr == MP_QSTR___traceback__) {
|
||||||
if (dest[1] == mp_const_none) {
|
if (dest[1] == mp_const_none) {
|
||||||
self->traceback = (mp_obj_traceback_t *)&mp_const_empty_traceback_obj;
|
self->traceback = (mp_obj_traceback_t *)&mp_const_empty_traceback_obj;
|
||||||
} else {
|
} else {
|
||||||
if (!mp_obj_is_type(dest[1], &mp_type_traceback)) {
|
if (!mp_obj_is_type(dest[1], &mp_type_traceback)) {
|
||||||
mp_raise_TypeError(MP_ERROR_TEXT("invalid traceback"));
|
mp_raise_TypeError_varg(MP_ERROR_TEXT("%q must be of type %q or None"), MP_QSTR___context__, MP_QSTR_traceback);
|
||||||
}
|
}
|
||||||
self->traceback = MP_OBJ_TO_PTR(dest[1]);
|
self->traceback = MP_OBJ_TO_PTR(dest[1]);
|
||||||
}
|
}
|
||||||
dest[0] = MP_OBJ_NULL; // indicate success
|
dest[0] = MP_OBJ_NULL; // indicate success
|
||||||
|
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
} else if (attr == MP_QSTR___cause__) {
|
||||||
|
if (dest[1] == mp_const_none) {
|
||||||
|
self->cause = NULL;
|
||||||
|
} else if (!mp_obj_is_type(dest[1], &mp_type_BaseException)) {
|
||||||
|
self->cause = dest[1];
|
||||||
|
} else {
|
||||||
|
mp_raise_TypeError_varg(MP_ERROR_TEXT("%q must be of type %q or None"), attr, MP_QSTR_BaseException);
|
||||||
|
}
|
||||||
|
self->suppress_context = true;
|
||||||
|
dest[0] = MP_OBJ_NULL; // indicate success
|
||||||
|
} else if (attr == MP_QSTR___context__) {
|
||||||
|
if (dest[1] == mp_const_none) {
|
||||||
|
self->context = NULL;
|
||||||
|
} else if (!mp_obj_is_type(dest[1], &mp_type_BaseException)) {
|
||||||
|
self->context = dest[1];
|
||||||
|
} else {
|
||||||
|
mp_raise_TypeError_varg(MP_ERROR_TEXT("%q must be of type %q or None"), attr, MP_QSTR_BaseException);
|
||||||
|
}
|
||||||
|
dest[0] = MP_OBJ_NULL; // indicate success
|
||||||
|
} else if (attr == MP_QSTR___suppress_context__) {
|
||||||
|
self->suppress_context = mp_obj_is_true(dest[1]);
|
||||||
|
dest[0] = MP_OBJ_NULL; // indicate success
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -240,6 +266,14 @@ void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
|||||||
dest[0] = mp_obj_exception_get_value(self_in);
|
dest[0] = mp_obj_exception_get_value(self_in);
|
||||||
} else if (attr == MP_QSTR___traceback__) {
|
} else if (attr == MP_QSTR___traceback__) {
|
||||||
dest[0] = (self->traceback) ? MP_OBJ_FROM_PTR(self->traceback) : mp_const_none;
|
dest[0] = (self->traceback) ? MP_OBJ_FROM_PTR(self->traceback) : mp_const_none;
|
||||||
|
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
} else if (attr == MP_QSTR___cause__) {
|
||||||
|
dest[0] = (self->cause) ? MP_OBJ_FROM_PTR(self->cause) : mp_const_none;
|
||||||
|
} else if (attr == MP_QSTR___context__) {
|
||||||
|
dest[0] = (self->context) ? MP_OBJ_FROM_PTR(self->context) : mp_const_none;
|
||||||
|
} else if (attr == MP_QSTR___suppress_context__) {
|
||||||
|
dest[0] = mp_obj_new_bool(self->suppress_context);
|
||||||
|
#endif
|
||||||
#if MICROPY_CPYTHON_COMPAT
|
#if MICROPY_CPYTHON_COMPAT
|
||||||
} else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
|
} else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
|
||||||
if (attr == MP_QSTR_errno) {
|
if (attr == MP_QSTR_errno) {
|
||||||
|
@ -34,6 +34,11 @@ typedef struct _mp_obj_exception_t {
|
|||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_obj_tuple_t *args;
|
mp_obj_tuple_t *args;
|
||||||
mp_obj_traceback_t *traceback;
|
mp_obj_traceback_t *traceback;
|
||||||
|
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
struct _mp_obj_exception_t *cause, *context;
|
||||||
|
bool suppress_context;
|
||||||
|
bool marked;
|
||||||
|
#endif
|
||||||
} mp_obj_exception_t;
|
} mp_obj_exception_t;
|
||||||
|
|
||||||
void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
|
void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
|
||||||
|
@ -38,7 +38,12 @@
|
|||||||
#include "supervisor/shared/translate/translate.h"
|
#include "supervisor/shared/translate/translate.h"
|
||||||
|
|
||||||
// Instance of GeneratorExit exception - needed by generator.close()
|
// Instance of GeneratorExit exception - needed by generator.close()
|
||||||
const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, (mp_obj_tuple_t *)&mp_const_empty_tuple_obj, (mp_obj_traceback_t *)&mp_const_empty_traceback_obj};
|
#if MICROPY_CONST_GENERATOREXIT_OBJ
|
||||||
|
const
|
||||||
|
#else
|
||||||
|
static
|
||||||
|
#endif
|
||||||
|
mp_obj_exception_t mp_static_GeneratorExit_obj = {{&mp_type_GeneratorExit}, (mp_obj_tuple_t *)&mp_const_empty_tuple_obj, (mp_obj_traceback_t *)&mp_const_empty_traceback_obj};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* generator wrapper */
|
/* generator wrapper */
|
||||||
@ -362,9 +367,19 @@ STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) {
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw);
|
||||||
|
|
||||||
|
static mp_obj_t generatorexit(void) {
|
||||||
|
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
MP_STATIC_ASSERT(!MICROPY_CONST_GENERATOREXIT_OBJ);
|
||||||
|
mp_static_GeneratorExit_obj.context = NULL;
|
||||||
|
mp_static_GeneratorExit_obj.cause = NULL;
|
||||||
|
mp_static_GeneratorExit_obj.suppress_context = false;
|
||||||
|
#endif
|
||||||
|
return MP_OBJ_FROM_PTR(&mp_static_GeneratorExit_obj);
|
||||||
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) {
|
STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) {
|
||||||
mp_obj_t ret;
|
mp_obj_t ret;
|
||||||
switch (mp_obj_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) {
|
switch (mp_obj_gen_resume(self_in, mp_const_none, generatorexit(), &ret)) {
|
||||||
case MP_VM_RETURN_YIELD:
|
case MP_VM_RETURN_YIELD:
|
||||||
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("generator ignored GeneratorExit"));
|
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("generator ignored GeneratorExit"));
|
||||||
|
|
||||||
|
53
py/vm.c
53
py/vm.c
@ -183,6 +183,15 @@
|
|||||||
#define TRACE_TICK(current_ip, current_sp, is_exception)
|
#define TRACE_TICK(current_ip, current_sp, is_exception)
|
||||||
#endif // MICROPY_PY_SYS_SETTRACE
|
#endif // MICROPY_PY_SYS_SETTRACE
|
||||||
|
|
||||||
|
STATIC mp_obj_t get_active_exception(mp_exc_stack_t *exc_sp, mp_exc_stack_t *exc_stack) {
|
||||||
|
for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; --e) {
|
||||||
|
if (e->prev_exc != NULL) {
|
||||||
|
return MP_OBJ_FROM_PTR(e->prev_exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MP_OBJ_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
|
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
|
||||||
// sp points to bottom of stack which grows up
|
// sp points to bottom of stack which grows up
|
||||||
// returns:
|
// returns:
|
||||||
@ -1129,13 +1138,7 @@ unwind_return:
|
|||||||
ENTRY(MP_BC_RAISE_LAST): {
|
ENTRY(MP_BC_RAISE_LAST): {
|
||||||
MARK_EXC_IP_SELECTIVE();
|
MARK_EXC_IP_SELECTIVE();
|
||||||
// search for the inner-most previous exception, to reraise it
|
// search for the inner-most previous exception, to reraise it
|
||||||
mp_obj_t obj = MP_OBJ_NULL;
|
mp_obj_t obj = get_active_exception(exc_sp, exc_stack);
|
||||||
for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; --e) {
|
|
||||||
if (e->prev_exc != NULL) {
|
|
||||||
obj = MP_OBJ_FROM_PTR(e->prev_exc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (obj == MP_OBJ_NULL) {
|
if (obj == MP_OBJ_NULL) {
|
||||||
obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("no active exception to reraise"));
|
obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("no active exception to reraise"));
|
||||||
}
|
}
|
||||||
@ -1145,14 +1148,30 @@ unwind_return:
|
|||||||
ENTRY(MP_BC_RAISE_OBJ): {
|
ENTRY(MP_BC_RAISE_OBJ): {
|
||||||
MARK_EXC_IP_SELECTIVE();
|
MARK_EXC_IP_SELECTIVE();
|
||||||
mp_obj_t obj = mp_make_raise_obj(TOP());
|
mp_obj_t obj = mp_make_raise_obj(TOP());
|
||||||
|
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
mp_obj_t active_exception = get_active_exception(exc_sp, exc_stack);
|
||||||
|
if (active_exception != MP_OBJ_NULL) {
|
||||||
|
mp_store_attr(obj, MP_QSTR___context__, active_exception);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
RAISE(obj);
|
RAISE(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
ENTRY(MP_BC_RAISE_FROM): {
|
ENTRY(MP_BC_RAISE_FROM): {
|
||||||
MARK_EXC_IP_SELECTIVE();
|
MARK_EXC_IP_SELECTIVE();
|
||||||
mp_warning(NULL, "exception chaining not supported");
|
mp_obj_t cause = POP();
|
||||||
sp--; // ignore (pop) "from" argument
|
|
||||||
mp_obj_t obj = mp_make_raise_obj(TOP());
|
mp_obj_t obj = mp_make_raise_obj(TOP());
|
||||||
|
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
// search for the inner-most previous exception, to chain it
|
||||||
|
mp_obj_t active_exception = get_active_exception(exc_sp, exc_stack);
|
||||||
|
if (active_exception != MP_OBJ_NULL) {
|
||||||
|
mp_store_attr(obj, MP_QSTR___context__, active_exception);
|
||||||
|
}
|
||||||
|
mp_store_attr(obj, MP_QSTR___cause__, cause);
|
||||||
|
#else
|
||||||
|
(void)cause;
|
||||||
|
mp_warning(NULL, "exception chaining not supported");
|
||||||
|
#endif
|
||||||
RAISE(obj);
|
RAISE(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1391,7 +1410,10 @@ unwind_loop:
|
|||||||
// - constant GeneratorExit object, because it's const
|
// - constant GeneratorExit object, because it's const
|
||||||
// - exceptions re-raised by END_FINALLY
|
// - exceptions re-raised by END_FINALLY
|
||||||
// - exceptions re-raised explicitly by "raise"
|
// - exceptions re-raised explicitly by "raise"
|
||||||
if (nlr.ret_val != &mp_const_GeneratorExit_obj
|
if ( true
|
||||||
|
#if MICROPY_CONST_GENERATOREXIT_OBJ
|
||||||
|
&& nlr.ret_val != &mp_static_GeneratorExit_obj
|
||||||
|
#endif
|
||||||
&& *code_state->ip != MP_BC_END_FINALLY
|
&& *code_state->ip != MP_BC_END_FINALLY
|
||||||
&& *code_state->ip != MP_BC_RAISE_LAST) {
|
&& *code_state->ip != MP_BC_RAISE_LAST) {
|
||||||
const byte *ip = code_state->fun_bc->bytecode;
|
const byte *ip = code_state->fun_bc->bytecode;
|
||||||
@ -1434,10 +1456,19 @@ unwind_loop:
|
|||||||
// catch exception and pass to byte code
|
// catch exception and pass to byte code
|
||||||
code_state->ip = exc_sp->handler;
|
code_state->ip = exc_sp->handler;
|
||||||
mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp);
|
mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp);
|
||||||
|
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
mp_obj_t active_exception = get_active_exception(exc_sp, exc_stack);
|
||||||
|
#endif
|
||||||
// save this exception in the stack so it can be used in a reraise, if needed
|
// save this exception in the stack so it can be used in a reraise, if needed
|
||||||
exc_sp->prev_exc = nlr.ret_val;
|
exc_sp->prev_exc = nlr.ret_val;
|
||||||
|
mp_obj_t obj = MP_OBJ_FROM_PTR(nlr.ret_val);
|
||||||
|
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
|
||||||
|
if (active_exception != MP_OBJ_NULL) {
|
||||||
|
mp_store_attr(obj, MP_QSTR___context__, active_exception);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// push exception object so it can be handled by bytecode
|
// push exception object so it can be handled by bytecode
|
||||||
PUSH(MP_OBJ_FROM_PTR(nlr.ret_val));
|
PUSH(obj);
|
||||||
code_state->sp = sp;
|
code_state->sp = sp;
|
||||||
|
|
||||||
#if MICROPY_STACKLESS
|
#if MICROPY_STACKLESS
|
||||||
|
@ -1,6 +1,54 @@
|
|||||||
# Exception chaining is not supported, but check that basic
|
|
||||||
# exception works as expected.
|
|
||||||
try:
|
try:
|
||||||
raise Exception from None
|
Exception().__cause__
|
||||||
except Exception:
|
except AttributeError:
|
||||||
print("Caught Exception")
|
print("SKIP")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
def print_exc_info(e):
|
||||||
|
print("exception", type(e), e.args)
|
||||||
|
print("context", type(e.__context__), e.__suppress_context__)
|
||||||
|
print("cause", type(e.__cause__))
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
1/0
|
||||||
|
except Exception as inner:
|
||||||
|
raise RuntimeError() from inner
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
1/0
|
||||||
|
except Exception as inner:
|
||||||
|
raise RuntimeError() from OSError()
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
1/0
|
||||||
|
except Exception as inner:
|
||||||
|
raise RuntimeError()
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
1/0
|
||||||
|
except Exception as inner:
|
||||||
|
raise RuntimeError() from None
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise RuntimeError()
|
||||||
|
except Exception as inner:
|
||||||
|
1/0
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
Warning: exception chaining not supported
|
|
||||||
Caught Exception
|
|
63
tests/circuitpython/traceback_test_chained.py
Normal file
63
tests/circuitpython/traceback_test_chained.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
try:
|
||||||
|
Exception().__cause__
|
||||||
|
except AttributeError:
|
||||||
|
print("SKIP")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
try:
|
||||||
|
import traceback
|
||||||
|
except:
|
||||||
|
print("SKIP")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
|
||||||
|
def print_exc_info(e):
|
||||||
|
print("-" * 72)
|
||||||
|
traceback.print_exception(None, e, e.__traceback__)
|
||||||
|
print("-" * 72)
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
1 / 0
|
||||||
|
except Exception as inner:
|
||||||
|
raise RuntimeError() from inner
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
1 / 0
|
||||||
|
except Exception as inner:
|
||||||
|
raise RuntimeError() from OSError()
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
1 / 0
|
||||||
|
except Exception as inner:
|
||||||
|
raise RuntimeError()
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
1 / 0
|
||||||
|
except Exception as inner:
|
||||||
|
raise RuntimeError() from None
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise RuntimeError()
|
||||||
|
except Exception as inner:
|
||||||
|
1 / 0
|
||||||
|
except Exception as e:
|
||||||
|
print_exc_info(e)
|
55
tests/circuitpython/traceback_test_chained.py.exp
Normal file
55
tests/circuitpython/traceback_test_chained.py.exp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
------------------------------------------------------------------------
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "circuitpython/traceback_test_chained.py", line 23, in <module>
|
||||||
|
ZeroDivisionError: division by zero
|
||||||
|
|
||||||
|
The above exception was the direct cause of the following exception:
|
||||||
|
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "circuitpython/traceback_test_chained.py", line 25, in <module>
|
||||||
|
RuntimeError:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
OSError:
|
||||||
|
|
||||||
|
The above exception was the direct cause of the following exception:
|
||||||
|
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "circuitpython/traceback_test_chained.py", line 34, in <module>
|
||||||
|
RuntimeError:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "circuitpython/traceback_test_chained.py", line 42, in <module>
|
||||||
|
ZeroDivisionError: division by zero
|
||||||
|
|
||||||
|
During handling of the above exception, another exception occurred:
|
||||||
|
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "circuitpython/traceback_test_chained.py", line 44, in <module>
|
||||||
|
RuntimeError:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "circuitpython/traceback_test_chained.py", line 53, in <module>
|
||||||
|
RuntimeError:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "circuitpython/traceback_test_chained.py", line 59, in <module>
|
||||||
|
RuntimeError:
|
||||||
|
|
||||||
|
During handling of the above exception, another exception occurred:
|
||||||
|
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "circuitpython/traceback_test_chained.py", line 61, in <module>
|
||||||
|
ZeroDivisionError: division by zero
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
@ -522,8 +522,12 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
|
|||||||
skip_tests.add("basics/scope_implicit.py") # requires checking for unbound local
|
skip_tests.add("basics/scope_implicit.py") # requires checking for unbound local
|
||||||
skip_tests.add("basics/try_finally_return2.py") # requires raise_varargs
|
skip_tests.add("basics/try_finally_return2.py") # requires raise_varargs
|
||||||
skip_tests.add("basics/unboundlocal.py") # requires checking for unbound local
|
skip_tests.add("basics/unboundlocal.py") # requires checking for unbound local
|
||||||
skip_tests.add(
|
skip_tests.update(
|
||||||
"circuitpython/traceback_test.py"
|
(
|
||||||
|
"basics/chained_exception.py",
|
||||||
|
"circuitpython/traceback_test.py",
|
||||||
|
"circuitpython/traceback_test_chained.py",
|
||||||
|
)
|
||||||
) # because native doesn't have proper traceback info
|
) # because native doesn't have proper traceback info
|
||||||
skip_tests.add("extmod/uasyncio_event.py") # unknown issue
|
skip_tests.add("extmod/uasyncio_event.py") # unknown issue
|
||||||
skip_tests.add("extmod/uasyncio_lock.py") # requires async with
|
skip_tests.add("extmod/uasyncio_lock.py") # requires async with
|
||||||
|
Loading…
Reference in New Issue
Block a user