From e771d17f7f3a76280f0eacde4e22317f7b6bba23 Mon Sep 17 00:00:00 2001 From: Jacob Williamson Date: Tue, 10 Nov 2026 17:29:48 +0000 Subject: [PATCH 1/2] Fix tiled queries for new node structure --- .../external_interaction/tiled/tiled.py | 19 +++++---- .../plugins/i15_1/tiled_interaction.py | 5 ++- src/daq_queuing_service/task_queue/queue.py | 13 +++++- .../external_interaction/tiled/test_tiled.py | 34 ++++++++------- .../plugins/i15_1/test_tiled_interaction.py | 41 +++++++------------ 5 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/daq_queuing_service/external_interaction/tiled/tiled.py b/src/daq_queuing_service/external_interaction/tiled/tiled.py index 3e3b7b96..40966a7a 100644 --- a/src/daq_queuing_service/external_interaction/tiled/tiled.py +++ b/src/daq_queuing_service/external_interaction/tiled/tiled.py @@ -55,16 +55,19 @@ def get_tiled_client( def get_metadata_from_tiled( - tiled_client: Container, instrument_session: str, blueapi_task_id: str + tiled_client: Container, + instrument: str, + instrument_session: str, + blueapi_task_id: str, ) -> list[tuple[str, dict[str, Any]]]: @cached(cache) def _query_tiled( - instrument_session: str, blueapi_task_id: str + instrument: str, instrument_session: str, blueapi_task_id: str ) -> list[tuple[str, dict[str, Any]]]: - result: Container = tiled_client.search( - Eq("start.instrument_session", instrument_session) - ).search(Eq("start.blueapi_task_id", blueapi_task_id)) + result: Container = tiled_client[ + f"{instrument}/{instrument_session.split('-')[0]}/{instrument_session}" + ].search(Eq("start.blueapi_task_id", blueapi_task_id)) items = sorted( ((key, dict(value.metadata)) for key, value in result.items()), @@ -72,10 +75,10 @@ def _query_tiled( ) return items - return _query_tiled(instrument_session, blueapi_task_id) + return _query_tiled(instrument, instrument_session, blueapi_task_id) -def get_tiled_and_scan_ids(tiled_client: Container, call: BlueapiCall): +def get_tiled_and_scan_ids(tiled_client: Container, instrument: str, call: BlueapiCall): tiled_ids: list[str] = [] scan_ids: list[int] = [] @@ -84,7 +87,7 @@ def get_tiled_and_scan_ids(tiled_client: Container, call: BlueapiCall): return tiled_ids, scan_ids scan_metadatas = get_metadata_from_tiled( - tiled_client, call.task_request.instrument_session, call.blueapi_id + tiled_client, instrument, call.task_request.instrument_session, call.blueapi_id ) for item in scan_metadatas: diff --git a/src/daq_queuing_service/plugins/i15_1/tiled_interaction.py b/src/daq_queuing_service/plugins/i15_1/tiled_interaction.py index 9e00504a..78520c42 100644 --- a/src/daq_queuing_service/plugins/i15_1/tiled_interaction.py +++ b/src/daq_queuing_service/plugins/i15_1/tiled_interaction.py @@ -31,8 +31,9 @@ def _query_tiled(instrument_session: str) -> list[TiledAuxiliary]: oldest_valid_time = time.time() - stale_time_s result: Container = ( - tiled_client.search(Eq("start.instrument", "i15-1")) - .search(Eq("start.instrument_session", instrument_session)) + tiled_client[ + f"i15-1/{instrument_session.split('-')[0]}/{instrument_session}" + ] .search(Eq("stop.exit_status", "success")) .search(Comparison("ge", "stop.time", oldest_valid_time)) .search(In("start.scan_type", list(AuxiliaryScanType))) diff --git a/src/daq_queuing_service/task_queue/queue.py b/src/daq_queuing_service/task_queue/queue.py index 4894d1fa..364d1b74 100644 --- a/src/daq_queuing_service/task_queue/queue.py +++ b/src/daq_queuing_service/task_queue/queue.py @@ -354,7 +354,11 @@ async def complete_call(self, call: BlueapiCall, result: TaskResult): result (TaskResult): The result of the task from blueapi """ with add_session_to_logger(call.task_request.instrument_session): - tiled_ids, scan_ids = get_tiled_and_scan_ids(self._tiled_client, call) + tiled_ids, scan_ids = ( + get_tiled_and_scan_ids(self._tiled_client, self.instrument, call) + if self.instrument + else ([], []) + ) should_pause = self._converter.pause_on_complete_blueapi_call( call.model_copy(), result ) @@ -383,7 +387,12 @@ async def fail_call( should_pause = self._converter.pause_on_fail_blueapi_call( call.model_copy(), errors ) - tiled_ids, scan_ids = get_tiled_and_scan_ids(self._tiled_client, call) + + tiled_ids, scan_ids = ( + get_tiled_and_scan_ids(self._tiled_client, self.instrument, call) + if self.instrument + else ([], []) + ) LOGGER.error(f"Plan {call} has failed with the following errors: {errors}") async with self._modifying: diff --git a/tests/unit_tests/external_interaction/tiled/test_tiled.py b/tests/unit_tests/external_interaction/tiled/test_tiled.py index 7009797a..4c4c137e 100644 --- a/tests/unit_tests/external_interaction/tiled/test_tiled.py +++ b/tests/unit_tests/external_interaction/tiled/test_tiled.py @@ -39,14 +39,13 @@ def mock_tiled_search( } } - search_result = MagicMock() - search_result.search = MagicMock( + search_result = MagicMock( return_value={"tiled_id_1": result_1, "tiled_id_2": result_2} ) - tiled_client.search = MagicMock(return_value=search_result) + tiled_client["ixx/cm12345/cm12345-1"].search = search_result - return (tiled_client, search_result) + return tiled_client def test_get_tiled_client_instantiates_client_from_uri(): @@ -104,22 +103,21 @@ def get_next_env_variable(*_, **__): # type:ignore ) -def test_get_metadata_from_tiled_makes_expected_searches( - mock_tiled_search: tuple[MagicMock, MagicMock], +def test_get_metadata_from_tiled_makes_expected_search( + mock_tiled_search: MagicMock, ): - client, result = mock_tiled_search - get_metadata_from_tiled(client, "cm12345-1", "bapi_task_id") - client.search.assert_called_once_with( - Eq(key="start.instrument_session", value="cm12345-1") + client = mock_tiled_search + get_metadata_from_tiled(client, "ixx", "cm12345-1", "bapi_task_id") + client["ixx/cm12345/cm12345-1"].search.assert_called_once_with( # type:ignore + Eq("start.blueapi_task_id", "bapi_task_id") ) - result.search.assert_called_once_with(Eq("start.blueapi_task_id", "bapi_task_id")) def test_get_metadata_from_tiled_returns_expected_result( - mock_tiled_search: tuple[MagicMock, MagicMock], + mock_tiled_search: MagicMock, ): - client, _ = mock_tiled_search - result = get_metadata_from_tiled(client, "cm12345-1", "bapi_task_id") + client = mock_tiled_search + result = get_metadata_from_tiled(client, "ixx", "cm12345-1", "bapi_task_id") assert result == [ # Should be in chronological order ( "tiled_id_2", @@ -149,9 +147,9 @@ def test_get_metadata_from_tiled_returns_expected_result( def test_get_metadata_from_tiled_returns_empty_list_if_no_result_found( - mock_tiled_search: tuple[MagicMock, MagicMock], + mock_tiled_search: MagicMock, ): - client, search = mock_tiled_search - search.search = MagicMock(return_value={}) - result = get_metadata_from_tiled(client, "cm12345-1", "bapi_task_id") + client = mock_tiled_search + client["ixx/cm12345/cm12345-1"].search = MagicMock(return_value={}) + result = get_metadata_from_tiled(client, "ixx", "cm12345-1", "bapi_task_id") assert result == [] diff --git a/tests/unit_tests/plugins/i15_1/test_tiled_interaction.py b/tests/unit_tests/plugins/i15_1/test_tiled_interaction.py index 1cd01b66..b3e6edaa 100644 --- a/tests/unit_tests/plugins/i15_1/test_tiled_interaction.py +++ b/tests/unit_tests/plugins/i15_1/test_tiled_interaction.py @@ -28,7 +28,7 @@ def mock_current_time(): @pytest.fixture() def mock_tiled_searches( tiled_client: MagicMock, -) -> tuple[MagicMock, MagicMock, MagicMock, MagicMock, MagicMock, MagicMock]: +) -> tuple[MagicMock, MagicMock, MagicMock, MagicMock]: result_1 = MagicMock() result_1.metadata = { @@ -93,8 +93,8 @@ def mock_tiled_searches( } } - search_result_6 = MagicMock() - search_result_6.search = MagicMock( + search_result_4 = MagicMock() + search_result_4.search = MagicMock( return_value={ "tiled_id_1": result_1, "tiled_id_2": result_2, @@ -104,51 +104,38 @@ def mock_tiled_searches( } ) - search_result_5 = MagicMock() - search_result_5.search = MagicMock(return_value=search_result_6) - search_result_4 = MagicMock() - search_result_4.search = MagicMock(return_value=search_result_5) search_result_3 = MagicMock() search_result_3.search = MagicMock(return_value=search_result_4) search_result_2 = MagicMock() search_result_2.search = MagicMock(return_value=search_result_3) - tiled_client.search = MagicMock(return_value=search_result_2) - - return ( - tiled_client, - search_result_2, - search_result_3, - search_result_4, - search_result_5, - search_result_6, + tiled_client["i15-1/cm12345/cm12345-1"].search = MagicMock( + return_value=search_result_2 ) + return (tiled_client, search_result_2, search_result_3, search_result_4) + def test_get_suitable_tiled_background_makes_expected_searches( - mock_tiled_searches: tuple[ - MagicMock, MagicMock, MagicMock, MagicMock, MagicMock, MagicMock - ], + mock_tiled_searches: tuple[MagicMock, MagicMock, MagicMock, MagicMock], queue_params: QueueParameters, ): - client, search_2, search_3, search_4, search_5, search_6 = mock_tiled_searches + client, search_2, search_3, search_4 = mock_tiled_searches get_suitable_tiled_scan( client, AuxiliaryScan(instrument_session="cm12345-1", pin=None, time_per_pdf=10), queue_params.tiled_stale_time_s, ) - client.search.assert_called_once_with(Eq(key="start.instrument", value="i15-1")) - search_2.search.assert_called_once_with( - Eq(key="start.instrument_session", value="cm12345-1") + client["i15-1/cm12345/cm12345-1"].search.assert_called_once_with( # type: ignore + Eq("stop.exit_status", "success") ) - search_3.search.assert_called_once_with(Eq("stop.exit_status", "success")) - search_4.search.assert_called_once_with( + search_2.search.assert_called_once_with( Comparison("ge", "stop.time", 30 - queue_params.tiled_stale_time_s) ) - search_5.search.assert_called_once_with( + search_3.search.assert_called_once_with( In(key="start.scan_type", value=["Air", "Empty Capillary", "Standard Sample"]) ) - search_6.search.assert_called_once_with( + search_4.search.assert_called_once_with( KeyPresent("start.experiment_definition.data.time_per_pdf") ) From e301f0ede21eb03d1821a8dcb44551eee8b63355 Mon Sep 17 00:00:00 2001 From: Jacob Williamson Date: Thu, 12 Nov 2026 11:38:17 +0000 Subject: [PATCH 2/2] New version of tiled --- pyproject.toml | 2 +- uv.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1749b713..47c84741 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ "fastapi>=0.136.0", "graypy>=2.1.0", "pydantic>=2.13.2", - "tiled[client]>=0.2.9", + "tiled[client]>=0.2.21", ] dynamic = ["version"] license.file = "LICENSE" diff --git a/uv.lock b/uv.lock index cfcc737d..b9745f04 100644 --- a/uv.lock +++ b/uv.lock @@ -464,7 +464,7 @@ wheels = [ [[package]] name = "blueapi" -version = "1.21.1" +version = "1.21.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aioca" }, @@ -491,9 +491,9 @@ dependencies = [ { name = "tomlkit" }, { name = "uvicorn" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/0e/3980ee2d4549d8072b0f5ccff44b9775114ba3c6159117bda5eb9f542547/blueapi-1.21.1.tar.gz", hash = "sha256:5cd9da1e55e0eff3dca8eb8c5bfcdc6b9328f6a226c74215de19e4461e9ea254", size = 2918935, upload-time = "2026-10-21T19:03:07.918Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/32/51d636ee95e6d517313b57fa4c495812522c127e94e763577072f246a9dc/blueapi-1.21.0.tar.gz", hash = "sha256:e8bd0580c9ea0a52c0fde7a8834a376a8f7f097a5d81ea79f06916f519f6b150", size = 2898200, upload-time = "2026-10-20T13:43:26.196Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/f2/7b1f350bc57094b0a74f258b32dbdff4826f728872722a3fbd53e29ca334/blueapi-1.21.1-py3-none-any.whl", hash = "sha256:e1b4f1c3587ea6d805954800f8d1366ccca7c5e62034e6336f3ce5c924c84ddd", size = 97535, upload-time = "2026-10-21T19:03:06.457Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d3/cd9b5c32bab9c72b014efde63a1ae72afac2ff531c8825845c5b89bcc59e/blueapi-1.21.0-py3-none-any.whl", hash = "sha256:57377d38b923eba2157833cfbc7b084b190bcc103a9b03c09a5f5b1070217603", size = 96935, upload-time = "2026-10-20T13:43:24.685Z" }, ] [[package]] @@ -1310,7 +1310,7 @@ requires-dist = [ { name = "fastapi", specifier = ">=0.136.0" }, { name = "graypy", specifier = ">=2.1.0" }, { name = "pydantic", specifier = ">=2.13.2" }, - { name = "tiled", extras = ["client"], specifier = ">=0.2.9" }, + { name = "tiled", extras = ["client"], specifier = ">=0.2.21" }, ] [package.metadata.requires-dev] @@ -5593,10 +5593,10 @@ wheels = [ [[package]] name = "tiled" -version = "0.2.18" +version = "0.2.21" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "httpx" }, + { name = "httpx2" }, { name = "json-merge-patch" }, { name = "jsonpatch" }, { name = "jsonschema" }, @@ -5608,9 +5608,9 @@ dependencies = [ { name = "pyyaml" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/e5/558ce54947c9385b74129589ac91b20a54b4e7c327ac7749c272badb338d/tiled-0.2.18.tar.gz", hash = "sha256:2f3943260c46824b162796fcb8a43c3d02f41205e2ccefc64e365b18b6ec1e27", size = 2785181, upload-time = "2026-09-02T21:50:09.616Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/f6/5bd7b29c185453bbd980eab8c33ddde244926ffca14c5a459aa077073276/tiled-0.2.21.tar.gz", hash = "sha256:ba36a7ce96391a10dfdeff08b0962bccf346ec515a20fe1df8b7ef983d12acaa", size = 3884519, upload-time = "2026-11-02T22:34:19.138Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/70/85966182bc5fd7a5edd63290849ee4b7ebba8f61375780b782b1427f0bed/tiled-0.2.18-py3-none-any.whl", hash = "sha256:416079d4b5c9acc5498197d48c05a951ee8f7c699ac3b07920ae907a8da7fa06", size = 1848867, upload-time = "2026-09-02T21:50:07.226Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/d9a3d4bd5cea3f64a82aa9dfddeea1ec10d3aa7a9450da21f3a774c3d0ec/tiled-0.2.21-py3-none-any.whl", hash = "sha256:de34646b0d3463cad4849decdec71bb86b3fbb4679be6bd26da9d4665bdc21b5", size = 1944015, upload-time = "2026-11-02T22:34:16.579Z" }, ] [package.optional-dependencies]