Skip to content

Commit 4ce20fa

Browse files
provinzkrautjcrist
andauthored
fix wrapping ValidationError and DecodeError in ValidationError in dec_hook #1012 (#1013)
* fix * Fixup --------- Co-authored-by: Jim Crist-Harif <[email protected]>
1 parent 20cc59d commit 4ce20fa

2 files changed

Lines changed: 34 additions & 6 deletions

File tree

‎src/msgspec/_core.c‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5282,14 +5282,22 @@ ms_maybe_wrap_validation_error(PathNode *path) {
52825282
/* If null, some other c-extension has borked, just return */
52835283
if (exc_type == NULL) return;
52845284

5285+
MsgspecState *mod = msgspec_get_global_state();
5286+
52855287
/* If it's a TypeError or ValueError, wrap it in a ValidationError.
5286-
* Otherwise we reraise the original error below */
5288+
* Otherwise we reraise the original error below.
5289+
* Since DecodeError (and ValidationError) subclass from ValueError, we need
5290+
* to special case them below - we don't wrap in those cases. */
52875291
if (
5288-
PyType_IsSubtype(
5289-
(PyTypeObject *)exc_type, (PyTypeObject *)PyExc_ValueError
5290-
) ||
5291-
PyType_IsSubtype(
5292-
(PyTypeObject *)exc_type, (PyTypeObject *)PyExc_TypeError
5292+
!PyType_IsSubtype((PyTypeObject *)exc_type, (PyTypeObject *)mod->DecodeError)
5293+
&&
5294+
(
5295+
PyType_IsSubtype(
5296+
(PyTypeObject *)exc_type, (PyTypeObject *)PyExc_ValueError
5297+
) ||
5298+
PyType_IsSubtype(
5299+
(PyTypeObject *)exc_type, (PyTypeObject *)PyExc_TypeError
5300+
)
52935301
)
52945302
) {
52955303
PyObject *exc_type2, *exc2, *tb2;

‎tests/unit/test_common.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,26 @@ class Custom(metaclass=Metaclass):
292292
with pytest.raises(TypeError, match="Oh no!"):
293293
dec.decode(msg)
294294

295+
@pytest.mark.parametrize(
296+
"base_error_cls", [msgspec.ValidationError, msgspec.DecodeError]
297+
)
298+
def test_dec_hook_validation_error_subclass_propagates_directly(
299+
self, proto, base_error_cls
300+
):
301+
class MyError(base_error_cls):
302+
pass
303+
304+
class Foo:
305+
pass
306+
307+
def dec_hook(tp, val):
308+
raise MyError("custom message")
309+
310+
dec = proto.Decoder(type=Foo, dec_hook=dec_hook)
311+
312+
with pytest.raises(MyError, match="custom message"):
313+
dec.decode(b"[]")
314+
295315

296316
@pytest.mark.skipif(
297317
PY312,

0 commit comments

Comments
 (0)