add traceback module

This commit is contained in:
microDev 2021-07-28 00:00:01 +05:30
parent fc59a7ac02
commit f371c0a609
No known key found for this signature in database
GPG Key ID: 2C0867BE60967730
8 changed files with 214 additions and 33 deletions

View File

@ -35,11 +35,11 @@ msgid ""
"https://github.com/adafruit/circuitpython/issues\n" "https://github.com/adafruit/circuitpython/issues\n"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c shared-bindings/traceback/__init__.c
msgid " File \"%q\"" msgid " File \"%q\""
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c shared-bindings/traceback/__init__.c
msgid " File \"%q\", line %d" msgid " File \"%q\", line %d"
msgstr "" msgstr ""
@ -322,7 +322,7 @@ msgstr ""
msgid "*x must be assignment target" msgid "*x must be assignment target"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c shared-bindings/traceback/__init__.c
msgid ", in %q\n" msgid ", in %q\n"
msgstr "" msgstr ""
@ -1185,11 +1185,6 @@ msgstr ""
msgid "Input/output error" msgid "Input/output error"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format
msgid "Missing jmp_pin. Instruction %d jumps on pin"
msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format #, c-format
msgid "Instruction %d shifts in more bits than pin count" msgid "Instruction %d shifts in more bits than pin count"
@ -1506,6 +1501,11 @@ msgstr ""
msgid "Missing first_set_pin. Instruction %d sets pin(s)" msgid "Missing first_set_pin. Instruction %d sets pin(s)"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format
msgid "Missing jmp_pin. Instruction %d jumps on pin"
msgstr ""
#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c #: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c
msgid "Must be a %q subclass." msgid "Must be a %q subclass."
msgstr "" msgstr ""
@ -2227,7 +2227,7 @@ msgstr ""
msgid "Touch alarms not available" msgid "Touch alarms not available"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c shared-bindings/traceback/__init__.c
msgid "Traceback (most recent call last):\n" msgid "Traceback (most recent call last):\n"
msgstr "" msgstr ""
@ -2525,7 +2525,7 @@ msgid "argument name reused"
msgstr "" msgstr ""
#: py/argcheck.c shared-bindings/_stage/__init__.c #: py/argcheck.c shared-bindings/_stage/__init__.c
#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/gamepad/GamePad.c #: shared-bindings/digitalio/DigitalInOut.c
msgid "argument num/types mismatch" msgid "argument num/types mismatch"
msgstr "" msgstr ""
@ -3089,6 +3089,10 @@ msgstr ""
msgid "file must be a file opened in byte mode" msgid "file must be a file opened in byte mode"
msgstr "" msgstr ""
#: shared-bindings/traceback/__init__.c
msgid "file write is not available"
msgstr ""
#: shared-bindings/storage/__init__.c #: shared-bindings/storage/__init__.c
msgid "filesystem must provide mount method" msgid "filesystem must provide mount method"
msgstr "" msgstr ""
@ -3376,6 +3380,10 @@ msgstr ""
msgid "invalid element_size %d, must be, 1, 2, or 4" msgid "invalid element_size %d, must be, 1, 2, or 4"
msgstr "" msgstr ""
#: shared-bindings/traceback/__init__.c
msgid "invalid exception"
msgstr ""
#: extmod/modframebuf.c #: extmod/modframebuf.c
msgid "invalid format" msgid "invalid format"
msgstr "" msgstr ""
@ -3457,6 +3465,10 @@ msgstr ""
msgid "lhs and rhs should be compatible" msgid "lhs and rhs should be compatible"
msgstr "" msgstr ""
#: shared-bindings/traceback/__init__.c
msgid "limit should be an int"
msgstr ""
#: py/emitnative.c #: py/emitnative.c
msgid "local '%q' has type '%q' but source is '%q'" msgid "local '%q' has type '%q' but source is '%q'"
msgstr "" msgstr ""
@ -3609,10 +3621,6 @@ msgstr ""
msgid "no active exception to reraise" msgid "no active exception to reraise"
msgstr "" msgstr ""
#: shared-bindings/socket/__init__.c shared-module/network/__init__.c
msgid "no available NIC"
msgstr ""
#: py/compile.c #: py/compile.c
msgid "no binding for nonlocal found" msgid "no binding for nonlocal found"
msgstr "" msgstr ""
@ -4085,6 +4093,10 @@ msgstr ""
msgid "source palette too large" msgid "source palette too large"
msgstr "" msgstr ""
#: shared-bindings/traceback/__init__.c
msgid "stack is not ok"
msgstr ""
#: py/objstr.c #: py/objstr.c
msgid "start/end indices" msgid "start/end indices"
msgstr "" msgstr ""

View File

