Skip to content

Commit 1a3c471

Browse files
authored
Merge pull request #9266 from jepler/improve-exception-chaining
Fix exception chaining for non-built-in exceptions
2 parents 0de50aa + 94db02f commit 1a3c471

File tree

3 files changed

+149
-5
lines changed

3 files changed

+149
-5
lines changed

py/obj.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,30 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
143143
mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind);
144144
}
145145

146+
// CIRCUITPY-CHANGE
147+
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
148+
static mp_obj_t mp_load_attr_or_none(mp_obj_t base, qstr attr) {
149+
mp_obj_t dest[2];
150+
mp_load_method_protected(base, attr, dest, true);
151+
return dest[0] == MP_OBJ_NULL ? mp_const_none : dest[0];
152+
}
153+
#endif
154+
146155
// CIRCUITPY-CHANGE
147156
static void mp_obj_print_inner_exception(const mp_print_t *print, mp_obj_t self_in, mp_int_t limit) {
148157
#if MICROPY_CPYTHON_EXCEPTION_CHAIN
149158
mp_obj_exception_t *self = mp_obj_exception_get_native(self_in);
150159
mp_rom_error_text_t msg = MP_ERROR_TEXT("During handling of the above exception, another exception occurred:");
151-
mp_obj_exception_t *inner = NULL;
152-
if (self->cause) {
160+
mp_obj_t inner_obj = mp_const_none;
161+
if (!self->suppress_context) {
162+
inner_obj = mp_load_attr_or_none(self_in, MP_QSTR___context__);
163+
}
164+
if (inner_obj == mp_const_none) {
153165
msg = MP_ERROR_TEXT("The above exception was the direct cause of the following exception:");
154-
inner = self->cause;
155-
} else if (!self->suppress_context) {
156-
inner = self->context;
166+
inner_obj = mp_load_attr_or_none(self_in, MP_QSTR___cause__);
157167
}
168+
mp_obj_exception_t *inner = mp_obj_is_exception_instance(inner_obj) ?
169+
mp_obj_exception_get_native(inner_obj) : NULL;
158170
if (inner && !inner->marked) {
159171
inner->marked = true;
160172
mp_obj_print_exception_with_limit(print, MP_OBJ_FROM_PTR(inner), limit);

tests/circuitpython/traceback_test_chained.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,60 @@ def print_exc_info(e, chain=True):
7272
print_exc_info(e, chain=False)
7373
print_exc_info(e)
7474
print()
75+
76+
class SomeException(RuntimeError):
77+
pass
78+
79+
try:
80+
try:
81+
raise Exception("inner")
82+
except Exception as inner:
83+
raise SomeException("outer") from inner
84+
except Exception as e:
85+
print_exc_info(e)
86+
87+
try:
88+
try:
89+
raise Exception("inner")
90+
except Exception as inner:
91+
l = inner
92+
raise SomeException("outer") from l
93+
except Exception as e:
94+
print_exc_info(e)
95+
print()
96+
97+
try:
98+
try:
99+
raise SomeException("inner")
100+
except Exception as inner:
101+
raise Exception("outer") from inner
102+
except Exception as e:
103+
print_exc_info(e)
104+
105+
try:
106+
try:
107+
raise SomeException("inner")
108+
except Exception as inner:
109+
l = inner
110+
raise Exception("outer") from l
111+
except Exception as e:
112+
print_exc_info(e)
113+
print()
114+
115+
try:
116+
try:
117+
raise SomeException("inner")
118+
except Exception as inner:
119+
raise SomeException("outer") from inner
120+
except Exception as e:
121+
print_exc_info(e)
122+
123+
try:
124+
try:
125+
raise SomeException("inner")
126+
except Exception as inner:
127+
l = inner
128+
raise SomeException("outer") from l
129+
except Exception as e:
130+
print_exc_info(e)
131+
print()

tests/circuitpython/traceback_test_chained.py.exp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,78 @@ ZeroDivisionError: division by zero
7474
------------------------------------------------------------------------
7575

7676

77+
------------------------------------------------------------------------
78+
Traceback (most recent call last):
79+
File "circuitpython/traceback_test_chained.py", line 81, in <module>
80+
Exception: inner
81+
82+
During handling of the above exception, another exception occurred:
83+
84+
Traceback (most recent call last):
85+
File "circuitpython/traceback_test_chained.py", line 83, in <module>
86+
SomeException: outer
87+
------------------------------------------------------------------------
88+
89+
------------------------------------------------------------------------
90+
Traceback (most recent call last):
91+
File "circuitpython/traceback_test_chained.py", line 89, in <module>
92+
Exception: inner
93+
94+
The above exception was the direct cause of the following exception:
95+
96+
Traceback (most recent call last):
97+
File "circuitpython/traceback_test_chained.py", line 92, in <module>
98+
SomeException: outer
99+
------------------------------------------------------------------------
100+
101+
102+
------------------------------------------------------------------------
103+
Traceback (most recent call last):
104+
File "circuitpython/traceback_test_chained.py", line 99, in <module>
105+
RuntimeError: inner
106+
107+
The above exception was the direct cause of the following exception:
108+
109+
Traceback (most recent call last):
110+
File "circuitpython/traceback_test_chained.py", line 101, in <module>
111+
Exception: outer
112+
------------------------------------------------------------------------
113+
114+
------------------------------------------------------------------------
115+
Traceback (most recent call last):
116+
File "circuitpython/traceback_test_chained.py", line 107, in <module>
117+
RuntimeError: inner
118+
119+
The above exception was the direct cause of the following exception:
120+
121+
Traceback (most recent call last):
122+
File "circuitpython/traceback_test_chained.py", line 110, in <module>
123+
Exception: outer
124+
------------------------------------------------------------------------
125+
126+
127+
------------------------------------------------------------------------
128+
Traceback (most recent call last):
129+
File "circuitpython/traceback_test_chained.py", line 117, in <module>
130+
RuntimeError: inner
131+
132+
During handling of the above exception, another exception occurred:
133+
134+
Traceback (most recent call last):
135+
File "circuitpython/traceback_test_chained.py", line 119, in <module>
136+
SomeException: outer
137+
------------------------------------------------------------------------
138+
139+
------------------------------------------------------------------------
140+
Traceback (most recent call last):
141+
File "circuitpython/traceback_test_chained.py", line 125, in <module>
142+
RuntimeError: inner
143+
144+
The above exception was the direct cause of the following exception:
145+
146+
Traceback (most recent call last):
147+
File "circuitpython/traceback_test_chained.py", line 128, in <module>
148+
SomeException: outer
149+
------------------------------------------------------------------------
150+
151+

0 commit comments

Comments
 (0)