Skip to content

Commit 4048702

Browse files
authored
Improve missing field errors (#747)
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.
1 parent ec3cd05 commit 4048702

2 files changed

Lines changed: 13 additions & 2 deletions

File tree

serde/de.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1288,10 +1288,18 @@ def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=Non
12881288
{% endif %}
12891289
12901290
{% for f in fields %}
1291+
{% set field_arg = arg(f,loop.index-1) %}
12911292
{% if f.flatten and is_flatten_dict(f.type) %}
12921293
__{{f.name}} = __flatten_extra
1294+
{% elif field_arg.supports_default() %}
1295+
__{{f.name}} = {{rvalue(field_arg)}}
12931296
{% else %}
1294-
__{{f.name}} = {{rvalue(arg(f,loop.index-1))}}
1297+
try:
1298+
__{{f.name}} = {{rvalue(field_arg)}}
1299+
except KeyError:
1300+
raise SerdeError(
1301+
"missing required field '{{field_arg.conv_name()}}' while deserializing {{class_name}}"
1302+
)
12951303
{% endif %}
12961304
{% endfor %}
12971305
@@ -1503,6 +1511,7 @@ def render_from_dict(
15031511
fields=fields,
15041512
type_check=type_check,
15051513
cls_type_vars=get_type_var_names(cls),
1514+
class_name=typename(cls),
15061515
rvalue=renderer.render,
15071516
arg=functools.partial(to_arg, rename_all=rename_all),
15081517
deny_unknown_fields=deny_unknown_fields,

tests/test_basics.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,9 +994,11 @@ class Foo:
994994
class Bar:
995995
pass
996996

997-
with pytest.raises(serde.SerdeError):
997+
with pytest.raises(serde.SerdeError) as exc_info:
998998
serde.from_dict(Foo, {})
999999

1000+
assert str(exc_info.value) == "missing required field 'a' while deserializing Foo"
1001+
10001002

10011003
def test_user_error() -> None:
10021004
class MyException(Exception):

0 commit comments

Comments
 (0)