mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-22 17:45:09 +02:00
fix: dedup deserialization warnings and add register_safe_types utility
Warnings in _check_allowed and _check_allowed_method now track already-warned types/methods per ext_hook closure, so the same warning is only emitted once. Added register_safe_types() to _msgpack.py as a public API for users to add custom types to the global safe-types set, exported from langgraph.checkpoint.serde. Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
This commit is contained in:
co-authored by
Sydney Runkle
parent
6719d34023
commit
a01c122452
@@ -983,3 +983,109 @@ def test_msgpack_nested_pydantic_serializes_as_dict(
|
||||
# No blocking should occur - inner is serialized as dict, not ext
|
||||
assert "blocked" not in caplog.text.lower()
|
||||
assert result == obj
|
||||
|
||||
|
||||
def test_msgpack_warning_dedup_default_mode(caplog: pytest.LogCaptureFixture) -> None:
|
||||
"""Repeated deserialization of the same unregistered type should only warn once."""
|
||||
current = _lg_msgpack.STRICT_MSGPACK_ENABLED
|
||||
_lg_msgpack.STRICT_MSGPACK_ENABLED = False
|
||||
serde = JsonPlusSerializer()
|
||||
|
||||
obj = AnotherPydantic(foo="test")
|
||||
dumped = serde.dumps_typed(obj)
|
||||
|
||||
caplog.clear()
|
||||
serde.loads_typed(dumped)
|
||||
first_count = caplog.text.lower().count("unregistered type")
|
||||
assert first_count >= 1
|
||||
|
||||
caplog.clear()
|
||||
serde.loads_typed(dumped)
|
||||
assert caplog.text.lower().count("unregistered type") == 0
|
||||
|
||||
_lg_msgpack.STRICT_MSGPACK_ENABLED = current
|
||||
|
||||
|
||||
def test_msgpack_warning_dedup_strict_mode(caplog: pytest.LogCaptureFixture) -> None:
|
||||
"""Repeated deserialization of the same blocked type should only warn once."""
|
||||
serde = JsonPlusSerializer(allowed_msgpack_modules=None)
|
||||
|
||||
obj = AnotherPydantic(foo="test")
|
||||
dumped = serde.dumps_typed(obj)
|
||||
|
||||
caplog.clear()
|
||||
serde.loads_typed(dumped)
|
||||
first_count = caplog.text.lower().count("blocked")
|
||||
assert first_count >= 1
|
||||
|
||||
caplog.clear()
|
||||
serde.loads_typed(dumped)
|
||||
assert caplog.text.lower().count("blocked") == 0
|
||||
|
||||
|
||||
def test_register_safe_types_silences_warning(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Types added via register_safe_types should deserialize without warnings."""
|
||||
_lg_msgpack.register_safe_types([AnotherPydantic])
|
||||
try:
|
||||
serde = JsonPlusSerializer()
|
||||
|
||||
obj = AnotherPydantic(foo="test")
|
||||
|
||||
caplog.clear()
|
||||
dumped = serde.dumps_typed(obj)
|
||||
result = serde.loads_typed(dumped)
|
||||
|
||||
assert "unregistered type" not in caplog.text.lower()
|
||||
assert "blocked" not in caplog.text.lower()
|
||||
assert result == obj
|
||||
finally:
|
||||
_lg_msgpack._CUSTOM_SAFE_MSGPACK_TYPES.discard(
|
||||
(AnotherPydantic.__module__, AnotherPydantic.__name__)
|
||||
)
|
||||
|
||||
|
||||
def test_register_safe_types_with_tuples(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""register_safe_types should accept (module, name) tuples."""
|
||||
_lg_msgpack.register_safe_types([("tests.test_jsonplus", "AnotherPydantic")])
|
||||
try:
|
||||
serde = JsonPlusSerializer()
|
||||
|
||||
obj = AnotherPydantic(foo="test")
|
||||
|
||||
caplog.clear()
|
||||
dumped = serde.dumps_typed(obj)
|
||||
result = serde.loads_typed(dumped)
|
||||
|
||||
assert "unregistered type" not in caplog.text.lower()
|
||||
assert "blocked" not in caplog.text.lower()
|
||||
assert result == obj
|
||||
finally:
|
||||
_lg_msgpack._CUSTOM_SAFE_MSGPACK_TYPES.discard(
|
||||
("tests.test_jsonplus", "AnotherPydantic")
|
||||
)
|
||||
|
||||
|
||||
def test_register_safe_types_strict_mode(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Types added via register_safe_types should also work in strict mode."""
|
||||
_lg_msgpack.register_safe_types([AnotherPydantic])
|
||||
try:
|
||||
serde = JsonPlusSerializer(allowed_msgpack_modules=None)
|
||||
|
||||
obj = AnotherPydantic(foo="test")
|
||||
|
||||
caplog.clear()
|
||||
dumped = serde.dumps_typed(obj)
|
||||
result = serde.loads_typed(dumped)
|
||||
|
||||
assert "blocked" not in caplog.text.lower()
|
||||
assert result == obj
|
||||
finally:
|
||||
_lg_msgpack._CUSTOM_SAFE_MSGPACK_TYPES.discard(
|
||||
(AnotherPydantic.__module__, AnotherPydantic.__name__)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user