From 9d96b22ed389f6ccf442b21bc63d075dc3850138 Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Thu, 4 Jan 2024 14:44:07 -0500 Subject: [PATCH 1/6] Update command unions. --- .../commands/command_unions.py | 249 +++++++++--------- 1 file changed, 129 insertions(+), 120 deletions(-) diff --git a/api/src/opentrons/protocol_engine/commands/command_unions.py b/api/src/opentrons/protocol_engine/commands/command_unions.py index 13e88874bed..1c80f6c14f5 100644 --- a/api/src/opentrons/protocol_engine/commands/command_unions.py +++ b/api/src/opentrons/protocol_engine/commands/command_unions.py @@ -1,6 +1,9 @@ """Union types of concrete command definitions.""" from typing import Union +from typing_extensions import Annotated + +from pydantic import Field from . import heater_shaker from . import magnetic_module @@ -284,66 +287,69 @@ GetTipPresenceCommandType, ) -Command = Union[ - Aspirate, - AspirateInPlace, - Comment, - Custom, - Dispense, - DispenseInPlace, - BlowOut, - BlowOutInPlace, - ConfigureForVolume, - ConfigureNozzleLayout, - DropTip, - DropTipInPlace, - Home, - RetractAxis, - LoadLabware, - LoadLiquid, - LoadModule, - LoadPipette, - MoveLabware, - MoveRelative, - MoveToCoordinates, - MoveToWell, - MoveToAddressableArea, - MoveToAddressableAreaForDropTip, - PrepareToAspirate, - WaitForResume, - WaitForDuration, - PickUpTip, - SavePosition, - SetRailLights, - TouchTip, - SetStatusBar, - VerifyTipPresence, - GetTipPresence, - heater_shaker.WaitForTemperature, - heater_shaker.SetTargetTemperature, - heater_shaker.DeactivateHeater, - heater_shaker.SetAndWaitForShakeSpeed, - heater_shaker.DeactivateShaker, - heater_shaker.OpenLabwareLatch, - heater_shaker.CloseLabwareLatch, - magnetic_module.Disengage, - magnetic_module.Engage, - temperature_module.SetTargetTemperature, - temperature_module.WaitForTemperature, - temperature_module.DeactivateTemperature, - thermocycler.SetTargetBlockTemperature, - thermocycler.WaitForBlockTemperature, - thermocycler.SetTargetLidTemperature, - thermocycler.WaitForLidTemperature, - thermocycler.DeactivateBlock, - thermocycler.DeactivateLid, - thermocycler.OpenLid, - thermocycler.CloseLid, - thermocycler.RunProfile, - calibration.CalibrateGripper, - calibration.CalibratePipette, - calibration.CalibrateModule, - calibration.MoveToMaintenancePosition, +Command = Annotated[ + Union[ + Aspirate, + AspirateInPlace, + Comment, + Custom, + Dispense, + DispenseInPlace, + BlowOut, + BlowOutInPlace, + ConfigureForVolume, + ConfigureNozzleLayout, + DropTip, + DropTipInPlace, + Home, + RetractAxis, + LoadLabware, + LoadLiquid, + LoadModule, + LoadPipette, + MoveLabware, + MoveRelative, + MoveToCoordinates, + MoveToWell, + MoveToAddressableArea, + MoveToAddressableAreaForDropTip, + PrepareToAspirate, + WaitForResume, + WaitForDuration, + PickUpTip, + SavePosition, + SetRailLights, + TouchTip, + SetStatusBar, + VerifyTipPresence, + GetTipPresence, + heater_shaker.WaitForTemperature, + heater_shaker.SetTargetTemperature, + heater_shaker.DeactivateHeater, + heater_shaker.SetAndWaitForShakeSpeed, + heater_shaker.DeactivateShaker, + heater_shaker.OpenLabwareLatch, + heater_shaker.CloseLabwareLatch, + magnetic_module.Disengage, + magnetic_module.Engage, + temperature_module.SetTargetTemperature, + temperature_module.WaitForTemperature, + temperature_module.DeactivateTemperature, + thermocycler.SetTargetBlockTemperature, + thermocycler.WaitForBlockTemperature, + thermocycler.SetTargetLidTemperature, + thermocycler.WaitForLidTemperature, + thermocycler.DeactivateBlock, + thermocycler.DeactivateLid, + thermocycler.OpenLid, + thermocycler.CloseLid, + thermocycler.RunProfile, + calibration.CalibrateGripper, + calibration.CalibratePipette, + calibration.CalibrateModule, + calibration.MoveToMaintenancePosition, + ], + Field(discriminator="commandType"), ] CommandParams = Union[ @@ -471,66 +477,69 @@ calibration.MoveToMaintenancePositionCommandType, ] -CommandCreate = Union[ - AspirateCreate, - AspirateInPlaceCreate, - CommentCreate, - ConfigureForVolumeCreate, - ConfigureNozzleLayoutCreate, - CustomCreate, - DispenseCreate, - DispenseInPlaceCreate, - BlowOutCreate, - BlowOutInPlaceCreate, - DropTipCreate, - DropTipInPlaceCreate, - HomeCreate, - RetractAxisCreate, - LoadLabwareCreate, - LoadLiquidCreate, - LoadModuleCreate, - LoadPipetteCreate, - MoveLabwareCreate, - MoveRelativeCreate, - MoveToCoordinatesCreate, - MoveToWellCreate, - MoveToAddressableAreaCreate, - MoveToAddressableAreaForDropTipCreate, - PrepareToAspirateCreate, - WaitForResumeCreate, - WaitForDurationCreate, - PickUpTipCreate, - SavePositionCreate, - SetRailLightsCreate, - TouchTipCreate, - SetStatusBarCreate, - VerifyTipPresenceCreate, - GetTipPresenceCreate, - heater_shaker.WaitForTemperatureCreate, - heater_shaker.SetTargetTemperatureCreate, - heater_shaker.DeactivateHeaterCreate, - heater_shaker.SetAndWaitForShakeSpeedCreate, - heater_shaker.DeactivateShakerCreate, - heater_shaker.OpenLabwareLatchCreate, - heater_shaker.CloseLabwareLatchCreate, - magnetic_module.DisengageCreate, - magnetic_module.EngageCreate, - temperature_module.SetTargetTemperatureCreate, - temperature_module.WaitForTemperatureCreate, - temperature_module.DeactivateTemperatureCreate, - thermocycler.SetTargetBlockTemperatureCreate, - thermocycler.WaitForBlockTemperatureCreate, - thermocycler.SetTargetLidTemperatureCreate, - thermocycler.WaitForLidTemperatureCreate, - thermocycler.DeactivateBlockCreate, - thermocycler.DeactivateLidCreate, - thermocycler.OpenLidCreate, - thermocycler.CloseLidCreate, - thermocycler.RunProfileCreate, - calibration.CalibrateGripperCreate, - calibration.CalibratePipetteCreate, - calibration.CalibrateModuleCreate, - calibration.MoveToMaintenancePositionCreate, +CommandCreate = Annotated[ + Union[ + AspirateCreate, + AspirateInPlaceCreate, + CommentCreate, + ConfigureForVolumeCreate, + ConfigureNozzleLayoutCreate, + CustomCreate, + DispenseCreate, + DispenseInPlaceCreate, + BlowOutCreate, + BlowOutInPlaceCreate, + DropTipCreate, + DropTipInPlaceCreate, + HomeCreate, + RetractAxisCreate, + LoadLabwareCreate, + LoadLiquidCreate, + LoadModuleCreate, + LoadPipetteCreate, + MoveLabwareCreate, + MoveRelativeCreate, + MoveToCoordinatesCreate, + MoveToWellCreate, + MoveToAddressableAreaCreate, + MoveToAddressableAreaForDropTipCreate, + PrepareToAspirateCreate, + WaitForResumeCreate, + WaitForDurationCreate, + PickUpTipCreate, + SavePositionCreate, + SetRailLightsCreate, + TouchTipCreate, + SetStatusBarCreate, + VerifyTipPresenceCreate, + GetTipPresenceCreate, + heater_shaker.WaitForTemperatureCreate, + heater_shaker.SetTargetTemperatureCreate, + heater_shaker.DeactivateHeaterCreate, + heater_shaker.SetAndWaitForShakeSpeedCreate, + heater_shaker.DeactivateShakerCreate, + heater_shaker.OpenLabwareLatchCreate, + heater_shaker.CloseLabwareLatchCreate, + magnetic_module.DisengageCreate, + magnetic_module.EngageCreate, + temperature_module.SetTargetTemperatureCreate, + temperature_module.WaitForTemperatureCreate, + temperature_module.DeactivateTemperatureCreate, + thermocycler.SetTargetBlockTemperatureCreate, + thermocycler.WaitForBlockTemperatureCreate, + thermocycler.SetTargetLidTemperatureCreate, + thermocycler.WaitForLidTemperatureCreate, + thermocycler.DeactivateBlockCreate, + thermocycler.DeactivateLidCreate, + thermocycler.OpenLidCreate, + thermocycler.CloseLidCreate, + thermocycler.RunProfileCreate, + calibration.CalibrateGripperCreate, + calibration.CalibratePipetteCreate, + calibration.CalibrateModuleCreate, + calibration.MoveToMaintenancePositionCreate, + ], + Field(discriminator="commandType"), ] CommandResult = Union[ From adc01d3b01b40f63631ead5d23f6bf2927b0009e Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Thu, 4 Jan 2024 14:44:24 -0500 Subject: [PATCH 2/6] Update stateless command unions. --- .../commands/stateless_commands.py | 90 ++++++++++--------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/robot-server/robot_server/commands/stateless_commands.py b/robot-server/robot_server/commands/stateless_commands.py index 9befd1901a6..871fcb5f8df 100644 --- a/robot-server/robot_server/commands/stateless_commands.py +++ b/robot-server/robot_server/commands/stateless_commands.py @@ -1,47 +1,57 @@ """Command requests and responses allowed to be used with /commands.""" from typing import Union +from typing_extensions import Annotated + +from pydantic import Field + from opentrons.protocol_engine import commands -StatelessCommandCreate = Union[ - commands.HomeCreate, - commands.SetRailLightsCreate, - commands.SetStatusBarCreate, - commands.magnetic_module.EngageCreate, - commands.magnetic_module.DisengageCreate, - commands.temperature_module.SetTargetTemperatureCreate, - commands.temperature_module.DeactivateTemperatureCreate, - commands.thermocycler.SetTargetBlockTemperatureCreate, - commands.thermocycler.SetTargetLidTemperatureCreate, - commands.thermocycler.DeactivateBlockCreate, - commands.thermocycler.DeactivateLidCreate, - commands.thermocycler.OpenLidCreate, - commands.thermocycler.CloseLidCreate, - commands.heater_shaker.SetTargetTemperatureCreate, - commands.heater_shaker.SetAndWaitForShakeSpeedCreate, - commands.heater_shaker.DeactivateHeaterCreate, - commands.heater_shaker.DeactivateShakerCreate, - commands.heater_shaker.OpenLabwareLatchCreate, - commands.heater_shaker.CloseLabwareLatchCreate, +StatelessCommandCreate = Annotated[ + Union[ + commands.HomeCreate, + commands.SetRailLightsCreate, + commands.SetStatusBarCreate, + commands.magnetic_module.EngageCreate, + commands.magnetic_module.DisengageCreate, + commands.temperature_module.SetTargetTemperatureCreate, + commands.temperature_module.DeactivateTemperatureCreate, + commands.thermocycler.SetTargetBlockTemperatureCreate, + commands.thermocycler.SetTargetLidTemperatureCreate, + commands.thermocycler.DeactivateBlockCreate, + commands.thermocycler.DeactivateLidCreate, + commands.thermocycler.OpenLidCreate, + commands.thermocycler.CloseLidCreate, + commands.heater_shaker.SetTargetTemperatureCreate, + commands.heater_shaker.SetAndWaitForShakeSpeedCreate, + commands.heater_shaker.DeactivateHeaterCreate, + commands.heater_shaker.DeactivateShakerCreate, + commands.heater_shaker.OpenLabwareLatchCreate, + commands.heater_shaker.CloseLabwareLatchCreate, + ], + Field(discriminator="commandType"), ] -StatelessCommand = Union[ - commands.Home, - commands.SetRailLights, - commands.SetStatusBar, - commands.magnetic_module.Engage, - commands.magnetic_module.Disengage, - commands.temperature_module.SetTargetTemperature, - commands.temperature_module.DeactivateTemperature, - commands.thermocycler.SetTargetBlockTemperature, - commands.thermocycler.SetTargetLidTemperature, - commands.thermocycler.DeactivateBlock, - commands.thermocycler.DeactivateLid, - commands.thermocycler.OpenLid, - commands.thermocycler.CloseLid, - commands.heater_shaker.SetTargetTemperature, - commands.heater_shaker.SetAndWaitForShakeSpeed, - commands.heater_shaker.DeactivateHeater, - commands.heater_shaker.DeactivateShaker, - commands.heater_shaker.OpenLabwareLatch, - commands.heater_shaker.CloseLabwareLatch, +StatelessCommand = Annotated[ + Union[ + commands.Home, + commands.SetRailLights, + commands.SetStatusBar, + commands.magnetic_module.Engage, + commands.magnetic_module.Disengage, + commands.temperature_module.SetTargetTemperature, + commands.temperature_module.DeactivateTemperature, + commands.thermocycler.SetTargetBlockTemperature, + commands.thermocycler.SetTargetLidTemperature, + commands.thermocycler.DeactivateBlock, + commands.thermocycler.DeactivateLid, + commands.thermocycler.OpenLid, + commands.thermocycler.CloseLid, + commands.heater_shaker.SetTargetTemperature, + commands.heater_shaker.SetAndWaitForShakeSpeed, + commands.heater_shaker.DeactivateHeater, + commands.heater_shaker.DeactivateShaker, + commands.heater_shaker.OpenLabwareLatch, + commands.heater_shaker.CloseLabwareLatch, + ], + Field(discriminator="commandType"), ] From 1e6d4e2e07d5e226d4f101c18ccee9eb1cc83f56 Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Thu, 4 Jan 2024 14:45:28 -0500 Subject: [PATCH 3/6] Work around Pydantic bug. --- robot-server/robot_server/commands/router.py | 7 ++++++- .../maintenance_runs/router/commands_router.py | 7 ++++++- robot-server/robot_server/runs/router/commands_router.py | 7 ++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/robot-server/robot_server/commands/router.py b/robot-server/robot_server/commands/router.py index 0d025b71dea..96e4ad7e049 100644 --- a/robot-server/robot_server/commands/router.py +++ b/robot-server/robot_server/commands/router.py @@ -27,6 +27,11 @@ commands_router = APIRouter() +# https://github.com/pydantic/pydantic/issues/3782 +class RequestModelWithCommand(RequestModel[StatelessCommandCreate]): + data: StatelessCommandCreate + + class CommandNotFound(ErrorDetails): """An error returned if the given command cannot be found.""" @@ -50,7 +55,7 @@ class CommandNotFound(ErrorDetails): }, ) async def create_command( - request_body: RequestModel[StatelessCommandCreate], + request_body: RequestModelWithCommand, waitUntilComplete: bool = Query( False, description=( diff --git a/robot-server/robot_server/maintenance_runs/router/commands_router.py b/robot-server/robot_server/maintenance_runs/router/commands_router.py index 4dc2901b959..ab3edf03ae3 100644 --- a/robot-server/robot_server/maintenance_runs/router/commands_router.py +++ b/robot-server/robot_server/maintenance_runs/router/commands_router.py @@ -42,6 +42,11 @@ commands_router = APIRouter() +# https://github.com/pydantic/pydantic/issues/3782 +class RequestModelWithCommand(RequestModel[pe_commands.CommandCreate]): + data: pe_commands.CommandCreate + + class CommandNotFound(ErrorDetails): """An error if a given run command is not found.""" @@ -125,7 +130,7 @@ async def get_current_run_engine_from_url( }, ) async def create_run_command( - request_body: RequestModel[pe_commands.CommandCreate], + request_body: RequestModelWithCommand, waitUntilComplete: bool = Query( default=False, description=( diff --git a/robot-server/robot_server/runs/router/commands_router.py b/robot-server/robot_server/runs/router/commands_router.py index 0c5a9a9444e..b844ce1301b 100644 --- a/robot-server/robot_server/runs/router/commands_router.py +++ b/robot-server/robot_server/runs/router/commands_router.py @@ -38,6 +38,11 @@ commands_router = APIRouter() +# https://github.com/pydantic/pydantic/issues/3782 +class RequestModelWithCommand(RequestModel[pe_commands.CommandCreate]): + data: pe_commands.CommandCreate + + class CommandNotFound(ErrorDetails): """An error if a given run command is not found.""" @@ -146,7 +151,7 @@ async def get_current_run_engine_from_url( }, ) async def create_run_command( - request_body: RequestModel[pe_commands.CommandCreate], + request_body: RequestModelWithCommand, waitUntilComplete: bool = Query( default=False, description=( From 8695a992c7c3ecce66bc7b2bf0b303949e0832a0 Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Mon, 8 Jan 2024 11:28:49 -0500 Subject: [PATCH 4/6] Fix names and docstrings for union workarounds. --- robot-server/robot_server/commands/router.py | 12 +++++++++--- .../maintenance_runs/router/commands_router.py | 12 +++++++++--- .../robot_server/runs/router/commands_router.py | 12 +++++++++--- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/robot-server/robot_server/commands/router.py b/robot-server/robot_server/commands/router.py index 96e4ad7e049..d831d889424 100644 --- a/robot-server/robot_server/commands/router.py +++ b/robot-server/robot_server/commands/router.py @@ -27,8 +27,14 @@ commands_router = APIRouter() -# https://github.com/pydantic/pydantic/issues/3782 -class RequestModelWithCommand(RequestModel[StatelessCommandCreate]): +class RequestModelWithStatelessCommandCreate(RequestModel[StatelessCommandCreate]): + """Equivalent to RequestModel[StatelessCommandCreate]. + + This works around a Pydantic v<2 bug where RequestModel[StatelessCommandCreate] + doesn't parse using the StatelessCommandCreate union discriminator. + https://github.com/pydantic/pydantic/issues/3782 + """ + data: StatelessCommandCreate @@ -55,7 +61,7 @@ class CommandNotFound(ErrorDetails): }, ) async def create_command( - request_body: RequestModelWithCommand, + request_body: RequestModelWithStatelessCommandCreate, waitUntilComplete: bool = Query( False, description=( diff --git a/robot-server/robot_server/maintenance_runs/router/commands_router.py b/robot-server/robot_server/maintenance_runs/router/commands_router.py index ab3edf03ae3..09eb4cce0bf 100644 --- a/robot-server/robot_server/maintenance_runs/router/commands_router.py +++ b/robot-server/robot_server/maintenance_runs/router/commands_router.py @@ -42,8 +42,14 @@ commands_router = APIRouter() -# https://github.com/pydantic/pydantic/issues/3782 -class RequestModelWithCommand(RequestModel[pe_commands.CommandCreate]): +class RequestModelWithCommandCreate(RequestModel[pe_commands.CommandCreate]): + """Equivalent to RequestModel[CommandCreate]. + + This works around a Pydantic v<2 bug where RequestModel[CommandCreate] + doesn't parse using the CommandCreate union discriminator. + https://github.com/pydantic/pydantic/issues/3782 + """ + data: pe_commands.CommandCreate @@ -130,7 +136,7 @@ async def get_current_run_engine_from_url( }, ) async def create_run_command( - request_body: RequestModelWithCommand, + request_body: RequestModelWithCommandCreate, waitUntilComplete: bool = Query( default=False, description=( diff --git a/robot-server/robot_server/runs/router/commands_router.py b/robot-server/robot_server/runs/router/commands_router.py index b844ce1301b..10e1833bd1a 100644 --- a/robot-server/robot_server/runs/router/commands_router.py +++ b/robot-server/robot_server/runs/router/commands_router.py @@ -38,8 +38,14 @@ commands_router = APIRouter() -# https://github.com/pydantic/pydantic/issues/3782 -class RequestModelWithCommand(RequestModel[pe_commands.CommandCreate]): +class RequestModelWithCommandCreate(RequestModel[pe_commands.CommandCreate]): + """Equivalent to RequestModel[CommandCreate]. + + This works around a Pydantic v<2 bug where RequestModel[CommandCreate] + doesn't parse using the CommandCreate union discriminator. + https://github.com/pydantic/pydantic/issues/3782 + """ + data: pe_commands.CommandCreate @@ -151,7 +157,7 @@ async def get_current_run_engine_from_url( }, ) async def create_run_command( - request_body: RequestModelWithCommand, + request_body: RequestModelWithCommandCreate, waitUntilComplete: bool = Query( default=False, description=( From 06882d17b98d504348454e14a07885e4fe674b5e Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Mon, 8 Jan 2024 13:51:02 -0500 Subject: [PATCH 5/6] Update tests. --- robot-server/tests/commands/test_router.py | 13 +++++++++---- .../router/test_commands_router.py | 10 ++++------ .../tests/runs/router/test_commands_router.py | 14 ++++++-------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/robot-server/tests/commands/test_router.py b/robot-server/tests/commands/test_router.py index 07a5ef2db24..bc90603c7f9 100644 --- a/robot-server/tests/commands/test_router.py +++ b/robot-server/tests/commands/test_router.py @@ -11,9 +11,14 @@ ) from opentrons.protocol_engine.errors import CommandDoesNotExistError -from robot_server.service.json_api import RequestModel, MultiBodyMeta +from robot_server.service.json_api import MultiBodyMeta from robot_server.errors import ApiError -from robot_server.commands.router import create_command, get_commands_list, get_command +from robot_server.commands.router import ( + RequestModelWithStatelessCommandCreate, + create_command, + get_commands_list, + get_command, +) @pytest.fixture() @@ -53,7 +58,7 @@ def _stub_queued_command_state(*_a: object, **_k: object) -> pe_commands.Command ).then_do(_stub_queued_command_state) result = await create_command( - RequestModel(data=command_create), + RequestModelWithStatelessCommandCreate(data=command_create), waitUntilComplete=False, timeout=42, engine=protocol_engine, @@ -111,7 +116,7 @@ def _stub_completed_command_state(*_a: object, **_k: object) -> None: ) result = await create_command( - RequestModel(data=command_create), + RequestModelWithStatelessCommandCreate(data=command_create), waitUntilComplete=True, timeout=42, engine=protocol_engine, diff --git a/robot-server/tests/maintenance_runs/router/test_commands_router.py b/robot-server/tests/maintenance_runs/router/test_commands_router.py index e9ffbd79a71..37a0114e65e 100644 --- a/robot-server/tests/maintenance_runs/router/test_commands_router.py +++ b/robot-server/tests/maintenance_runs/router/test_commands_router.py @@ -14,10 +14,7 @@ from opentrons.protocol_engine.errors import CommandDoesNotExistError from robot_server.errors import ApiError -from robot_server.service.json_api import ( - RequestModel, - MultiBodyMeta, -) +from robot_server.service.json_api import MultiBodyMeta from robot_server.maintenance_runs.maintenance_engine_store import ( MaintenanceEngineStore, @@ -33,6 +30,7 @@ CommandCollectionLinks, CommandLink, CommandLinkMeta, + RequestModelWithCommandCreate, create_run_command, get_run_command, get_run_commands, @@ -107,7 +105,7 @@ def _stub_queued_command_state(*_a: object, **_k: object) -> pe_commands.Command ).then_do(_stub_queued_command_state) result = await create_run_command( - request_body=RequestModel(data=command_request), + request_body=RequestModelWithCommandCreate(data=command_request), waitUntilComplete=False, protocol_engine=mock_protocol_engine, ) @@ -165,7 +163,7 @@ def _stub_completed_command_state(*_a: object, **_k: object) -> None: ) result = await create_run_command( - request_body=RequestModel(data=command_request), + request_body=RequestModelWithCommandCreate(data=command_request), waitUntilComplete=True, timeout=999, protocol_engine=mock_protocol_engine, diff --git a/robot-server/tests/runs/router/test_commands_router.py b/robot-server/tests/runs/router/test_commands_router.py index a53b7c49142..478e05996b3 100644 --- a/robot-server/tests/runs/router/test_commands_router.py +++ b/robot-server/tests/runs/router/test_commands_router.py @@ -13,10 +13,7 @@ ) from robot_server.errors import ApiError -from robot_server.service.json_api import ( - RequestModel, - MultiBodyMeta, -) +from robot_server.service.json_api import MultiBodyMeta from robot_server.runs.run_store import RunStore, CommandNotFoundError from robot_server.runs.engine_store import EngineStore @@ -26,6 +23,7 @@ CommandCollectionLinks, CommandLink, CommandLinkMeta, + RequestModelWithCommandCreate, create_run_command, get_run_command, get_run_commands, @@ -123,7 +121,7 @@ def _stub_queued_command_state(*_a: object, **_k: object) -> pe_commands.Command ).then_do(_stub_queued_command_state) result = await create_run_command( - request_body=RequestModel(data=command_request), + request_body=RequestModelWithCommandCreate(data=command_request), waitUntilComplete=False, protocol_engine=mock_protocol_engine, ) @@ -181,7 +179,7 @@ def _stub_completed_command_state(*_a: object, **_k: object) -> None: ) result = await create_run_command( - request_body=RequestModel(data=command_request), + request_body=RequestModelWithCommandCreate(data=command_request), waitUntilComplete=True, timeout=999, protocol_engine=mock_protocol_engine, @@ -207,7 +205,7 @@ async def test_add_conflicting_setup_command( with pytest.raises(ApiError) as exc_info: await create_run_command( - request_body=RequestModel(data=command_request), + request_body=RequestModelWithCommandCreate(data=command_request), waitUntilComplete=False, protocol_engine=mock_protocol_engine, ) @@ -235,7 +233,7 @@ async def test_add_command_to_stopped_engine( with pytest.raises(ApiError) as exc_info: await create_run_command( - request_body=RequestModel(data=command_request), + request_body=RequestModelWithCommandCreate(data=command_request), waitUntilComplete=False, protocol_engine=mock_protocol_engine, ) From be08e43c8b447c2c06c8eeb79676193374962007 Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Mon, 8 Jan 2024 15:31:51 -0500 Subject: [PATCH 6/6] Update command schema. --- shared-data/command/schemas/8.json | 65 ++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/shared-data/command/schemas/8.json b/shared-data/command/schemas/8.json index 984fe40cb36..727ca89fbd8 100644 --- a/shared-data/command/schemas/8.json +++ b/shared-data/command/schemas/8.json @@ -1,6 +1,71 @@ { "title": "CreateCommandUnion", "description": "Model that validates a union of all CommandCreate models.", + "discriminator": { + "propertyName": "commandType", + "mapping": { + "aspirate": "#/definitions/AspirateCreate", + "aspirateInPlace": "#/definitions/AspirateInPlaceCreate", + "comment": "#/definitions/CommentCreate", + "configureForVolume": "#/definitions/ConfigureForVolumeCreate", + "configureNozzleLayout": "#/definitions/ConfigureNozzleLayoutCreate", + "custom": "#/definitions/CustomCreate", + "dispense": "#/definitions/DispenseCreate", + "dispenseInPlace": "#/definitions/DispenseInPlaceCreate", + "blowout": "#/definitions/BlowOutCreate", + "blowOutInPlace": "#/definitions/BlowOutInPlaceCreate", + "dropTip": "#/definitions/DropTipCreate", + "dropTipInPlace": "#/definitions/DropTipInPlaceCreate", + "home": "#/definitions/HomeCreate", + "retractAxis": "#/definitions/RetractAxisCreate", + "loadLabware": "#/definitions/LoadLabwareCreate", + "loadLiquid": "#/definitions/LoadLiquidCreate", + "loadModule": "#/definitions/LoadModuleCreate", + "loadPipette": "#/definitions/LoadPipetteCreate", + "moveLabware": "#/definitions/MoveLabwareCreate", + "moveRelative": "#/definitions/MoveRelativeCreate", + "moveToCoordinates": "#/definitions/MoveToCoordinatesCreate", + "moveToWell": "#/definitions/MoveToWellCreate", + "moveToAddressableArea": "#/definitions/MoveToAddressableAreaCreate", + "moveToAddressableAreaForDropTip": "#/definitions/MoveToAddressableAreaForDropTipCreate", + "prepareToAspirate": "#/definitions/PrepareToAspirateCreate", + "waitForResume": "#/definitions/WaitForResumeCreate", + "pause": "#/definitions/WaitForResumeCreate", + "waitForDuration": "#/definitions/WaitForDurationCreate", + "pickUpTip": "#/definitions/PickUpTipCreate", + "savePosition": "#/definitions/SavePositionCreate", + "setRailLights": "#/definitions/SetRailLightsCreate", + "touchTip": "#/definitions/TouchTipCreate", + "setStatusBar": "#/definitions/SetStatusBarCreate", + "verifyTipPresence": "#/definitions/VerifyTipPresenceCreate", + "getTipPresence": "#/definitions/GetTipPresenceCreate", + "heaterShaker/waitForTemperature": "#/definitions/opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureCreate", + "heaterShaker/setTargetTemperature": "#/definitions/opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureCreate", + "heaterShaker/deactivateHeater": "#/definitions/DeactivateHeaterCreate", + "heaterShaker/setAndWaitForShakeSpeed": "#/definitions/SetAndWaitForShakeSpeedCreate", + "heaterShaker/deactivateShaker": "#/definitions/DeactivateShakerCreate", + "heaterShaker/openLabwareLatch": "#/definitions/OpenLabwareLatchCreate", + "heaterShaker/closeLabwareLatch": "#/definitions/CloseLabwareLatchCreate", + "magneticModule/disengage": "#/definitions/DisengageCreate", + "magneticModule/engage": "#/definitions/EngageCreate", + "temperatureModule/setTargetTemperature": "#/definitions/opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureCreate", + "temperatureModule/waitForTemperature": "#/definitions/opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureCreate", + "temperatureModule/deactivate": "#/definitions/DeactivateTemperatureCreate", + "thermocycler/setTargetBlockTemperature": "#/definitions/SetTargetBlockTemperatureCreate", + "thermocycler/waitForBlockTemperature": "#/definitions/WaitForBlockTemperatureCreate", + "thermocycler/setTargetLidTemperature": "#/definitions/SetTargetLidTemperatureCreate", + "thermocycler/waitForLidTemperature": "#/definitions/WaitForLidTemperatureCreate", + "thermocycler/deactivateBlock": "#/definitions/DeactivateBlockCreate", + "thermocycler/deactivateLid": "#/definitions/DeactivateLidCreate", + "thermocycler/openLid": "#/definitions/OpenLidCreate", + "thermocycler/closeLid": "#/definitions/CloseLidCreate", + "thermocycler/runProfile": "#/definitions/RunProfileCreate", + "calibration/calibrateGripper": "#/definitions/CalibrateGripperCreate", + "calibration/calibratePipette": "#/definitions/CalibratePipetteCreate", + "calibration/calibrateModule": "#/definitions/CalibrateModuleCreate", + "calibration/moveToMaintenancePosition": "#/definitions/MoveToMaintenancePositionCreate" + } + }, "anyOf": [ { "$ref": "#/definitions/AspirateCreate"