Skip to content

Commit b6f86e1

Browse files
committed
Recursively print chained exceptions
1 parent f316924 commit b6f86e1

File tree

5 files changed

+138
-9
lines changed

5 files changed

+138
-9
lines changed

locale/circuitpython.pot

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ msgstr ""
106106
msgid "%q in use"
107107
msgstr ""
108108

109-
#: py/obj.c py/objstr.c py/objstrunicode.c
109+
#: py/objstr.c py/objstrunicode.c
110110
msgid "%q index out of range"
111111
msgstr ""
112112

@@ -171,11 +171,11 @@ msgstr ""
171171
msgid "%q must be an int"
172172
msgstr ""
173173

174-
#: py/argcheck.c
174+
#: py/argcheck.c py/obj.c
175175
msgid "%q must be of type %q"
176176
msgstr ""
177177

178-
#: shared-bindings/digitalio/Pull.c
178+
#: py/objexcept.c shared-bindings/digitalio/Pull.c
179179
msgid "%q must be of type %q or None"
180180
msgstr ""
181181

@@ -894,6 +894,10 @@ msgstr ""
894894
msgid "Drive mode not used when direction is input."
895895
msgstr ""
896896

897+
#: py/obj.c
898+
msgid "During handling of the above exception, another exception occurred:"
899+
msgstr ""
900+
897901
#: shared-bindings/aesio/aes.c
898902
msgid "ECB only operates on 16 bytes at a time"
899903
msgstr ""
@@ -2007,6 +2011,10 @@ msgid ""
20072011
"exit safe mode."
20082012
msgstr ""
20092013

2014+
#: py/obj.c
2015+
msgid "The above exception was the direct cause of the following exception:"
2016+
msgstr ""
2017+
20102018
#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h
20112019
msgid "The central button was pressed at start up.\n"
20122020
msgstr ""
@@ -3153,7 +3161,7 @@ msgid "index is out of bounds"
31533161
msgstr ""
31543162

31553163
#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c
3156-
#: ports/espressif/common-hal/pulseio/PulseIn.c py/obj.c
3164+
#: ports/espressif/common-hal/pulseio/PulseIn.c
31573165
#: shared-bindings/bitmaptools/__init__.c
31583166
msgid "index out of range"
31593167
msgstr ""
@@ -3336,10 +3344,6 @@ msgstr ""
33363344
msgid "invalid syntax for number"
33373345
msgstr ""
33383346

3339-
#: py/objexcept.c
3340-
msgid "invalid traceback"
3341-
msgstr ""
3342-
33433347
#: py/objtype.c
33443348
msgid "issubclass() arg 1 must be a class"
33453349
msgstr ""

py/obj.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,33 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
142142
mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind);
143143
}
144144

145+
static void mp_obj_print_inner_exception(const mp_print_t *print, mp_obj_t self_in, mp_int_t limit) {
146+
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
147+
mp_obj_exception_t *self = mp_obj_exception_get_native(self_in);
148+
const compressed_string_t *msg = MP_ERROR_TEXT("During handling of the above exception, another exception occurred:");
149+
mp_obj_exception_t *inner = NULL;
150+
if (self->cause) {
151+
msg = MP_ERROR_TEXT("The above exception was the direct cause of the following exception:");
152+
inner = self->cause;
153+
} else if (!self->suppress_context) {
154+
inner = self->context;
155+
}
156+
if (inner && !inner->marked) {
157+
inner->marked = true;
158+
mp_obj_print_exception_with_limit(print, MP_OBJ_FROM_PTR(inner), limit);
159+
inner->marked = false;
160+
mp_printf(print, "\n");
161+
mp_cprintf(print, msg);
162+
mp_printf(print, "\n\n");
163+
}
164+
#endif
165+
}
166+
145167
// helper function to print an exception with traceback
146168
void mp_obj_print_exception_with_limit(const mp_print_t *print, mp_obj_t exc, mp_int_t limit) {
147169
if (mp_obj_is_exception_instance(exc) && stack_ok()) {
170+
mp_obj_print_inner_exception(print, exc, limit);
171+
148172
size_t n, *values;
149173
mp_obj_exception_get_traceback(exc, &n, &values);
150174
if (n > 0) {

py/objexcept.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ typedef struct _mp_obj_exception_t {
3434
mp_obj_base_t base;
3535
mp_obj_tuple_t *args;
3636
mp_obj_traceback_t *traceback;
37-
mp_obj_t cause, context;
37+
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
38+
struct _mp_obj_exception_t *cause, *context;
3839
bool suppress_context;
40+
bool marked;
41+
#endif
3942
} mp_obj_exception_t;
4043

4144
void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
try:
2+
Exception().__cause__
3+
except AttributeError:
4+
print("SKIP")
5+
raise SystemExit
6+
7+
try:
8+
import traceback
9+
except:
10+
print("SKIP")
11+
raise SystemExit
12+
13+
14+
def print_exc_info(e):
15+
print("-" * 72)
16+
traceback.print_exception(None, e, e.__traceback__)
17+
print("-" * 72)
18+
print()
19+
20+
21+
try:
22+
try:
23+
1 / 0
24+
except Exception as inner:
25+
raise RuntimeError() from inner
26+
except Exception as e:
27+
print_exc_info(e)
28+
print()
29+
30+
try:
31+
try:
32+
1 / 0
33+
except Exception as inner:
34+
raise RuntimeError() from OSError()
35+
except Exception as e:
36+
print_exc_info(e)
37+
print()
38+
39+
40+
try:
41+
try:
42+
1 / 0
43+
except Exception as inner:
44+
raise RuntimeError()
45+
except Exception as e:
46+
print_exc_info(e)
47+
print()
48+
49+
try:
50+
try:
51+
1 / 0
52+
except Exception as inner:
53+
raise RuntimeError() from None
54+
except Exception as e:
55+
print_exc_info(e)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
------------------------------------------------------------------------
2+
Traceback (most recent call last):
3+
File "circuitpython/traceback_test_chained.py", line 23, in <module>
4+
ZeroDivisionError: division by zero
5+
6+
The above exception was the direct cause of the following exception:
7+
8+
Traceback (most recent call last):
9+
File "circuitpython/traceback_test_chained.py", line 25, in <module>
10+
RuntimeError:
11+
------------------------------------------------------------------------
12+
13+
14+
------------------------------------------------------------------------
15+
OSError:
16+
17+
The above exception was the direct cause of the following exception:
18+
19+
Traceback (most recent call last):
20+
File "circuitpython/traceback_test_chained.py", line 34, in <module>
21+
RuntimeError:
22+
------------------------------------------------------------------------
23+
24+
25+
------------------------------------------------------------------------
26+
Traceback (most recent call last):
27+
File "circuitpython/traceback_test_chained.py", line 42, in <module>
28+
ZeroDivisionError: division by zero
29+
30+
During handling of the above exception, another exception occurred:
31+
32+
Traceback (most recent call last):
33+
File "circuitpython/traceback_test_chained.py", line 44, in <module>
34+
RuntimeError:
35+
------------------------------------------------------------------------
36+
37+
38+
------------------------------------------------------------------------
39+
Traceback (most recent call last):
40+
File "circuitpython/traceback_test_chained.py", line 53, in <module>
41+
RuntimeError:
42+
------------------------------------------------------------------------
43+

0 commit comments

Comments
 (0)