Skip to content

Commit 91db473

Browse files
authored
Skip non-serde fields correctly (#702)
1 parent 421772d commit 91db473

File tree

3 files changed

+47
-6
lines changed

3 files changed

+47
-6
lines changed

serde/de.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ def to_iter_arg(f: DeField[T], *args: Any, **kwargs: Any) -> DeField[T]:
11941194

11951195

11961196
def renderable(f: DeField[Any]) -> bool:
1197-
return f.init
1197+
return f.init and not f.skip
11981198

11991199

12001200
jinja2_env = jinja2.Environment(

serde/se.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -600,24 +600,24 @@ def {{func}}(obj, reuse_instances = None, convert_sets = None, skip_none = False
600600
601601
res = {}
602602
{% for f in fields -%}
603-
subres = {{rvalue(f)}}
604603
{% if not f.skip -%}
605-
{% if lvalue(f) == '__FLATTEN_DICT__' -%}
604+
subres = {{rvalue(f)}}
605+
{% if lvalue(f) == '__FLATTEN_DICT__' -%}
606606
# Merge flattened dict into result (declared fields take precedence)
607607
if subres:
608608
for __k, __v in subres.items():
609609
if __k not in res:
610610
res[__k] = __v
611-
{% elif f.skip_if -%}
611+
{% elif f.skip_if -%}
612612
if not {{f.skip_if.name}}(subres):
613613
{{lvalue(f)}} = subres
614-
{% else -%}
614+
{% else -%}
615615
if skip_none:
616616
if subres is not None:
617617
{{lvalue(f)}} = subres
618618
else:
619619
{{lvalue(f)}} = subres
620-
{% endif -%}
620+
{% endif -%}
621621
{% endif %}
622622
623623
{% endfor -%}

tests/test_basics.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,47 @@ class Foo:
780780
assert str(ex.value).startswith("Unsupported type: UnsupportedClass")
781781

782782

783+
def test_skip_with_unsupported_types() -> None:
784+
class UnsupportedClass:
785+
"""A class that is NOT decorated with @serde."""
786+
787+
def __init__(self, value: int = 42) -> None:
788+
self.value = value
789+
790+
# Decoration should succeed
791+
@serde.serde
792+
class Foo:
793+
name: str
794+
internal: UnsupportedClass = serde.field(default_factory=UnsupportedClass, skip=True)
795+
796+
# Serialization should work
797+
f = Foo(name="test")
798+
assert serde.to_dict(f) == {"name": "test"}
799+
800+
# Deserialization should work, using default for skipped field
801+
restored = serde.from_dict(Foo, {"name": "test"})
802+
assert restored.name == "test"
803+
assert isinstance(restored.internal, UnsupportedClass)
804+
805+
# Also test with List of unsupported types
806+
@serde.serde
807+
class Bar:
808+
name: str
809+
items: list[UnsupportedClass] = serde.field(default_factory=list, skip=True)
810+
811+
b = Bar(name="test")
812+
b.items.append(UnsupportedClass(1))
813+
b.items.append(UnsupportedClass(2))
814+
815+
# Serialization should work even with non-empty list
816+
assert serde.to_dict(b) == {"name": "test"}
817+
818+
# Deserialization should work
819+
restored_bar = serde.from_dict(Bar, {"name": "test"})
820+
assert restored_bar.name == "test"
821+
assert restored_bar.items == []
822+
823+
783824
def test_dataclass_inheritance() -> None:
784825
@serde.serde
785826
class Base:

0 commit comments

Comments
 (0)