From 0c0490e1fc916387fb2b8ed25bc01ef971eb56e5 Mon Sep 17 00:00:00 2001 From: Allan Chain <36528777+AllanChain@users.noreply.github.com> Date: Tue, 5 May 2026 15:30:44 +0800 Subject: [PATCH] Improve missing field errors Missing required fields currently surface as a bare `SerdeError("'field'")`. Here we catch that `KeyError` at the required-field lookup site so pyserde raises a contextual `SerdeError` with the field and class name, while leaving defaulted-field fallback behavior unchanged. --- serde/de.py | 11 ++++++++++- tests/test_basics.py | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/serde/de.py b/serde/de.py index cf242564..d822050f 100644 --- a/serde/de.py +++ b/serde/de.py @@ -1288,10 +1288,18 @@ def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=Non {% endif %} {% for f in fields %} + {% set field_arg = arg(f,loop.index-1) %} {% if f.flatten and is_flatten_dict(f.type) %} __{{f.name}} = __flatten_extra + {% elif field_arg.supports_default() %} + __{{f.name}} = {{rvalue(field_arg)}} {% else %} - __{{f.name}} = {{rvalue(arg(f,loop.index-1))}} + try: + __{{f.name}} = {{rvalue(field_arg)}} + except KeyError: + raise SerdeError( + "missing required field '{{field_arg.conv_name()}}' while deserializing {{class_name}}" + ) {% endif %} {% endfor %} @@ -1503,6 +1511,7 @@ def render_from_dict( fields=fields, type_check=type_check, cls_type_vars=get_type_var_names(cls), + class_name=typename(cls), rvalue=renderer.render, arg=functools.partial(to_arg, rename_all=rename_all), deny_unknown_fields=deny_unknown_fields, diff --git a/tests/test_basics.py b/tests/test_basics.py index bce48746..f0957582 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -994,9 +994,11 @@ class Foo: class Bar: pass - with pytest.raises(serde.SerdeError): + with pytest.raises(serde.SerdeError) as exc_info: serde.from_dict(Foo, {}) + assert str(exc_info.value) == "missing required field 'a' while deserializing Foo" + def test_user_error() -> None: class MyException(Exception):