From 34543d57cb10f3a90e5e2e1e899649fcc40b24ba Mon Sep 17 00:00:00 2001
From: Peter Holloway <peter.holloway@diamond.ac.uk>
Date: Tue, 25 Jun 2024 11:40:18 +0100
Subject: [PATCH 1/3] Correct generated schema for Reference types

When bluesky protocol types are translated into references to allow them
to be passed by name from external processes, the generated schema needs
to specify the type that the reference should refer to rather than the
type of the value itself (str).

The previous version used the field name as the key for this entry in
the schema instead of the constant 'type' used and expected elsewhere.
---
 src/blueapi/core/context.py    | 2 +-
 tests/service/test_rest_api.py | 6 ++----
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/src/blueapi/core/context.py b/src/blueapi/core/context.py
index 219e736b7..8689c167b 100644
--- a/src/blueapi/core/context.py
+++ b/src/blueapi/core/context.py
@@ -202,7 +202,7 @@ def __modify_schema__(
                     cls, field_schema: dict[str, Any], field: ModelField | None
                 ):
                     if field:
-                        field_schema.update({field.name: repr(target)})
+                        field_schema.update({"type": repr(target)})
 
             self._reference_cache[target] = Reference
 
diff --git a/tests/service/test_rest_api.py b/tests/service/test_rest_api.py
index b40a44da4..eda62b8b3 100644
--- a/tests/service/test_rest_api.py
+++ b/tests/service/test_rest_api.py
@@ -110,9 +110,7 @@ def test_get_plan_with_device_reference(handler: Handler, client: TestClient) ->
                         "title": "Delay",
                     },
                     "detectors": {
-                        "items": {
-                            "_detectors": "<class " "'bluesky.protocols.Readable'>"
-                        },
+                        "items": {"type": "<class " "'bluesky.protocols.Readable'>"},
                         "title": "Detectors",
                         "type": "array",
                     },
@@ -135,7 +133,7 @@ def test_get_plan_with_device_reference(handler: Handler, client: TestClient) ->
                     "title": "Delay",
                 },
                 "detectors": {
-                    "items": {"_detectors": "<class " "'bluesky.protocols.Readable'>"},
+                    "items": {"type": "<class " "'bluesky.protocols.Readable'>"},
                     "title": "Detectors",
                     "type": "array",
                 },

From 2f08d79feaacb5170b19a3187e7677ae96b90d35 Mon Sep 17 00:00:00 2001
From: Peter Holloway <peter.holloway@diamond.ac.uk>
Date: Tue, 25 Jun 2024 11:56:19 +0100
Subject: [PATCH 2/3] Add test for generated schema

---
 tests/core/test_context.py | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/tests/core/test_context.py b/tests/core/test_context.py
index aeb68f31f..2a01663e3 100644
--- a/tests/core/test_context.py
+++ b/tests/core/test_context.py
@@ -121,6 +121,20 @@ def test_add_plan(empty_context: BlueskyContext, plan: PlanGenerator) -> None:
     assert plan.__name__ in empty_context.plans
 
 
+def test_generated_schema(
+    empty_context: BlueskyContext,
+):
+    def demo_plan(foo: int, mov: Movable) -> MsgGenerator:  # type: ignore
+        ...
+
+    empty_context.plan(demo_plan)
+    schema = empty_context.plans["demo_plan"].model.schema()
+    assert schema["properties"] == {
+        "foo": {"title": "Foo", "type": "integer"},
+        "mov": {"title": "Mov", "type": repr(Movable)},
+    }
+
+
 @pytest.mark.parametrize(
     "plan", [has_typeless_param, has_typed_and_typeless_params, has_typeless_params]
 )

From 46598b08021d59c08dc4434f34e606ea1cb79fea Mon Sep 17 00:00:00 2001
From: Peter Holloway <peter.holloway@diamond.ac.uk>
Date: Tue, 25 Jun 2024 12:21:45 +0100
Subject: [PATCH 3/3] Use FQCN for reference type schemas

Instead of using the repr(cls) output. Gives

    bluesky.protocols.Readable

instead of

    <class 'bluesky.protocols.Readable'>
---
 src/blueapi/core/context.py    | 4 +++-
 tests/core/test_context.py     | 2 +-
 tests/service/test_rest_api.py | 4 ++--
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/blueapi/core/context.py b/src/blueapi/core/context.py
index 8689c167b..1bd8e482e 100644
--- a/src/blueapi/core/context.py
+++ b/src/blueapi/core/context.py
@@ -202,7 +202,9 @@ def __modify_schema__(
                     cls, field_schema: dict[str, Any], field: ModelField | None
                 ):
                     if field:
-                        field_schema.update({"type": repr(target)})
+                        field_schema.update(
+                            {"type": f"{target.__module__}.{target.__qualname__}"}
+                        )
 
             self._reference_cache[target] = Reference
 
diff --git a/tests/core/test_context.py b/tests/core/test_context.py
index 2a01663e3..a1f6bdb1a 100644
--- a/tests/core/test_context.py
+++ b/tests/core/test_context.py
@@ -131,7 +131,7 @@ def demo_plan(foo: int, mov: Movable) -> MsgGenerator:  # type: ignore
     schema = empty_context.plans["demo_plan"].model.schema()
     assert schema["properties"] == {
         "foo": {"title": "Foo", "type": "integer"},
-        "mov": {"title": "Mov", "type": repr(Movable)},
+        "mov": {"title": "Mov", "type": "bluesky.protocols.Movable"},
     }
 
 
diff --git a/tests/service/test_rest_api.py b/tests/service/test_rest_api.py
index eda62b8b3..238a93e41 100644
--- a/tests/service/test_rest_api.py
+++ b/tests/service/test_rest_api.py
@@ -110,7 +110,7 @@ def test_get_plan_with_device_reference(handler: Handler, client: TestClient) ->
                         "title": "Delay",
                     },
                     "detectors": {
-                        "items": {"type": "<class " "'bluesky.protocols.Readable'>"},
+                        "items": {"type": "bluesky.protocols.Readable"},
                         "title": "Detectors",
                         "type": "array",
                     },
@@ -133,7 +133,7 @@ def test_get_plan_with_device_reference(handler: Handler, client: TestClient) ->
                     "title": "Delay",
                 },
                 "detectors": {
-                    "items": {"type": "<class " "'bluesky.protocols.Readable'>"},
+                    "items": {"type": "bluesky.protocols.Readable"},
                     "title": "Detectors",
                     "type": "array",
                 },