This commit is contained in:
@@ -107,10 +107,7 @@ def _instantiate(
|
|||||||
TypeError: If instantiation fails
|
TypeError: If instantiation fails
|
||||||
"""
|
"""
|
||||||
# Handle JSON payload first
|
# Handle JSON payload first
|
||||||
try:
|
json_payload = json.loads(payload) if is_json and isinstance(payload, str) else None
|
||||||
json_payload = json.loads(payload) if is_json and isinstance(payload, str) else None
|
|
||||||
except Exception:
|
|
||||||
json_payload = None
|
|
||||||
|
|
||||||
# Handle basic types
|
# Handle basic types
|
||||||
if type_string == "str":
|
if type_string == "str":
|
||||||
@@ -143,12 +140,22 @@ def _instantiate(
|
|||||||
if type_string.startswith("typing.Set"):
|
if type_string.startswith("typing.Set"):
|
||||||
if json_payload is not None:
|
if json_payload is not None:
|
||||||
return set(json_payload)
|
return set(json_payload)
|
||||||
return set(payload if isinstance(payload, list) else payload.split(","))
|
_set_type = _extract_type_of(type_string)
|
||||||
|
return set(
|
||||||
|
payload
|
||||||
|
if isinstance(payload, list)
|
||||||
|
else [_instantiate(_set_type, p) for p in payload.split(",")]
|
||||||
|
)
|
||||||
|
|
||||||
if type_string.startswith("typing.Tuple"):
|
if type_string.startswith("typing.Tuple"):
|
||||||
if json_payload is not None:
|
if json_payload is not None:
|
||||||
return tuple(json_payload)
|
return tuple(json_payload)
|
||||||
return tuple(payload if isinstance(payload, list) else payload.split(","))
|
_tuple_type = _extract_type_of(type_string)
|
||||||
|
return tuple(
|
||||||
|
payload
|
||||||
|
if isinstance(payload, list)
|
||||||
|
else [_instantiate(_tuple_type, p) for p in payload.split(",")]
|
||||||
|
)
|
||||||
|
|
||||||
if type_string.startswith("typing.Optional"):
|
if type_string.startswith("typing.Optional"):
|
||||||
inner_type = _extract_type_of(type_string)
|
inner_type = _extract_type_of(type_string)
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
|
import json
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from amqp.adapter.type_descriptor import TypeDescriptor
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from amqp.adapter.type_descriptor import TypeDescriptor, _instantiate
|
||||||
|
|
||||||
|
|
||||||
|
class TestClass(BaseModel):
|
||||||
|
value: str
|
||||||
|
extra: str
|
||||||
|
|
||||||
|
|
||||||
class TestTypeDescriptor(unittest.TestCase):
|
class TestTypeDescriptor(unittest.TestCase):
|
||||||
@@ -66,6 +74,138 @@ class TestTypeDescriptor(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(repr(td), "TypeDescriptor(type='str', is_json=True)")
|
self.assertEqual(repr(td), "TypeDescriptor(type='str', is_json=True)")
|
||||||
|
|
||||||
|
def test_instantiate_basic_types(self):
|
||||||
|
test_cases = [
|
||||||
|
("str", "hello", "hello"),
|
||||||
|
("int", "42", 42),
|
||||||
|
("float", "3.14", 3.14),
|
||||||
|
("bool", "true", True),
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_str, input_value, expected in test_cases:
|
||||||
|
with self.subTest(type_str=type_str, input_value=input_value):
|
||||||
|
result = _instantiate(type_str, input_value)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_instantiate_list_types(self):
|
||||||
|
test_cases = [
|
||||||
|
("typing.List[str]", "a,b,c", ["a", "b", "c"]),
|
||||||
|
("typing.List[int]", "1,2,3", [1, 2, 3]),
|
||||||
|
("typing.List[str]", json.dumps(["a", "b", "c"]), ["a", "b", "c"], True),
|
||||||
|
("typing.List[int]", json.dumps([1, 2, 3]), [1, 2, 3], True),
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_str, input_value, expected, *args in test_cases:
|
||||||
|
is_json = args[0] if args else False
|
||||||
|
with self.subTest(type_str=type_str, input_value=input_value, is_json=is_json):
|
||||||
|
result = _instantiate(type_str, input_value, is_json=is_json)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_instantiate_dict_types(self):
|
||||||
|
test_cases = [
|
||||||
|
("typing.Dict", {"a": 1, "b": 2}, {"a": 1, "b": 2}),
|
||||||
|
("typing.Dict", json.dumps({"a": 1, "b": 2}), {"a": 1, "b": 2}, True),
|
||||||
|
("typing.Mapping", {"a": 1, "b": 2}, {"a": 1, "b": 2}),
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_str, input_value, expected, *args in test_cases:
|
||||||
|
is_json = args[0] if args else False
|
||||||
|
with self.subTest(type_str=type_str, input_value=input_value, is_json=is_json):
|
||||||
|
result = _instantiate(type_str, input_value, is_json=is_json)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_instantiate_set_types(self):
|
||||||
|
test_cases = [
|
||||||
|
("typing.Set[str]", "a,b,c", {"a", "b", "c"}),
|
||||||
|
("typing.Set[int]", "1,2,3", {1, 2, 3}),
|
||||||
|
("typing.Set[str]", json.dumps(["a", "b", "c"]), {"a", "b", "c"}, True),
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_str, input_value, expected, *args in test_cases:
|
||||||
|
is_json = args[0] if args else False
|
||||||
|
with self.subTest(type_str=type_str, input_value=input_value, is_json=is_json):
|
||||||
|
result = _instantiate(type_str, input_value, is_json=is_json)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_instantiate_tuple_types(self):
|
||||||
|
test_cases = [
|
||||||
|
("typing.Tuple[str, int]", ["hello", 42], ("hello", 42)),
|
||||||
|
("typing.Tuple[str, int]", json.dumps(["hello", 42]), ("hello", 42), True),
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_str, input_value, expected, *args in test_cases:
|
||||||
|
is_json = args[0] if args else False
|
||||||
|
with self.subTest(type_str=type_str, input_value=input_value, is_json=is_json):
|
||||||
|
result = _instantiate(type_str, input_value, is_json=is_json)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_instantiate_optional_types(self):
|
||||||
|
test_cases = [
|
||||||
|
("typing.Optional[str]", "hello", "hello"),
|
||||||
|
("typing.Optional[typing.List[str]]", "a,b,c", ["a", "b", "c"]),
|
||||||
|
(
|
||||||
|
"typing.Optional[typing.List[str]]",
|
||||||
|
json.dumps(["a", "b", "c"]),
|
||||||
|
["a", "b", "c"],
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_str, input_value, expected, *args in test_cases:
|
||||||
|
is_json = args[0] if args else False
|
||||||
|
with self.subTest(type_str=type_str, input_value=input_value, is_json=is_json):
|
||||||
|
result = _instantiate(type_str, input_value, is_json=is_json)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_instantiate_nested_types(self):
|
||||||
|
test_cases = [
|
||||||
|
(
|
||||||
|
"typing.List[typing.Dict]",
|
||||||
|
json.dumps([{"a": 1}, {"b": 2}]),
|
||||||
|
[{"a": 1}, {"b": 2}],
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"typing.Optional[typing.List[typing.Dict]]",
|
||||||
|
json.dumps([{"a": 1}, {"b": 2}]),
|
||||||
|
[{"a": 1}, {"b": 2}],
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_str, input_value, expected, *args in test_cases:
|
||||||
|
is_json = args[0] if args else False
|
||||||
|
with self.subTest(type_str=type_str, input_value=input_value, is_json=is_json):
|
||||||
|
result = _instantiate(type_str, input_value, is_json=is_json)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_instantiate_error_handling(self):
|
||||||
|
test_cases = [
|
||||||
|
("typing.List[str]", "invalid json", True, json.JSONDecodeError),
|
||||||
|
("typing.NonExistentType", "value", False, ImportError),
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_str, input_value, is_json, expected_exception in test_cases:
|
||||||
|
with self.subTest(type_str=type_str, input_value=input_value, is_json=is_json):
|
||||||
|
with self.assertRaises(expected_exception):
|
||||||
|
_instantiate(type_str, input_value, is_json=is_json)
|
||||||
|
|
||||||
|
def test_instantiate_with_extra_init_data(self):
|
||||||
|
|
||||||
|
test_cases = [
|
||||||
|
(
|
||||||
|
"tests.adapter.test_type_descriptor.TestClass",
|
||||||
|
{"value": "test"},
|
||||||
|
{"extra": "extra_value"},
|
||||||
|
lambda x: x.value == "test" and x.extra == "extra_value",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_str, input_value, extra_init_data, validator in test_cases:
|
||||||
|
with self.subTest(type_str=type_str, input_value=input_value):
|
||||||
|
result = _instantiate(type_str, input_value, extra_init_data=extra_init_data)
|
||||||
|
self.assertTrue(validator(result))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user