mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-28 10:49:56 +02:00
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:
co-authored by
William FH
parent
2c98c59fca
commit
426728f8d1
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user