Skip to content

Commit db4a8f5

Browse files
committed
modsys: exc_info: Add traceback
Add traceback chain to sys.exec_info()[2]. No actual frame info is added, but just enough to recreate the printed exception traceback. Used by the unittest module which collects errors and failures and prints them at the end.
1 parent b897603 commit db4a8f5

File tree

4 files changed

+164
-1
lines changed

4 files changed

+164
-1
lines changed

py/builtinimport.c

100755100644
File mode changed.

py/modsys.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ STATIC mp_obj_t mp_sys_exc_info(void) {
135135

136136
t->items[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(cur_exc));
137137
t->items[1] = cur_exc;
138-
t->items[2] = mp_const_none;
138+
t->items[2] = mp_obj_exception_get_traceback_obj(cur_exc);
139139
return MP_OBJ_FROM_PTR(t);
140140
}
141141
MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_exc_info_obj, mp_sys_exc_info);

py/obj.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,7 @@ bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type);
717717
void mp_obj_exception_clear_traceback(mp_obj_t self_in);
718718
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block);
719719
void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values);
720+
mp_obj_t mp_obj_exception_get_traceback_obj(mp_obj_t self_in);
720721
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
721722
mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
722723
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);

py/objexcept.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <stdio.h>
3131

3232
#include "py/objlist.h"
33+
#include "py/objnamedtuple.h"
3334
#include "py/objstr.h"
3435
#include "py/objtuple.h"
3536
#include "py/objtype.h"
@@ -531,3 +532,164 @@ void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values
531532
*values = self->traceback_data;
532533
}
533534
}
535+
536+
#if MICROPY_PY_SYS_EXC_INFO
537+
STATIC const mp_obj_namedtuple_type_t code_type_obj = {
538+
.base = {
539+
.base = {
540+
.type = &mp_type_type
541+
},
542+
.name = MP_QSTR_code,
543+
.print = namedtuple_print,
544+
.make_new = namedtuple_make_new,
545+
.unary_op = mp_obj_tuple_unary_op,
546+
.binary_op = mp_obj_tuple_binary_op,
547+
.attr = namedtuple_attr,
548+
.subscr = mp_obj_tuple_subscr,
549+
.getiter = mp_obj_tuple_getiter,
550+
.parent = &mp_type_tuple,
551+
},
552+
.n_fields = 15,
553+
.fields = {
554+
MP_QSTR_co_argcount,
555+
MP_QSTR_co_kwonlyargcount,
556+
MP_QSTR_co_nlocals,
557+
MP_QSTR_co_stacksize,
558+
MP_QSTR_co_flags,
559+
MP_QSTR_co_code,
560+
MP_QSTR_co_consts,
561+
MP_QSTR_co_names,
562+
MP_QSTR_co_varnames,
563+
MP_QSTR_co_freevars,
564+
MP_QSTR_co_cellvars,
565+
MP_QSTR_co_filename,
566+
MP_QSTR_co_name,
567+
MP_QSTR_co_firstlineno,
568+
MP_QSTR_co_lnotab,
569+
},
570+
};
571+
572+
STATIC mp_obj_t code_make_new(qstr file, qstr block) {
573+
mp_obj_t elems[15] = {
574+
mp_obj_new_int(0), // co_argcount
575+
mp_obj_new_int(0), // co_kwonlyargcount
576+
mp_obj_new_int(0), // co_nlocals
577+
mp_obj_new_int(0), // co_stacksize
578+
mp_obj_new_int(0), // co_flags
579+
mp_obj_new_bytearray(0, NULL), // co_code
580+
mp_obj_new_tuple(0, NULL), // co_consts
581+
mp_obj_new_tuple(0, NULL), // co_names
582+
mp_obj_new_tuple(0, NULL), // co_varnames
583+
mp_obj_new_tuple(0, NULL), // co_freevars
584+
mp_obj_new_tuple(0, NULL), // co_cellvars
585+
MP_OBJ_NEW_QSTR(file), // co_filename
586+
MP_OBJ_NEW_QSTR(block), // co_name
587+
mp_obj_new_int(1), // co_firstlineno
588+
mp_obj_new_bytearray(0, NULL), // co_lnotab
589+
};
590+
591+
return namedtuple_make_new((const mp_obj_type_t*)&code_type_obj, 15, 0, elems);
592+
}
593+
594+
STATIC const mp_obj_namedtuple_type_t frame_type_obj = {
595+
.base = {
596+
.base = {
597+
.type = &mp_type_type
598+
},
599+
.name = MP_QSTR_frame,
600+
.print = namedtuple_print,
601+
.make_new = namedtuple_make_new,
602+
.unary_op = mp_obj_tuple_unary_op,
603+
.binary_op = mp_obj_tuple_binary_op,
604+
.attr = namedtuple_attr,
605+
.subscr = mp_obj_tuple_subscr,
606+
.getiter = mp_obj_tuple_getiter,
607+
.parent = &mp_type_tuple,
608+
},
609+
.n_fields = 8,
610+
.fields = {
611+
MP_QSTR_f_back,
612+
MP_QSTR_f_builtins,
613+
MP_QSTR_f_code,
614+
MP_QSTR_f_globals,
615+
MP_QSTR_f_lasti,
616+
MP_QSTR_f_lineno,
617+
MP_QSTR_f_locals,
618+
MP_QSTR_f_trace,
619+
},
620+
};
621+
622+
STATIC mp_obj_t frame_make_new(mp_obj_t f_code, int f_lineno) {
623+
mp_obj_t elems[8] = {
624+
mp_const_none, // f_back
625+
mp_obj_new_dict(0), // f_builtins
626+
f_code, // f_code
627+
mp_obj_new_dict(0), // f_globals
628+
mp_obj_new_int(0), // f_lasti
629+
mp_obj_new_int(f_lineno), // f_lineno
630+
mp_obj_new_dict(0), // f_locals
631+
mp_const_none, // f_trace
632+
};
633+
634+
return namedtuple_make_new((const mp_obj_type_t*)&frame_type_obj, 8, 0, elems);
635+
}
636+
637+
STATIC const mp_obj_namedtuple_type_t traceback_type_obj = {
638+
.base = {
639+
.base = {
640+
.type = &mp_type_type
641+
},
642+
.name = MP_QSTR_traceback,
643+
.print = namedtuple_print,
644+
.make_new = namedtuple_make_new,
645+
.unary_op = mp_obj_tuple_unary_op,
646+
.binary_op = mp_obj_tuple_binary_op,
647+
.attr = namedtuple_attr,
648+
.subscr = mp_obj_tuple_subscr,
649+
.getiter = mp_obj_tuple_getiter,
650+
.parent = &mp_type_tuple,
651+
},
652+
.n_fields = 4,
653+
.fields = {
654+
MP_QSTR_tb_frame,
655+
MP_QSTR_tb_lasti,
656+
MP_QSTR_tb_lineno,
657+
MP_QSTR_tb_next,
658+
},
659+
};
660+
661+
STATIC mp_obj_t traceback_from_values(size_t *values, mp_obj_t tb_next) {
662+
int lineno = values[1];
663+
664+
mp_obj_t elems[4] = {
665+
frame_make_new(code_make_new(values[0], values[2]), lineno),
666+
mp_obj_new_int(0),
667+
mp_obj_new_int(lineno),
668+
tb_next,
669+
};
670+
671+
return namedtuple_make_new((const mp_obj_type_t*)&traceback_type_obj, 4, 0, elems);
672+
};
673+
674+
mp_obj_t mp_obj_exception_get_traceback_obj(mp_obj_t self_in) {
675+
mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
676+
677+
if (!mp_obj_is_exception_instance(self)) {
678+
return mp_const_none;
679+
}
680+
681+
size_t n, *values;
682+
mp_obj_exception_get_traceback(self, &n, &values);
683+
if (n == 0) {
684+
return mp_const_none;
685+
}
686+
687+
mp_obj_t tb_next = mp_const_none;
688+
689+
for (size_t i = 0; i < n; i += 3) {
690+
tb_next = traceback_from_values(&values[i], tb_next);
691+
}
692+
693+
return tb_next;
694+
}
695+
#endif

0 commit comments

Comments
 (0)