Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -4189,6 +4189,10 @@ msgstr ""
msgid "timestamp out of range for platform time_t"
msgstr ""

#: shared-bindings/traceback/__init__.c
msgid "Supply both or neither of %q and %q"
msgstr ""

#: shared-bindings/traceback/__init__.c
msgid "file write is not available"
msgstr ""
Expand Down
50 changes: 29 additions & 21 deletions shared-bindings/traceback/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,18 @@ static void traceback_exception_common(bool is_print_exception, mp_print_t *prin
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;
mp_obj_t tb_obj = args[ARG_tb].u_obj;

// Both or neither of value and tb must be supplied.
if ((value != MP_OBJ_NULL && tb_obj == MP_OBJ_NULL) ||
(value == MP_OBJ_NULL && tb_obj != MP_OBJ_NULL)) {
mp_raise_ValueError_varg(MP_ERROR_TEXT("Supply both or neither of %q and %q"), MP_QSTR_value, MP_QSTR_tb);
}

if (value == MP_OBJ_NULL) {
value = args[ARG_exc].u_obj;
}
mp_obj_t tb_obj = args[ARG_tb].u_obj;

mp_obj_t limit_obj = args[ARG_limit].u_obj;
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
bool chain = args[ARG_chain].u_bool;
Expand Down Expand Up @@ -105,21 +113,21 @@ static void traceback_exception_common(bool is_print_exception, mp_print_t *prin
//| def format_exception(
//| exc: BaseException | Type[BaseException],
//| /,
//| value: Optional[BaseException] = None,
//| value: BaseException,
//| tb: Optional[TracebackType] = None,
//| limit: Optional[int] = None,
//| chain: Optional[bool] = True,
//| ) -> List[str]:
//| """Format a stack trace and the exception information.
//|
//| 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 ``exc``, and ``value`` and ``tb`` are not supplied,
//| 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.
//| If the exception value is passed in ``value``, then both ``value`` and ``tb`` must be supplied.
//| 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.
//|
//| The arguments have the same meaning as the corresponding arguments
//| to print_exception(). The return value is a list of strings, each
Expand All @@ -128,8 +136,8 @@ static void traceback_exception_common(bool is_print_exception, mp_print_t *prin
//| printed as does print_exception().
//|
//| :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.
//| :param value: If specified, is used in place of ``exc``, and ``tb`` must also be specified.
//| :param tb: When ``value`` is also specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed.
//| :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 bool chain: If `True` then chained exceptions will be printed.
Expand All @@ -150,26 +158,26 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(traceback_format_exception_obj, 0, traceback_f
//| def print_exception(
//| exc: BaseException | Type[BaseException],
//| /,
//| value: Optional[BaseException] = None,
//| value: BaseException,
//| tb: Optional[TracebackType] = None,
//| limit: Optional[int] = None,
//| file: Optional[io.FileIO] = None,
//| chain: Optional[bool] = True,
//| ) -> None:
//| """Prints exception information and stack trace entries.
//|
//| 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 ``exc``, and ``value`` and ``tb`` are not supplied,
//| 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.
//| If the exception value is passed in ``value``, then both ``value`` and ``tb`` must be supplied.
//| 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.
//| :param value: If specified, is used in place of ``exc``, and ``tb`` must also be specified.
//| :param tb: When ``value`` is also specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed.
//| :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
Expand Down
16 changes: 16 additions & 0 deletions tests/circuitpython/traceback_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ def fun():
print("\nLimit=-1 Trace:")
print("".join(traceback.format_exception(None, exc, exc.__traceback__, limit=-1)), end="")

# value and tb must both be supplied or neither
print()
try:
fun()
except Exception as exc:
try:
traceback.print_exception(None, value=exc)
print("Should have raised ValueError for missing tb arg")
except ValueError:
print("ValueError for missing tb arg, as expected")
try:
traceback.print_exception(None, tb=None)
print("Should have raised ValueError for missing value arg")
except ValueError:
print("ValueError for missing value arg, as expected")


class NonNativeException(Exception):
pass
Expand Down
Loading