diff --git a/src/blueapi/worker/event.py b/src/blueapi/worker/event.py index 367464457e..df9b54bb45 100644 --- a/src/blueapi/worker/event.py +++ b/src/blueapi/worker/event.py @@ -4,6 +4,7 @@ from bluesky.run_engine import RunEngineStateMachine from pydantic import Field, PydanticSchemaGenerationError, TypeAdapter +from pydantic_core import PydanticSerializationError from super_state_machine.extras import PropertyMachine, ProxyString from blueapi.utils import BlueapiBaseModel @@ -73,8 +74,8 @@ class TaskResult(BlueapiBaseModel): def from_result(cls, result: Any) -> Self: type_str = type(result).__name__ try: - value = TypeAdapter(type(result)).dump_python(result) - except PydanticSchemaGenerationError: + value = TypeAdapter(type(result)).dump_python(result, mode="json") + except (PydanticSchemaGenerationError, PydanticSerializationError): value = None return cls(result=value, type=type_str) diff --git a/tests/unit_tests/worker/test_task_worker.py b/tests/unit_tests/worker/test_task_worker.py index 4b4d83408c..ee5db34f7f 100644 --- a/tests/unit_tests/worker/test_task_worker.py +++ b/tests/unit_tests/worker/test_task_worker.py @@ -893,3 +893,22 @@ def test_plan_module_with_composite_devices_can_be_loaded_before_device_module( params = Task(name="injected_device_plan").prepare_params(context_without_devices) assert params["composite"].fake_device == fake_device assert params["composite"].second_fake_device == second_fake_device + + +@pytest.mark.parametrize( + "plan_result,task_result,type_name", + ( + (Unreturnable(foo=1, bar=[]), None, "Unreturnable"), + ((Unreturnable(foo=2, bar=[]),), None, "tuple"), + (ComplexReturn(foo=3, bar=["a"]), {"foo": 3, "bar": ["a"]}, "ComplexReturn"), + ((ComplexReturn(foo=4, bar=["b"]),), [{"foo": 4, "bar": ["b"]}], "tuple"), + (ModelReturn(foo=5, bar=["c"]), {"foo": 5, "bar": ["c"]}, "ModelReturn"), + ((ModelReturn(foo=6, bar=["d"]),), [{"foo": 6, "bar": ["d"]}], "tuple"), + (42, 42, "int"), + ((1, 2), [1, 2], "tuple"), + ), +) +def test_task_result_serialization(plan_result, task_result, type_name): + res = TaskResult.from_result(plan_result) + assert res.result == task_result + assert res.type == type_name