Skip to content

Commit 0de3e52

Browse files
committed
Recursively print chained exceptions
1 parent 88acdb3 commit 0de3e52

File tree

5 files changed

+135
-6
lines changed

5 files changed

+135
-6
lines changed

locale/circuitpython.pot

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ msgstr ""
178178
msgid "%q must be of type %q"
179179
msgstr ""
180180

181-
#: shared-bindings/digitalio/Pull.c
181+
#: py/objexcept.c shared-bindings/digitalio/Pull.c
182182
msgid "%q must be of type %q or None"
183183
msgstr ""
184184

@@ -882,6 +882,10 @@ msgstr ""
882882
msgid "Drive mode not used when direction is input."
883883
msgstr ""
884884

885+
#: py/obj.c
886+
msgid "During handling of the above exception, another exception occurred:"
887+
msgstr ""
888+
885889
#: shared-bindings/aesio/aes.c
886890
msgid "ECB only operates on 16 bytes at a time"
887891
msgstr ""
@@ -1979,6 +1983,10 @@ msgid ""
19791983
"exit safe mode."
19801984
msgstr ""
19811985

1986+
#: py/obj.c
1987+
msgid "The above exception was the direct cause of the following exception:"
1988+
msgstr ""
1989+
19821990
#: shared-bindings/rgbmatrix/RGBMatrix.c
19831991
msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30"
19841992
msgstr ""
@@ -3308,10 +3316,6 @@ msgstr ""
33083316
msgid "invalid syntax for number"
33093317
msgstr ""
33103318

3311-
#: py/objexcept.c
3312-
msgid "invalid traceback"
3313-
msgstr ""
3314-
33153319
#: py/objtype.c
33163320
msgid "issubclass() arg 1 must be a class"
33173321
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)