You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_serialization.py 6.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. from dataclasses import dataclass
  2. from typing import Union
  3. import pytest
  4. from autogen_core import Image
  5. from autogen_core._serialization import (
  6. JSON_DATA_CONTENT_TYPE,
  7. PROTOBUF_DATA_CONTENT_TYPE,
  8. DataclassJsonMessageSerializer,
  9. MessageSerializer,
  10. PydanticJsonMessageSerializer,
  11. SerializationRegistry,
  12. try_get_known_serializers_for_type,
  13. )
  14. from PIL import Image as PILImage
  15. from protos.serialization_test_pb2 import NestingProtoMessage, ProtoMessage
  16. from pydantic import BaseModel
  17. class PydanticMessage(BaseModel):
  18. message: str
  19. class NestingPydanticMessage(BaseModel):
  20. message: str
  21. nested: PydanticMessage
  22. @dataclass
  23. class DataclassMessage:
  24. message: str
  25. @dataclass
  26. class NestingDataclassMessage:
  27. message: str
  28. nested: DataclassMessage
  29. @dataclass
  30. class NestingPydanticDataclassMessage:
  31. message: str
  32. nested: PydanticMessage
  33. def test_pydantic() -> None:
  34. serde = SerializationRegistry()
  35. serde.add_serializer(try_get_known_serializers_for_type(PydanticMessage))
  36. message = PydanticMessage(message="hello")
  37. name = serde.type_name(message)
  38. json = serde.serialize(message, type_name=name, data_content_type=JSON_DATA_CONTENT_TYPE)
  39. assert name == "PydanticMessage"
  40. assert json == b'{"message":"hello"}'
  41. deserialized = serde.deserialize(json, type_name=name, data_content_type=JSON_DATA_CONTENT_TYPE)
  42. assert deserialized == message
  43. def test_nested_pydantic() -> None:
  44. serde = SerializationRegistry()
  45. serde.add_serializer(try_get_known_serializers_for_type(NestingPydanticMessage))
  46. message = NestingPydanticMessage(message="hello", nested=PydanticMessage(message="world"))
  47. name = serde.type_name(message)
  48. json = serde.serialize(message, type_name=name, data_content_type=JSON_DATA_CONTENT_TYPE)
  49. assert json == b'{"message":"hello","nested":{"message":"world"}}'
  50. deserialized = serde.deserialize(json, type_name=name, data_content_type=JSON_DATA_CONTENT_TYPE)
  51. assert deserialized == message
  52. def test_dataclass() -> None:
  53. serde = SerializationRegistry()
  54. serde.add_serializer(try_get_known_serializers_for_type(DataclassMessage))
  55. message = DataclassMessage(message="hello")
  56. name = serde.type_name(message)
  57. json = serde.serialize(message, type_name=name, data_content_type=JSON_DATA_CONTENT_TYPE)
  58. assert json == b'{"message": "hello"}'
  59. deserialized = serde.deserialize(json, type_name=name, data_content_type=JSON_DATA_CONTENT_TYPE)
  60. assert deserialized == message
  61. def test_nesting_dataclass_dataclass() -> None:
  62. serde = SerializationRegistry()
  63. with pytest.raises(ValueError):
  64. serde.add_serializer(try_get_known_serializers_for_type(NestingDataclassMessage))
  65. def test_proto() -> None:
  66. serde = SerializationRegistry()
  67. serde.add_serializer(try_get_known_serializers_for_type(ProtoMessage))
  68. message = ProtoMessage(message="hello")
  69. name = serde.type_name(message)
  70. data = serde.serialize(message, type_name=name, data_content_type=PROTOBUF_DATA_CONTENT_TYPE)
  71. assert name == "agents.ProtoMessage"
  72. deserialized = serde.deserialize(data, type_name=name, data_content_type=PROTOBUF_DATA_CONTENT_TYPE)
  73. assert deserialized.message == message.message
  74. def test_nested_proto() -> None:
  75. serde = SerializationRegistry()
  76. serde.add_serializer(try_get_known_serializers_for_type(NestingProtoMessage))
  77. message = NestingProtoMessage(message="hello", nested=ProtoMessage(message="world"))
  78. name = serde.type_name(message)
  79. data = serde.serialize(message, type_name=name, data_content_type=PROTOBUF_DATA_CONTENT_TYPE)
  80. deserialized = serde.deserialize(data, type_name=name, data_content_type=PROTOBUF_DATA_CONTENT_TYPE)
  81. assert deserialized.message == message.message
  82. assert deserialized.nested.message == message.nested.message
  83. @dataclass
  84. class DataclassNestedUnionSyntaxOldMessage:
  85. message: Union[str, int]
  86. @dataclass
  87. class DataclassNestedUnionSyntaxNewMessage:
  88. message: str | int
  89. @pytest.mark.parametrize("cls", [DataclassNestedUnionSyntaxOldMessage, DataclassNestedUnionSyntaxNewMessage])
  90. def test_nesting_union_old_syntax_dataclass(
  91. cls: type[DataclassNestedUnionSyntaxOldMessage | DataclassNestedUnionSyntaxNewMessage],
  92. ) -> None:
  93. with pytest.raises(ValueError):
  94. _serializer = DataclassJsonMessageSerializer(cls)
  95. def test_nesting_dataclass_pydantic() -> None:
  96. serde = SerializationRegistry()
  97. with pytest.raises(ValueError):
  98. serde.add_serializer(try_get_known_serializers_for_type(NestingPydanticDataclassMessage))
  99. def test_invalid_type() -> None:
  100. serde = SerializationRegistry()
  101. try:
  102. serde.add_serializer(try_get_known_serializers_for_type(str))
  103. except ValueError as e:
  104. assert str(e) == "Unsupported type <class 'str'>"
  105. def test_custom_type() -> None:
  106. serde = SerializationRegistry()
  107. class CustomStringTypeSerializer(MessageSerializer[str]):
  108. @property
  109. def data_content_type(self) -> str:
  110. return "str"
  111. @property
  112. def type_name(self) -> str:
  113. return "custom_str"
  114. def deserialize(self, payload: bytes) -> str:
  115. message = payload.decode("utf-8")
  116. return message[1:-1]
  117. def serialize(self, message: str) -> bytes:
  118. return f'"{message}"'.encode("utf-8")
  119. serde.add_serializer(CustomStringTypeSerializer())
  120. message = "hello"
  121. json = serde.serialize(message, type_name="custom_str", data_content_type="str")
  122. assert json == b'"hello"'
  123. deserialized = serde.deserialize(json, type_name="custom_str", data_content_type="str")
  124. assert deserialized == message
  125. def test_image_type() -> None:
  126. pil_image = PILImage.new("RGB", (100, 100))
  127. image = Image(pil_image)
  128. class PydanticImageMessage(BaseModel):
  129. image: Image
  130. serializer = PydanticJsonMessageSerializer(PydanticImageMessage)
  131. json = serializer.serialize(PydanticImageMessage(image=image))
  132. deserialized = serializer.deserialize(json)
  133. assert deserialized.image.image.size == (100, 100)
  134. assert deserialized.image.image.mode == "RGB"
  135. assert deserialized.image.image == image.image
  136. def test_type_name_for_protos() -> None:
  137. type_name = SerializationRegistry().type_name(ProtoMessage())
  138. assert type_name == "agents.ProtoMessage"
  139. type_name = SerializationRegistry().type_name(ProtoMessage)
  140. assert type_name == "agents.ProtoMessage"
  141. type_name = SerializationRegistry().type_name(NestingProtoMessage())
  142. assert type_name == "agents.NestingProtoMessage"
  143. type_name = SerializationRegistry().type_name(NestingProtoMessage)
  144. assert type_name == "agents.NestingProtoMessage"