feat: add str-fallback for custom types in msgpack serialization

Objects whose class defines __str__ (not inherited from object) are now
serialized as EXT_CONSTRUCTOR_SINGLE_ARG with str(obj), enabling
round-trip serde for types like bson.ObjectId without new dependencies.

Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
This commit is contained in:
open-swe[bot]
2026-04-13 16:22:14 +00:00
co-authored by William FH
parent 2c98c59fca
commit 426728f8d1
2 changed files with 46 additions and 0 deletions
@@ -494,6 +494,13 @@ def _msgpack_default(obj: Any) -> str | ormsgpack.Ext:
elif isinstance(obj, BaseException):
return repr(obj)
elif type(obj).__str__ is not object.__str__:
return ormsgpack.Ext(
EXT_CONSTRUCTOR_SINGLE_ARG,
_msgpack_enc(
(obj.__class__.__module__, obj.__class__.__name__, str(obj)),
),
)
else:
raise TypeError(f"Object of type {obj.__class__.__name__} is not serializable")
+39
View File
@@ -93,6 +93,19 @@ class MyEnum(Enum):
BAR = "bar"
class StrReconstructable:
"""Mimics types like bson.ObjectId that round-trip via str()."""
def __init__(self, value: str = "default") -> None:
self.value = value
def __str__(self) -> str:
return self.value
def __eq__(self, other: object) -> bool:
return isinstance(other, StrReconstructable) and self.value == other.value
@dataclasses_json.dataclass_json
@dataclasses.dataclass
class Person:
@@ -580,6 +593,32 @@ def test_msgpack_safe_types_no_warning(caplog: pytest.LogCaptureFixture) -> None
assert result is not None
def test_serde_str_reconstructable_roundtrip() -> None:
"""Objects with custom __str__ serialize via the str-fallback and round-trip."""
serde = JsonPlusSerializer(
allowed_msgpack_modules=[
(StrReconstructable.__module__, StrReconstructable.__name__)
]
)
obj = StrReconstructable("abc123")
dumped = serde.dumps_typed(obj)
assert dumped[0] == "msgpack"
result = serde.loads_typed(dumped)
assert isinstance(result, StrReconstructable)
assert result == obj
def test_serde_str_fallback_not_triggered_for_plain_object() -> None:
"""Objects without custom __str__ still raise TypeError."""
serde = JsonPlusSerializer()
class PlainObj:
pass
with pytest.raises(ormsgpack.MsgpackEncodeError):
serde.dumps_typed(PlainObj())
def test_msgpack_pydantic_warns_by_default(caplog: pytest.LogCaptureFixture) -> None:
"""Pydantic models not in allowlist should log warning but still deserialize."""
current = _lg_msgpack.STRICT_MSGPACK_ENABLED