Skip to content

Commit 46c3ab2

Browse files
pfalcondpgeorge
authored andcommitted
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 adafruit#751.
1 parent d0caaad commit 46c3ab2

14 files changed

Lines changed: 62 additions & 23 deletions

File tree

bare-arm/main.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "runtime0.h"
1515
#include "runtime.h"
1616
#include "repl.h"
17+
#include "pfenv.h"
1718

1819
void do_str(const char *src) {
1920
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) {
3839

3940
if (mp_obj_is_exception_instance(module_fun)) {
4041
// compile error
41-
mp_obj_print_exception(module_fun);
42+
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
4243
return;
4344
}
4445

@@ -48,7 +49,7 @@ void do_str(const char *src) {
4849
nlr_pop();
4950
} else {
5051
// uncaught exception
51-
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
52+
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
5253
}
5354
}
5455

py/modsys.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#include "objstr.h"
3939
#include "mpz.h"
4040
#include "objint.h"
41+
#include "pfenv.h"
42+
#include "stream.h"
4143

4244
#if MICROPY_PY_SYS
4345

@@ -78,6 +80,25 @@ STATIC mp_obj_t mp_sys_exit(mp_uint_t n_args, const mp_obj_t *args) {
7880
}
7981
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit);
8082

83+
STATIC mp_obj_t mp_sys_print_exception(mp_uint_t n_args, const mp_obj_t *args) {
84+
#if MICROPY_PY_IO
85+
mp_obj_t stream_obj = &mp_sys_stdout_obj;
86+
if (n_args > 1) {
87+
stream_obj = args[1];
88+
}
89+
90+
pfenv_t pfenv;
91+
pfenv.data = stream_obj;
92+
pfenv.print_strn = (void (*)(void *, const char *, mp_uint_t))mp_stream_write;
93+
mp_obj_print_exception((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[0]);
94+
#else
95+
mp_obj_print_exception(printf_wrapper, NULL, args[0]);
96+
#endif
97+
98+
return mp_const_none;
99+
}
100+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_print_exception_obj, 1, 2, mp_sys_print_exception);
101+
81102
STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
82103
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sys) },
83104

@@ -118,6 +139,12 @@ STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
118139
{ MP_OBJ_NEW_QSTR(MP_QSTR_stdout), (mp_obj_t)&mp_sys_stdout_obj },
119140
{ MP_OBJ_NEW_QSTR(MP_QSTR_stderr), (mp_obj_t)&mp_sys_stderr_obj },
120141
#endif
142+
143+
/*
144+
* Extensions to CPython
145+
*/
146+
147+
{ MP_OBJ_NEW_QSTR(MP_QSTR_print_exception), (mp_obj_t)&mp_sys_print_exception_obj },
121148
};
122149

123150
STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table);

py/obj.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,31 +85,31 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
8585
}
8686

8787
// helper function to print an exception with traceback
88-
void mp_obj_print_exception(mp_obj_t exc) {
88+
void mp_obj_print_exception(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t exc) {
8989
if (mp_obj_is_exception_instance(exc)) {
9090
mp_uint_t n, *values;
9191
mp_obj_exception_get_traceback(exc, &n, &values);
9292
if (n > 0) {
9393
assert(n % 3 == 0);
94-
printf("Traceback (most recent call last):\n");
94+
print(env, "Traceback (most recent call last):\n");
9595
for (int i = n - 3; i >= 0; i -= 3) {
9696
#if MICROPY_ENABLE_SOURCE_LINE
97-
printf(" File \"%s\", line %d", qstr_str(values[i]), (int)values[i + 1]);
97+
print(env, " File \"%s\", line %d", qstr_str(values[i]), (int)values[i + 1]);
9898
#else
99-
printf(" File \"%s\"", qstr_str(values[i]));
99+
print(env, " File \"%s\"", qstr_str(values[i]));
100100
#endif
101101
// the block name can be NULL if it's unknown
102102
qstr block = values[i + 2];
103103
if (block == MP_QSTR_NULL) {
104-
printf("\n");
104+
print(env, "\n");
105105
} else {
106-
printf(", in %s\n", qstr_str(block));
106+
print(env, ", in %s\n", qstr_str(block));
107107
}
108108
}
109109
}
110110
}
111-
mp_obj_print(exc, PRINT_EXC);
112-
printf("\n");
111+
mp_obj_print_helper(print, env, exc, PRINT_EXC);
112+
print(env, "\n");
113113
}
114114

115115
bool mp_obj_is_true(mp_obj_t arg) {

py/obj.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t
418418

419419
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind);
420420
void mp_obj_print(mp_obj_t o, mp_print_kind_t kind);
421-
void mp_obj_print_exception(mp_obj_t exc);
421+
void mp_obj_print_exception(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t exc);
422422

423423
bool mp_obj_is_true(mp_obj_t arg);
424424

py/pfenv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,6 @@ int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, c
5252

5353
//int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args);
5454
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...);
55+
56+
// Wrapper for system printf
57+
void printf_wrapper(void *env, const char *fmt, ...);

py/qstrdefs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ Q(version_info)
403403
#if MICROPY_PY_SYS_MAXSIZE
404404
Q(maxsize)
405405
#endif
406+
Q(print_exception)
406407
#endif
407408

408409
#if MICROPY_PY_STRUCT

qemu-arm/main.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "runtime0.h"
1515
#include "runtime.h"
1616
#include "repl.h"
17+
#include "pfenv.h"
1718

1819
void do_str(const char *src) {
1920
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) {
3839

3940
if (mp_obj_is_exception_instance(module_fun)) {
4041
// compile error
41-
mp_obj_print_exception(module_fun);
42+
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
4243
return;
4344
}
4445

@@ -48,7 +49,7 @@ void do_str(const char *src) {
4849
nlr_pop();
4950
} else {
5051
// uncaught exception
51-
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
52+
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
5253
}
5354
}
5455

qemu-arm/test_main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ inline void do_str(const char *src) {
4040
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
4141

4242
if (mp_obj_is_exception_instance(module_fun)) {
43-
mp_obj_print_exception(module_fun);
43+
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
4444
tt_abort_msg("Compile error");
4545
}
4646

@@ -49,7 +49,7 @@ inline void do_str(const char *src) {
4949
mp_call_function_0(module_fun);
5050
nlr_pop();
5151
} else {
52-
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
52+
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
5353
tt_abort_msg("Uncaught exception");
5454
}
5555
end:

stmhal/extint.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "gc.h"
3838
#include "obj.h"
3939
#include "runtime.h"
40+
#include "pfenv.h"
4041

4142
#include "pin.h"
4243
#include "extint.h"
@@ -373,7 +374,7 @@ void Handle_EXTI_Irq(uint32_t line) {
373374
v->callback_obj = mp_const_none;
374375
extint_disable(line);
375376
printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line);
376-
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
377+
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
377378
}
378379
gc_unlock();
379380
}

stmhal/pyexec.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "pyexec.h"
4949
#include "pybstdio.h"
5050
#include "genhdr/py-version.h"
51+
#include "pfenv.h"
5152

5253
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
5354
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
8788
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
8889
stdout_tx_strn("\x04", 1);
8990
}
90-
mp_obj_print_exception(module_fun);
91+
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
9192
goto finish;
9293
}
9394

@@ -116,7 +117,7 @@ STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_ki
116117
// at the moment, the value of SystemExit is unused
117118
ret = PYEXEC_FORCED_EXIT;
118119
} else {
119-
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
120+
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
120121
ret = 0;
121122
}
122123
}

0 commit comments

Comments
 (0)