2021-07-27 14:30:01 -04:00
/*
* 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"
2021-08-05 09:49:19 -04:00
# include "shared-module/traceback/__init__.h"
2021-07-27 14:30:01 -04:00
//| """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.
//|
2022-05-03 14:31:20 -04:00
//| |see_cpython_module| :mod:`cpython:traceback`.
2021-07-27 14:30:01 -04:00
//| """
//| ...
2023-02-01 03:08:41 -05:00
//|
2021-07-27 14:30:01 -04:00
2022-10-13 09:44:57 -04:00
STATIC void traceback_exception_common ( bool is_print_exception , mp_print_t * print , size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
2022-10-13 09:51:41 -04:00
enum { ARG_exc , ARG_value , ARG_tb , ARG_limit , ARG_file , ARG_chain } ;
2022-10-13 09:44:57 -04:00
static const mp_arg_t allowed_args [ ] = {
2022-10-13 09:51:41 -04:00
{ MP_QSTR_ , MP_ARG_OBJ | MP_ARG_REQUIRED , { . u_obj = MP_OBJ_NULL } } ,
{ MP_QSTR_value , MP_ARG_OBJ , { . u_obj = MP_OBJ_NULL } } ,
{ MP_QSTR_tb , MP_ARG_OBJ , { . u_obj = MP_OBJ_NULL } } ,
2022-10-13 09:44:57 -04:00
{ 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 value = args [ ARG_value ] . u_obj ;
2022-10-13 09:51:41 -04:00
if ( value = = MP_OBJ_NULL ) {
value = args [ ARG_exc ] . u_obj ;
}
2022-10-13 09:44:57 -04:00
mp_obj_t tb_obj = args [ ARG_tb ] . u_obj ;
mp_obj_t limit_obj = args [ ARG_limit ] . u_obj ;
2023-08-14 09:51:52 -04:00
# if MICROPY_CPYTHON_EXCEPTION_CHAIN
2022-12-02 11:47:50 -05:00
bool chain = args [ ARG_chain ] . u_bool ;
2023-08-14 09:51:52 -04:00
# endif
2022-10-13 09:44:57 -04:00
if ( args [ ARG_file ] . u_obj ! = mp_const_none ) {
if ( ! is_print_exception ) {
# if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch ( ) ;
# else
mp_raise_msg_varg ( & mp_type_TypeError , MP_ERROR_TEXT ( " unexpected keyword argument '%q' " ) , MP_QSTR_file ) ;
# endif
}
# 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
}
2021-08-08 12:03:03 -04:00
if ( ! mp_obj_is_exception_instance ( value ) ) {
mp_raise_TypeError ( translate ( " invalid exception " ) ) ;
}
mp_int_t limit = 0 ;
bool print_tb = true ;
if ( limit_obj ! = mp_const_none ) {
limit = mp_obj_get_int ( limit_obj ) ;
print_tb = ( limit ! = 0 ) ;
}
2021-12-15 01:41:21 -05:00
mp_obj_exception_t * exc = mp_obj_exception_get_native ( value ) ;
mp_obj_traceback_t * trace_backup = exc - > traceback ;
2022-12-02 11:47:50 -05:00
# if MICROPY_CPYTHON_EXCEPTION_CHAIN
mp_obj_exception_t * context_backup = exc - > context ;
mp_obj_exception_t * cause_backup = exc - > cause ;
if ( ! chain ) {
exc - > context = NULL ;
exc - > cause = NULL ;
}
# endif
2021-12-15 01:41:21 -05:00
2022-10-13 09:51:41 -04:00
if ( tb_obj = = MP_OBJ_NULL ) {
/* Print the traceback's exception as is */
} else if ( tb_obj ! = mp_const_none & & print_tb ) {
2021-12-15 01:41:21 -05:00
exc - > traceback = mp_arg_validate_type ( tb_obj , & mp_type_traceback , MP_QSTR_tb ) ;
2021-08-08 12:03:03 -04:00
} else {
2021-12-15 01:41:21 -05:00
exc - > traceback = ( mp_obj_traceback_t * ) & mp_const_empty_traceback_obj ;
2021-08-08 12:03:03 -04:00
}
2021-12-15 01:41:21 -05:00
shared_module_traceback_print_exception ( MP_OBJ_TO_PTR ( value ) , print , limit ) ;
exc - > traceback = trace_backup ;
2022-12-02 11:47:50 -05:00
# if MICROPY_CPYTHON_EXCEPTION_CHAIN
exc - > context = context_backup ;
exc - > cause = cause_backup ;
# endif
2021-08-08 12:03:03 -04:00
}
2022-09-27 16:21:42 -04:00
//| def format_exception(
2022-10-13 10:24:46 -04:00
//| exc: BaseException | Type[BaseException],
//| /,
//| value: Optional[BaseException] = None,
//| tb: Optional[TracebackType] = None,
2022-09-27 16:21:42 -04:00
//| limit: Optional[int] = None,
//| chain: Optional[bool] = True,
2022-10-13 10:29:21 -04:00
//| ) -> List[str]:
2021-08-08 12:03:03 -04:00
//| """Format a stack trace and the exception information.
//|
2022-10-13 10:24:46 -04:00
//| If the exception value is passed in ``exc``, then this exception value and its
//| associated traceback are used. This is compatible with CPython 3.10 and newer.
//|
//| If the exception value is passed in ``value``, then any value passed in for
//| ``exc`` is ignored. ``value`` is used as the exception value and the
//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is None,
//| no traceback will be shown. This is compatible with CPython 3.5 and
//| newer.
//|
2021-08-08 12:03:03 -04:00
//| The arguments have the same meaning as the corresponding arguments
//| to print_exception(). The return value is a list of strings, each
//| ending in a newline and some containing internal newlines. When
//| these lines are concatenated and printed, exactly the same text is
//| printed as does print_exception().
//|
2022-10-13 10:24:46 -04:00
//| :param exc: The exception. Must be an instance of `BaseException`. Unused if value is specified.
//| :param value: If specified, is used in place of ``exc``.
//| :param TracebackType tb: When value is alsp specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed.
2021-08-08 12:03:03 -04:00
//| :param int limit: Print up to limit stack trace entries (starting from the caller’ s frame) if limit is positive.
//| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed.
2022-12-02 11:47:50 -05:00
//| :param bool chain: If `True` then chained exceptions will be printed.
2021-08-08 12:03:03 -04:00
//| """
2022-09-29 20:22:32 -04:00
//|
2021-08-08 12:03:03 -04:00
STATIC mp_obj_t traceback_format_exception ( size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
mp_print_t print ;
vstr_t vstr ;
vstr_init_print ( & vstr , 0 , & print ) ;
2022-10-13 09:44:57 -04:00
traceback_exception_common ( false , & print , n_args , pos_args , kw_args ) ;
2022-10-13 10:29:21 -04:00
mp_obj_t output = mp_obj_new_str_from_vstr ( & mp_type_str , & vstr ) ;
return mp_obj_new_list ( 1 , & output ) ;
2021-08-08 12:03:03 -04:00
}
2021-10-07 16:36:06 -04:00
STATIC MP_DEFINE_CONST_FUN_OBJ_KW ( traceback_format_exception_obj , 0 , traceback_format_exception ) ;
2021-08-08 12:03:03 -04:00
2022-09-27 16:21:42 -04:00
//| def print_exception(
2022-10-13 10:24:46 -04:00
//| exc: BaseException | Type[BaseException],
//| /,
//| value: Optional[BaseException] = None,
//| tb: Optional[TracebackType] = None,
2022-09-27 16:21:42 -04:00
//| limit: Optional[int] = None,
//| file: Optional[io.FileIO] = None,
//| chain: Optional[bool] = True,
//| ) -> None:
2021-07-27 14:30:01 -04:00
//| """Prints exception information and stack trace entries.
//|
2022-10-13 10:24:46 -04:00
//| If the exception value is passed in ``exc``, then this exception value and its
//| associated traceback are used. This is compatible with CPython 3.10 and newer.
//|
//| If the exception value is passed in ``value``, then any value passed in for
//| ``exc`` is ignored. ``value`` is used as the exception value and the
//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is None,
//| no traceback will be shown. This is compatible with CPython 3.5 and
//| newer.
//|
//| :param exc: The exception. Must be an instance of `BaseException`. Unused if value is specified.
//| :param value: If specified, is used in place of ``exc``.
//| :param tb: When value is alsp specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed.
2021-07-27 14:30:01 -04:00
//| :param int limit: Print up to limit stack trace entries (starting from the caller’ s 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.
2022-12-02 11:47:50 -05:00
//| :param bool chain: If `True` then chained exceptions will be printed.
2021-07-27 14:30:01 -04:00
//|
//| """
//| ...
2022-09-29 20:22:32 -04:00
//|
2021-08-08 12:03:03 -04:00
2021-07-27 14:30:01 -04:00
STATIC mp_obj_t traceback_print_exception ( size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
mp_print_t print = mp_plat_print ;
2022-10-13 09:44:57 -04:00
traceback_exception_common ( true , & print , n_args , pos_args , kw_args ) ;
2021-07-27 14:30:01 -04:00
return mp_const_none ;
}
2021-10-07 16:36:06 -04:00
STATIC MP_DEFINE_CONST_FUN_OBJ_KW ( traceback_print_exception_obj , 0 , traceback_print_exception ) ;
2021-07-27 14:30:01 -04:00
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
2021-08-08 12:03:03 -04:00
{ MP_ROM_QSTR ( MP_QSTR_format_exception ) , MP_ROM_PTR ( & traceback_format_exception_obj ) } ,
2021-07-27 14:30:01 -04:00
{ 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 ,
} ;
Convert more modules to use MP_REGISTER_MODULE
Convert neopixel_write, onewireio, ps2io, pulseio, pwmio, rainbowio, random, rgbmatrix, rotaryio, rtc, sdcardio, sharpdisplay, _stage, storage, struct, supervisor, synthio, touchio, traceback, usb_cdc, usb_hid, usb_midi, and vectorio modules to use MP_REGISTER_MODULE.
Related to #5183.
2021-08-30 22:29:51 -04:00
2023-08-07 20:45:57 -04:00
MP_REGISTER_MODULE ( MP_QSTR_traceback , traceback_module ) ;