@ -19,6 +19,7 @@ CIRCUITPY_PWMIO = 0
CIRCUITPY_ROTARYIO = 0 CIRCUITPY_ROTARYIO = 0
CIRCUITPY_RTC = 0 CIRCUITPY_RTC = 0
CIRCUITPY_USB_MIDI = 0 CIRCUITPY_USB_MIDI = 0
CIRCUITPY_TRACEBACK = 0
CIRCUITPY_PIXELBUF = 1 CIRCUITPY_PIXELBUF = 1
CIRCUITPY_BUSDEVICE = 1 CIRCUITPY_BUSDEVICE = 1

View File

@ -293,6 +293,9 @@ endif
ifeq ($(CIRCUITPY_TOUCHIO),1) ifeq ($(CIRCUITPY_TOUCHIO),1)
SRC_PATTERNS += touchio/% SRC_PATTERNS += touchio/%
endif endif
ifeq ($(CIRCUITPY_TRACEBACK),1)
SRC_PATTERNS += traceback/%
endif
ifeq ($(CIRCUITPY_UHEAP),1) ifeq ($(CIRCUITPY_UHEAP),1)
SRC_PATTERNS += uheap/% SRC_PATTERNS += uheap/%
endif endif
@ -544,6 +547,7 @@ SRC_SHARED_MODULE_ALL = \
terminalio/Terminal.c \ terminalio/Terminal.c \
terminalio/__init__.c \ terminalio/__init__.c \
time/__init__.c \ time/__init__.c \
traceback/__init__.c \
uheap/__init__.c \ uheap/__init__.c \
ustack/__init__.c \ ustack/__init__.c \
vectorio/Circle.c \ vectorio/Circle.c \

View File

@ -763,6 +763,13 @@ extern const struct _mp_obj_module_t touchio_module;
#define TOUCHIO_MODULE #define TOUCHIO_MODULE
#endif #endif
#if CIRCUITPY_TRACEBACK
extern const struct _mp_obj_module_t traceback_module;
#define TRACEBACK_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_traceback), (mp_obj_t)&traceback_module },
#else
#define TRACEBACK_MODULE
#endif
#if CIRCUITPY_UHEAP #if CIRCUITPY_UHEAP
extern const struct _mp_obj_module_t uheap_module; extern const struct _mp_obj_module_t uheap_module;
#define UHEAP_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_uheap),(mp_obj_t)&uheap_module }, #define UHEAP_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_uheap),(mp_obj_t)&uheap_module },
@ -917,6 +924,7 @@ extern const struct _mp_obj_module_t msgpack_module;
SUPERVISOR_MODULE \ SUPERVISOR_MODULE \
SYNTHIO_MODULE \ SYNTHIO_MODULE \
TOUCHIO_MODULE \ TOUCHIO_MODULE \
TRACEBACK_MODULE \
UHEAP_MODULE \ UHEAP_MODULE \
USB_CDC_MODULE \ USB_CDC_MODULE \
USB_HID_MODULE \ USB_HID_MODULE \

View File

@ -324,6 +324,9 @@ CFLAGS += -DCIRCUITPY_TOUCHIO_USE_NATIVE=$(CIRCUITPY_TOUCHIO_USE_NATIVE)
CIRCUITPY_TOUCHIO ?= 1 CIRCUITPY_TOUCHIO ?= 1
CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO) CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO)
CIRCUITPY_TRACEBACK ?= 1
CFLAGS += -DCIRCUITPY_TRACEBACK=$(CIRCUITPY_TRACEBACK)
# For debugging. # For debugging.
CIRCUITPY_UHEAP ?= 0 CIRCUITPY_UHEAP ?= 0
CFLAGS += -DCIRCUITPY_UHEAP=$(CIRCUITPY_UHEAP) CFLAGS += -DCIRCUITPY_UHEAP=$(CIRCUITPY_UHEAP)

View File

