Details
Description
serializable_dataclass doesn't handle from __future__ import annotations (PEP 563). When the import is present, all annotations become strings at runtime, which causes two problems:
-
Auto-serialization of nested SerializableDataclass fields fails. The generated serialize() doesn't recognize that e.g. list[Inner] contains a SerializableDataclass, so nested objects are left as-is and json.dumps() raises TypeError: Object of type ... is not JSON serializable.
-
Plain defaults after serializable_field cause TypeError: non-default argument follows default argument. When annotations are strings, it appears that the decorator's pre-processing of fields mishandles plain = value defaults, causing dataclasses.dataclass() to reject the field ordering.
Reproducer
from __future__ import annotations
from muutils.json_serialize import (
SerializableDataclass,
serializable_dataclass,
serializable_field,
)
import json
@serializable_dataclass
class Inner(SerializableDataclass):
value: int = 0
@serializable_dataclass
class Outer(SerializableDataclass):
items: list[Inner] = serializable_field(default_factory=list)
outer = Outer(items=[Inner(value=42)])
data = outer.serialize()
# data["items"] is [Inner(value=42)] instead of [{"value": 42, ...}]
json.dumps(data) # TypeError: Object of type Inner is not JSON serializable
Workaround
Add explicit serialization_fn/deserialize_fn for any field containing nested SerializableDataclass objects:
items: list[Inner] = serializable_field(
default_factory=list,
serialization_fn=lambda items: [i.serialize() for i in items],
deserialize_fn=lambda items: [Inner.load(i) for i in items],
)
For the field-ordering issue, use kw_only=True:
@serializable_dataclass(kw_only=True)
class MyConfig(SerializableDataclass):
...
Details
Description
serializable_dataclassdoesn't handlefrom __future__ import annotations(PEP 563). When the import is present, all annotations become strings at runtime, which causes two problems:Auto-serialization of nested
SerializableDataclassfields fails. The generatedserialize()doesn't recognize that e.g.list[Inner]contains aSerializableDataclass, so nested objects are left as-is andjson.dumps()raisesTypeError: Object of type ... is not JSON serializable.Plain defaults after
serializable_fieldcauseTypeError: non-default argument follows default argument. When annotations are strings, it appears that the decorator's pre-processing of fields mishandles plain= valuedefaults, causingdataclasses.dataclass()to reject the field ordering.Reproducer
Workaround
Add explicit
serialization_fn/deserialize_fnfor any field containing nestedSerializableDataclassobjects:For the field-ordering issue, use
kw_only=True: