modsys: Add sys.print_exception(exc, file=sys.stdout) function.
The function is modeled after traceback.print_exception(), but unbloated, and put into existing module to save overhead on adding another module. Compliant traceback.print_exception() is intended to be implemented in micropython-lib in terms of sys.print_exception(). This change required refactoring mp_obj_print_exception() to take pfenv_t interface arguments. Addresses #751.
This commit is contained in:
parent
d0caaadaee
commit
46c3ab2004
@ -14,6 +14,7 @@
|
|||||||
#include "runtime0.h"
|
#include "runtime0.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
#include "repl.h"
|
#include "repl.h"
|
||||||
|
#include "pfenv.h"
|
||||||
|
|
||||||
void do_str(const char *src) {
|
void do_str(const char *src) {
|
||||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||||
@ -38,7 +39,7 @@ void do_str(const char *src) {
|
|||||||
|
|
||||||
if (mp_obj_is_exception_instance(module_fun)) {
|
if (mp_obj_is_exception_instance(module_fun)) {
|
||||||
// compile error
|
// compile error
|
||||||
mp_obj_print_exception(module_fun);
|
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ void do_str(const char *src) {
|
|||||||
nlr_pop();
|
nlr_pop();
|
||||||
} else {
|
} else {
|
||||||
// uncaught exception
|
// uncaught exception
|
||||||
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
|
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
py/modsys.c
27
py/modsys.c
@ -38,6 +38,8 @@
|
|||||||
#include "objstr.h"
|
#include "objstr.h"
|
||||||
#include "mpz.h"
|
#include "mpz.h"
|
||||||
#include "objint.h"
|
#include "objint.h"
|
||||||
|
#include "pfenv.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
#if MICROPY_PY_SYS
|
#if MICROPY_PY_SYS
|
||||||
|
|
||||||
@ -78,6 +80,25 @@ STATIC mp_obj_t mp_sys_exit(mp_uint_t n_args, const mp_obj_t *args) {
|
|||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit);
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit);
|
||||||
|
|
||||||
|
STATIC mp_obj_t mp_sys_print_exception(mp_uint_t n_args, const mp_obj_t *args) {
|
||||||
|
#if MICROPY_PY_IO
|
||||||
|
mp_obj_t stream_obj = &mp_sys_stdout_obj;
|
||||||
|
if (n_args > 1) {
|
||||||
|
stream_obj = args[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
pfenv_t pfenv;
|
||||||
|
pfenv.data = stream_obj;
|
||||||
|
pfenv.print_strn = (void (*)(void *, const char *, mp_uint_t))mp_stream_write;
|
||||||
|
mp_obj_print_exception((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[0]);
|
||||||
|
#else
|
||||||
|
mp_obj_print_exception(printf_wrapper, NULL, args[0]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_print_exception_obj, 1, 2, mp_sys_print_exception);
|
||||||
|
|
||||||
STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
|
STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sys) },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sys) },
|
||||||
|
|
||||||
@ -118,6 +139,12 @@ STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
|
|||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stdout), (mp_obj_t)&mp_sys_stdout_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_stdout), (mp_obj_t)&mp_sys_stdout_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stderr), (mp_obj_t)&mp_sys_stderr_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_stderr), (mp_obj_t)&mp_sys_stderr_obj },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extensions to CPython
|
||||||
|
*/
|
||||||
|
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_print_exception), (mp_obj_t)&mp_sys_print_exception_obj },
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table);
|
STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table);
|
||||||
|
16
py/obj.c
16
py/obj.c
@ -85,31 +85,31 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// helper function to print an exception with traceback
|
// helper function to print an exception with traceback
|
||||||
void mp_obj_print_exception(mp_obj_t exc) {
|
void mp_obj_print_exception(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t exc) {
|
||||||
if (mp_obj_is_exception_instance(exc)) {
|
if (mp_obj_is_exception_instance(exc)) {
|
||||||
mp_uint_t n, *values;
|
mp_uint_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) {
|
||||||
assert(n % 3 == 0);
|
assert(n % 3 == 0);
|
||||||
printf("Traceback (most recent call last):\n");
|
print(env, "Traceback (most recent call last):\n");
|
||||||
for (int i = n - 3; i >= 0; i -= 3) {
|
for (int i = n - 3; i >= 0; i -= 3) {
|
||||||
#if MICROPY_ENABLE_SOURCE_LINE
|
#if MICROPY_ENABLE_SOURCE_LINE
|
||||||
printf(" File \"%s\", line %d", qstr_str(values[i]), (int)values[i + 1]);
|
print(env, " File \"%s\", line %d", qstr_str(values[i]), (int)values[i + 1]);
|
||||||
#else
|
#else
|
||||||
printf(" File \"%s\"", qstr_str(values[i]));
|
print(env, " File \"%s\"", qstr_str(values[i]));
|
||||||
#endif
|
#endif
|
||||||
// the block name can be NULL if it's unknown
|
// the block name can be NULL if it's unknown
|
||||||
qstr block = values[i + 2];
|
qstr block = values[i + 2];
|
||||||
if (block == MP_QSTR_NULL) {
|
if (block == MP_QSTR_NULL) {
|
||||||
printf("\n");
|
print(env, "\n");
|
||||||
} else {
|
} else {
|
||||||
printf(", in %s\n", qstr_str(block));
|
print(env, ", in %s\n", qstr_str(block));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mp_obj_print(exc, PRINT_EXC);
|
mp_obj_print_helper(print, env, exc, PRINT_EXC);
|
||||||
printf("\n");
|
print(env, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_obj_is_true(mp_obj_t arg) {
|
bool mp_obj_is_true(mp_obj_t arg) {
|
||||||
|
2
py/obj.h
2
py/obj.h
@ -418,7 +418,7 @@ mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t
|
|||||||
|
|
||||||
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind);
|
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind);
|
||||||
void mp_obj_print(mp_obj_t o, mp_print_kind_t kind);
|
void mp_obj_print(mp_obj_t o, mp_print_kind_t kind);
|
||||||
void mp_obj_print_exception(mp_obj_t exc);
|
void mp_obj_print_exception(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t exc);
|
||||||
|
|
||||||
bool mp_obj_is_true(mp_obj_t arg);
|
bool mp_obj_is_true(mp_obj_t arg);
|
||||||
|
|
||||||
|
@ -52,3 +52,6 @@ int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, c
|
|||||||
|
|
||||||
//int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args);
|
//int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args);
|
||||||
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...);
|
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...);
|
||||||
|
|
||||||
|
// Wrapper for system printf
|
||||||
|
void printf_wrapper(void *env, const char *fmt, ...);
|
||||||
|
@ -403,6 +403,7 @@ Q(version_info)
|
|||||||
#if MICROPY_PY_SYS_MAXSIZE
|
#if MICROPY_PY_SYS_MAXSIZE
|
||||||
Q(maxsize)
|
Q(maxsize)
|
||||||
#endif
|
#endif
|
||||||
|
Q(print_exception)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MICROPY_PY_STRUCT
|
#if MICROPY_PY_STRUCT
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "runtime0.h"
|
#include "runtime0.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
#include "repl.h"
|
#include "repl.h"
|
||||||
|
#include "pfenv.h"
|
||||||
|
|
||||||
void do_str(const char *src) {
|
void do_str(const char *src) {
|
||||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||||
@ -38,7 +39,7 @@ void do_str(const char *src) {
|
|||||||
|
|
||||||
if (mp_obj_is_exception_instance(module_fun)) {
|
if (mp_obj_is_exception_instance(module_fun)) {
|
||||||
// compile error
|
// compile error
|
||||||
mp_obj_print_exception(module_fun);
|
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ void do_str(const char *src) {
|
|||||||
nlr_pop();
|
nlr_pop();
|
||||||
} else {
|
} else {
|
||||||
// uncaught exception
|
// uncaught exception
|
||||||
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
|
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ inline void do_str(const char *src) {
|
|||||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
||||||
|
|
||||||
if (mp_obj_is_exception_instance(module_fun)) {
|
if (mp_obj_is_exception_instance(module_fun)) {
|
||||||
mp_obj_print_exception(module_fun);
|
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
|
||||||
tt_abort_msg("Compile error");
|
tt_abort_msg("Compile error");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ inline void do_str(const char *src) {
|
|||||||
mp_call_function_0(module_fun);
|
mp_call_function_0(module_fun);
|
||||||
nlr_pop();
|
nlr_pop();
|
||||||
} else {
|
} else {
|
||||||
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
|
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
|
||||||
tt_abort_msg("Uncaught exception");
|
tt_abort_msg("Uncaught exception");
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include "pfenv.h"
|
||||||
|
|
||||||
#include "pin.h"
|
#include "pin.h"
|
||||||
#include "extint.h"
|
#include "extint.h"
|
||||||
@ -373,7 +374,7 @@ void Handle_EXTI_Irq(uint32_t line) {
|
|||||||
v->callback_obj = mp_const_none;
|
v->callback_obj = mp_const_none;
|
||||||
extint_disable(line);
|
extint_disable(line);
|
||||||
printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line);
|
printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line);
|
||||||
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
|
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
|
||||||
}
|
}
|
||||||
gc_unlock();
|
gc_unlock();
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "pyexec.h"
|
#include "pyexec.h"
|
||||||
#include "pybstdio.h"
|
#include "pybstdio.h"
|
||||||
#include "genhdr/py-version.h"
|
#include "genhdr/py-version.h"
|
||||||
|
#include "pfenv.h"
|
||||||
|
|
||||||
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
||||||
STATIC bool repl_display_debugging_info = 0;
|
STATIC bool repl_display_debugging_info = 0;
|
||||||
@ -87,7 +88,7 @@ STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_ki
|
|||||||
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
||||||
stdout_tx_strn("\x04", 1);
|
stdout_tx_strn("\x04", 1);
|
||||||
}
|
}
|
||||||
mp_obj_print_exception(module_fun);
|
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_ki
|
|||||||
// at the moment, the value of SystemExit is unused
|
// at the moment, the value of SystemExit is unused
|
||||||
ret = PYEXEC_FORCED_EXIT;
|
ret = PYEXEC_FORCED_EXIT;
|
||||||
} else {
|
} else {
|
||||||
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
|
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "servo.h"
|
#include "servo.h"
|
||||||
#include "pin.h"
|
#include "pin.h"
|
||||||
|
#include "pfenv.h"
|
||||||
|
|
||||||
/// \moduleref pyb
|
/// \moduleref pyb
|
||||||
/// \class Timer - periodically call a function
|
/// \class Timer - periodically call a function
|
||||||
@ -1245,7 +1246,7 @@ STATIC void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_o
|
|||||||
} else {
|
} else {
|
||||||
printf("uncaught exception in Timer(%u) channel %u interrupt handler\n", tim->tim_id, channel);
|
printf("uncaught exception in Timer(%u) channel %u interrupt handler\n", tim->tim_id, channel);
|
||||||
}
|
}
|
||||||
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
|
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
|
||||||
}
|
}
|
||||||
gc_unlock();
|
gc_unlock();
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "qstr.h"
|
#include "qstr.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include "pfenv.h"
|
||||||
#include MICROPY_HAL_H
|
#include MICROPY_HAL_H
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "pin.h"
|
#include "pin.h"
|
||||||
@ -917,7 +918,7 @@ STATIC bool ftm_handle_irq_callback(pyb_timer_obj_t *self, mp_uint_t channel, mp
|
|||||||
printf("Uncaught exception in Timer(" UINT_FMT ") channel "
|
printf("Uncaught exception in Timer(" UINT_FMT ") channel "
|
||||||
UINT_FMT " interrupt handler\n", self->tim_id, channel);
|
UINT_FMT " interrupt handler\n", self->tim_id, channel);
|
||||||
}
|
}
|
||||||
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
|
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
|
||||||
}
|
}
|
||||||
gc_unlock();
|
gc_unlock();
|
||||||
return handled;
|
return handled;
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "parsehelper.h"
|
#include "parsehelper.h"
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include "pfenv.h"
|
||||||
|
|
||||||
void do_file(const char *file) {
|
void do_file(const char *file) {
|
||||||
mp_lexer_t *lex = mp_lexer_new_from_file(file);
|
mp_lexer_t *lex = mp_lexer_new_from_file(file);
|
||||||
@ -80,7 +81,7 @@ void do_file(const char *file) {
|
|||||||
//printf("----------------\n");
|
//printf("----------------\n");
|
||||||
|
|
||||||
if (mp_obj_is_exception_instance(module_fun)) {
|
if (mp_obj_is_exception_instance(module_fun)) {
|
||||||
mp_obj_print_exception(module_fun);
|
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "genhdr/py-version.h"
|
#include "genhdr/py-version.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "stackctrl.h"
|
#include "stackctrl.h"
|
||||||
|
#include "pfenv.h"
|
||||||
|
|
||||||
// Command line options, with their defaults
|
// Command line options, with their defaults
|
||||||
STATIC bool compile_only = false;
|
STATIC bool compile_only = false;
|
||||||
@ -100,7 +101,7 @@ STATIC int handle_uncaught_exception(mp_obj_t exc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Report all other exceptions
|
// Report all other exceptions
|
||||||
mp_obj_print_exception(exc);
|
mp_obj_print_exception(printf_wrapper, NULL, exc);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +151,7 @@ STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind,
|
|||||||
|
|
||||||
if (mp_obj_is_exception_instance(module_fun)) {
|
if (mp_obj_is_exception_instance(module_fun)) {
|
||||||
// compile error
|
// compile error
|
||||||
mp_obj_print_exception(module_fun);
|
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user