@ -120,25 +120,6 @@ STATIC mp_obj_t mp_sys_exit(size_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(size_t n_args, const mp_obj_t *args) {
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
void *stream_obj = &mp_sys_stdout_obj;
if (n_args > 1) {
mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE);
stream_obj = MP_OBJ_TO_PTR(args[1]);
}
mp_print_t print = {stream_obj, mp_stream_write_adaptor};
mp_obj_print_exception(&print, args[0]);
#else
(void)n_args;
mp_obj_print_exception(&mp_plat_print, 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);
#if MICROPY_PY_SYS_EXC_INFO #if MICROPY_PY_SYS_EXC_INFO
STATIC mp_obj_t mp_sys_exc_info(void) { STATIC mp_obj_t mp_sys_exc_info(void) {
mp_obj_t cur_exc = MP_OBJ_FROM_PTR(MP_STATE_VM(cur_exception)); mp_obj_t cur_exc = MP_OBJ_FROM_PTR(MP_STATE_VM(cur_exception));

View File

@ -0,0 +1,171 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 microDev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/stream.h"
#include "py/runtime.h"
#include "supervisor/shared/stack.h"
//| """Traceback Module
//|
//| This module provides a standard interface to print stack traces of programs.
//| This is useful when you want to print stack traces under program control.
//|
//| """
//| ...
//|
//| def print_exception(etype: Type[BaseException], value: BaseException, tb: TracebackType,
//| limit: Optional[int] = None, file: Optional[io.FileIO] = None, chain: Optional[bool] = True) -> None:
//|
//| """Prints exception information and stack trace entries.
//|
//| .. note: Setting `chain` will have no effect as chained exceptions are not yet implemented.
//|
//| :param Type[BaseException] etype: This is ignored and inferred from the type of ``value``.
//| :param BaseException value: The exception. Must be an instance of `BaseException`.
//| :param TracebackType tb: The traceback object. If `None`, the traceback will not be printed.
//| :param int limit: Print up to limit stack trace entries (starting from the callers frame) if limit is positive.
//| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed.
//| :param io.FileIO file: If file is omitted or `None`, the output goes to `sys.stderr`; otherwise it should be an open
//| file or file-like object to receive the output.
//| :param bool chain: If `True` then chained exceptions will be printed.
//|
//| """
//| ...
//|
STATIC mp_obj_t traceback_print_exception(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_etype, ARG_value, ARG_tb, ARG_limit, ARG_file, ARG_chain };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_etype, MP_ARG_OBJ | MP_ARG_REQUIRED },
{ MP_QSTR_value, MP_ARG_OBJ | MP_ARG_REQUIRED },
{ MP_QSTR_tb, MP_ARG_OBJ | MP_ARG_REQUIRED },
{ MP_QSTR_limit, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_file, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_chain, MP_ARG_BOOL, {.u_bool = true} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_obj_t exc = args[ARG_value].u_obj;
if (!mp_obj_is_exception_instance(exc)) {
mp_raise_TypeError(translate("invalid exception"));
}
mp_print_t print = mp_plat_print;
if (args[ARG_file].u_obj != mp_const_none) {
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
mp_get_stream_raise(args[ARG_file].u_obj, MP_STREAM_OP_WRITE);
print.data = MP_OBJ_TO_PTR(args[ARG_file].u_obj);
print.print_strn = mp_stream_write_adaptor;
#else
mp_raise_NotImplementedError(translate("file write is not available"));
#endif
}
mp_int_t limit = 0;
bool print_tb = true;
if (args[ARG_limit].u_obj != mp_const_none) {
if (!mp_obj_get_int_maybe(args[ARG_limit].u_obj, &limit)) {
mp_raise_TypeError(translate("limit should be an int"));
}
print_tb = !(limit == 0);
}
if (args[ARG_tb].u_obj != mp_const_none && print_tb) {
if (!stack_ok()) {
mp_raise_RuntimeError(translate("stack is not ok"));
}
size_t n, *values;
mp_obj_exception_get_traceback(exc, &n, &values);
if (n > 0) {
assert(n % 3 == 0);
// Decompress the format strings
const compressed_string_t *traceback = MP_ERROR_TEXT("Traceback (most recent call last):\n");
char decompressed[decompress_length(traceback)];
decompress(traceback, decompressed);
#if MICROPY_ENABLE_SOURCE_LINE
const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\", line %d");
#else
const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\"");
#endif
char decompressed_frame[decompress_length(frame)];
decompress(frame, decompressed_frame);
const compressed_string_t *block_fmt = MP_ERROR_TEXT(", in %q\n");
char decompressed_block[decompress_length(block_fmt)];
decompress(block_fmt, decompressed_block);
// Set traceback formatting
// Default: Print full traceback
int i = n - 3, j;
if (limit > 0) {
// Print upto limit traceback
// from caller's frame
limit = n - (limit * 3);
} else if (limit < 0) {
// Print upto limit traceback
// from last
i = 0, limit = 3 + (limit * 3);
}
// Print the traceback
mp_print_str(&print, decompressed);
for (; i >= limit; i -= 3) {
j = (i < 0) ? -i : i;
#if MICROPY_ENABLE_SOURCE_LINE
mp_printf(&print, decompressed_frame, values[j], (int)values[j + 1]);
#else
mp_printf(&print, decompressed_frame, values[j]);
#endif
// The block name can be NULL if it's unknown
qstr block = values[j + 2];
if (block == MP_QSTRnull) {
mp_print_str(&print, "\n");
} else {
mp_printf(&print, decompressed_block, block);
}
}
}
}
mp_obj_print_helper(&print, exc, PRINT_EXC);
mp_print_str(&print, "\n");
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(traceback_print_exception_obj, 3, traceback_print_exception);
STATIC const mp_rom_map_elem_t traceback_module_globals_table[] = {
// module name
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_traceback) },
// module functions
{ MP_ROM_QSTR(MP_QSTR_print_exception), MP_ROM_PTR(&traceback_print_exception_obj) },
};
STATIC MP_DEFINE_CONST_DICT(traceback_module_globals, traceback_module_globals_table);
const mp_obj_module_t traceback_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&traceback_module_globals,
};

View File

@ -0,0 +1 @@
// empty file