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.3 kB

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