diff --git a/app/src/sessions/__fixtures__/index.js b/app/src/sessions/__fixtures__/index.js index cd7c6f977c6..6ef01b228fb 100644 --- a/app/src/sessions/__fixtures__/index.js +++ b/app/src/sessions/__fixtures__/index.js @@ -36,12 +36,12 @@ export const mockSession: Types.Session = { } export const mockSessionCommand: Types.SessionCommandAttributes = { - command: 'jog', + command: 'calibration.jog', data: { someData: 32 }, } export const mockSessionCommandAttributes: Types.SessionCommandAttributes = { - command: 'preparePipette', + command: 'calibration.preparePipette', status: 'accepted', data: {}, } diff --git a/app/src/sessions/calibration-check/constants.js b/app/src/sessions/calibration-check/constants.js index 0321a8bcbb7..0ed40b88758 100644 --- a/app/src/sessions/calibration-check/constants.js +++ b/app/src/sessions/calibration-check/constants.js @@ -42,15 +42,18 @@ export const CHECK_STEP_BAD_ROBOT_CALIBRATION: 'badCalibrationData' = export const CHECK_STEP_NO_PIPETTES_ATTACHED: 'noPipettesAttached' = 'noPipettesAttached' -const LOAD_LABWARE: 'loadLabware' = 'loadLabware' -const PREPARE_PIPETTE: 'preparePipette' = 'preparePipette' -const JOG: 'jog' = 'jog' -const PICK_UP_TIP: 'pickUpTip' = 'pickUpTip' -const CONFIRM_TIP: 'confirmTip' = 'confirmTip' -const INVALIDATE_TIP: 'invalidateTip' = 'invalidateTip' -const COMPARE_POINT: 'comparePoint' = 'comparePoint' -const GO_TO_NEXT_CHECK: 'goToNextCheck' = 'goToNextCheck' -const EXIT: 'exitSession' = 'exitSession' +const LOAD_LABWARE: 'calibration.loadLabware' = 'calibration.loadLabware' +const PREPARE_PIPETTE: 'calibration.preparePipette' = + 'calibration.preparePipette' +const JOG: 'calibration.jog' = 'calibration.jog' +const PICK_UP_TIP: 'calibration.pickUpTip' = 'calibration.pickUpTip' +const CONFIRM_TIP: 'calibration.confirmTip' = 'calibration.confirmTip' +const INVALIDATE_TIP: 'calibration.invalidateTip' = 'calibration.invalidateTip' +const COMPARE_POINT: 'calibration.check.comparePoint' = + 'calibration.check.comparePoint' +const GO_TO_NEXT_CHECK: 'calibration.check.goToNextCheck' = + 'calibration.check.goToNextCheck' +const EXIT: 'calibration.exitSession' = 'calibration.exitSession' export const checkCommands = { LOAD_LABWARE, diff --git a/app/src/sessions/epic/__tests__/createSessionCommandEpic.test.js b/app/src/sessions/epic/__tests__/createSessionCommandEpic.test.js index f13662ae5c4..e4cdf405206 100644 --- a/app/src/sessions/epic/__tests__/createSessionCommandEpic.test.js +++ b/app/src/sessions/epic/__tests__/createSessionCommandEpic.test.js @@ -33,7 +33,7 @@ describe('createSessionCommandEpic', () => { data: { type: 'Command', attributes: { - command: 'jog', + command: 'calibration.jog', data: { someData: 32, }, diff --git a/robot-server/robot_server/robot/calibration/check/session.py b/robot-server/robot_server/robot/calibration/check/session.py index 2925f505e20..056cda85d67 100644 --- a/robot-server/robot_server/robot/calibration/check/session.py +++ b/robot-server/robot_server/robot/calibration/check/session.py @@ -13,7 +13,8 @@ from robot_server.robot.calibration.helper_classes import ( CheckMove, DeckCalibrationError, PipetteRank, PipetteInfo, PipetteStatus ) -from robot_server.service.session.models import OffsetVector +from robot_server.service.session.models import OffsetVector,\ + CalibrationCommand, CalibrationCheckCommand from opentrons.hardware_control import ThreadManager from opentrons.protocol_api import labware @@ -57,16 +58,16 @@ class CalibrationCheckState(str, Enum): class CalibrationCheckTrigger(str, Enum): - load_labware = "loadLabware" - prepare_pipette = "preparePipette" - jog = "jog" - pick_up_tip = "pickUpTip" - confirm_tip_attached = "confirmTip" - invalidate_tip = "invalidateTip" - compare_point = "comparePoint" - go_to_next_check = "goToNextCheck" - exit = "exitSession" - reject_calibration = "rejectCalibration" + load_labware = CalibrationCommand.load_labware.value + prepare_pipette = CalibrationCommand.prepare_pipette.value + jog = CalibrationCommand.jog.value + pick_up_tip = CalibrationCommand.pick_up_tip.value + confirm_tip_attached = CalibrationCommand.confirm_tip_attached.value + invalidate_tip = CalibrationCommand.invalidate_tip.value + compare_point = CalibrationCheckCommand.compare_point.value + go_to_next_check = CalibrationCheckCommand.go_to_next_check.value + exit = CalibrationCommand.exit.value + reject_calibration = CalibrationCheckCommand.reject_calibration.value CHECK_TRANSITIONS: typing.List[typing.Dict[str, typing.Any]] = [ diff --git a/robot-server/robot_server/robot/calibration/tip_length/state_machine.py b/robot-server/robot_server/robot/calibration/tip_length/state_machine.py index 17ece7f19d0..f6e6df260ca 100644 --- a/robot-server/robot_server/robot/calibration/tip_length/state_machine.py +++ b/robot-server/robot_server/robot/calibration/tip_length/state_machine.py @@ -1,5 +1,6 @@ from typing import Dict -from robot_server.service.session.models import CommandName +from robot_server.service.session.models import CommandDefinition, \ + TipLengthCalibrationCommand, CalibrationCommand from robot_server.robot.calibration.tip_length.util import ( SimpleStateMachine, TipCalibrationError as Error @@ -9,41 +10,41 @@ ) -TIP_LENGTH_TRANSITIONS: Dict[State, Dict[CommandName, State]] = { +TIP_LENGTH_TRANSITIONS: Dict[State, Dict[CommandDefinition, State]] = { State.sessionStarted: { - CommandName.load_labware: State.labwareLoaded + CalibrationCommand.load_labware: State.labwareLoaded }, State.labwareLoaded: { - CommandName.move_to_reference_point: State.measuringNozzleOffset + TipLengthCalibrationCommand.move_to_reference_point: State.measuringNozzleOffset # noqa: e501 }, State.measuringNozzleOffset: { - CommandName.save_offset: State.preparingPipette, - CommandName.jog: State.measuringNozzleOffset + CalibrationCommand.save_offset: State.preparingPipette, + CalibrationCommand.jog: State.measuringNozzleOffset }, State.preparingPipette: { - CommandName.jog: State.preparingPipette, - CommandName.pick_up_tip: State.preparingPipette, - CommandName.invalidate_tip: State.preparingPipette, - CommandName.move_to_reference_point: State.measuringTipOffset + CalibrationCommand.jog: State.preparingPipette, + CalibrationCommand.pick_up_tip: State.preparingPipette, + CalibrationCommand.invalidate_tip: State.preparingPipette, + TipLengthCalibrationCommand.move_to_reference_point: State.measuringTipOffset # noqa: e501 }, State.measuringTipOffset: { - CommandName.save_offset: State.calibrationComplete, - CommandName.jog: State.measuringTipOffset + CalibrationCommand.save_offset: State.calibrationComplete, + CalibrationCommand.jog: State.measuringTipOffset }, State.WILDCARD: { - CommandName.exit: State.sessionExited + CalibrationCommand.exit: State.sessionExited } } -class TipCalibrationStateMachine(): +class TipCalibrationStateMachine: def __init__(self): self._state_machine = SimpleStateMachine( states=set(s for s in State), transitions=TIP_LENGTH_TRANSITIONS ) - def get_next_state(self, from_state: State, command: CommandName): + def get_next_state(self, from_state: State, command: CommandDefinition): next_state = self._state_machine.get_next_state(from_state, command) if next_state: return next_state diff --git a/robot-server/robot_server/robot/calibration/tip_length/user_flow.py b/robot-server/robot_server/robot/calibration/tip_length/user_flow.py index eb932e5cc8c..b09881a2591 100644 --- a/robot-server/robot_server/robot/calibration/tip_length/user_flow.py +++ b/robot-server/robot_server/robot/calibration/tip_length/user_flow.py @@ -1,7 +1,8 @@ from typing import Dict, Awaitable, Callable, Any from opentrons.types import Mount, Point from opentrons.hardware_control import ThreadManager -from robot_server.service.session.models import CommandName +from robot_server.service.session.models import CalibrationCommand, \ + TipLengthCalibrationCommand from robot_server.robot.calibration.tip_length.state_machine import ( TipCalibrationStateMachine ) @@ -19,32 +20,6 @@ unique (by serial number) physical pipette. """ -TIP_LENGTH_TRANSITIONS: Dict[State, Dict[CommandName, State]] = { - State.sessionStarted: { - CommandName.load_labware: State.labwareLoaded - }, - State.labwareLoaded: { - CommandName.move_to_reference_point: State.measuringNozzleOffset - }, - State.measuringNozzleOffset: { - CommandName.save_offset: State.preparingPipette, - CommandName.jog: State.measuringNozzleOffset - }, - State.preparingPipette: { - CommandName.jog: State.preparingPipette, - CommandName.pick_up_tip: State.preparingPipette, - CommandName.invalidate_tip: State.preparingPipette, - CommandName.move_to_reference_point: State.measuringTipOffset - }, - State.measuringTipOffset: { - CommandName.save_offset: State.calibrationComplete, - CommandName.jog: State.measuringTipOffset - }, - State.WILDCARD: { - CommandName.exit: State.sessionExited - } -} - # TODO: BC 2020-07-08: type all command logic here with actual Model type COMMAND_HANDLER = Callable[..., Awaitable] @@ -68,13 +43,13 @@ def __init__(self, 'cannot run tip length calibration') self._command_map: COMMAND_MAP = { - CommandName.load_labware: self.load_labware, - CommandName.jog: self.jog, - CommandName.pick_up_tip: self.pick_up_tip, - CommandName.invalidate_tip: self.invalidate_tip, - CommandName.save_offset: self.save_offset, - CommandName.move_to_reference_point: self.move_to_reference_point, - CommandName.exit: self.exit_session, + CalibrationCommand.load_labware: self.load_labware, + CalibrationCommand.jog: self.jog, + CalibrationCommand.pick_up_tip: self.pick_up_tip, + CalibrationCommand.invalidate_tip: self.invalidate_tip, + CalibrationCommand.save_offset: self.save_offset, + TipLengthCalibrationCommand.move_to_reference_point: self.move_to_reference_point, # noqa: E501 + CalibrationCommand.exit: self.exit_session, } def _set_current_state(self, to_state: State): diff --git a/robot-server/robot_server/service/session/command_execution/__init__.py b/robot-server/robot_server/service/session/command_execution/__init__.py index 358c3ba5abf..b3c1ab4e365 100644 --- a/robot-server/robot_server/service/session/command_execution/__init__.py +++ b/robot-server/robot_server/service/session/command_execution/__init__.py @@ -1,5 +1,5 @@ from .base_command_queue import CommandQueue # noqa(W0611) from .base_executor import CommandExecutor # noqa(W0611) -from .command import Command, CompletedCommand, create_command # noqa(W0611) +from .command import Command, CompletedCommand, create_command, CommandResult # noqa(W0611) from .callable_executor import CallableExecutor # noqa(W0611) from .hardware_executor import HardwareExecutor, DefaultHardwareExecutor # noqa(W0611) diff --git a/robot-server/robot_server/service/session/command_execution/command.py b/robot-server/robot_server/service/session/command_execution/command.py index 2ebfd50819f..1b47426164b 100644 --- a/robot-server/robot_server/service/session/command_execution/command.py +++ b/robot-server/robot_server/service/session/command_execution/command.py @@ -2,12 +2,12 @@ from dataclasses import dataclass, field from robot_server.service.session.models import IdentifierType, \ - create_identifier, CommandName, CommandDataType, CommandStatus + create_identifier, CommandDefinition, CommandDataType, CommandStatus @dataclass(frozen=True) class CommandContent: - name: CommandName + name: CommandDefinition data: CommandDataType @@ -37,7 +37,7 @@ class CompletedCommand: result: CommandResult -def create_command(name: CommandName, data: CommandDataType) -> Command: +def create_command(name: CommandDefinition, data: CommandDataType) -> Command: """Create a command object""" return Command( content=CommandContent( diff --git a/robot-server/robot_server/service/session/command_execution/hardware_executor.py b/robot-server/robot_server/service/session/command_execution/hardware_executor.py index 43a2970d6b1..eec26c6057a 100644 --- a/robot-server/robot_server/service/session/command_execution/hardware_executor.py +++ b/robot-server/robot_server/service/session/command_execution/hardware_executor.py @@ -1,11 +1,10 @@ import typing from opentrons.hardware_control import ThreadManager -from . import Command, CompletedCommand +from . import Command, CompletedCommand, CommandResult from . base_executor import CommandExecutor -from .command import CommandResult from ..errors import UnsupportedCommandException -from ..models import CommandDataType, CommandName +from ..models import CommandDataType, RobotCommand, CommandDefinition from robot_server.util import duration @@ -25,14 +24,14 @@ async def toggle_lights(hardware: ThreadManager, *args): class HardwareExecutor(CommandExecutor): """A command executor that executes direct hardware commands""" - COMMAND_TO_FUNC: typing.Dict[CommandName, COMMAND_HANDLER] = { - CommandName.home_all_motors: home_all_motors, - CommandName.toggle_lights: toggle_lights + COMMAND_TO_FUNC: typing.Dict[CommandDefinition, COMMAND_HANDLER] = { + RobotCommand.home_all_motors: home_all_motors, + RobotCommand.toggle_lights: toggle_lights } def __init__(self, hardware: ThreadManager, - command_filter: typing.Optional[typing.Set[CommandName]]): + command_filter: typing.Optional[typing.Set[RobotCommand]]): """ Constructor @@ -59,7 +58,7 @@ async def execute(self, command: Command) -> CompletedCommand: completed_at=timed.end) ) - def get_handler(self, command_name: CommandName) \ + def get_handler(self, command_name: CommandDefinition) \ -> typing.Optional[COMMAND_HANDLER]: """Get the handler for the command type""" if self._command_filter is not None: @@ -71,6 +70,6 @@ def get_handler(self, command_name: CommandName) \ class DefaultHardwareExecutor(HardwareExecutor): """The default command executor""" def __init__(self, hardware: ThreadManager): - super().__init__(hardware, {CommandName.home_all_motors, - CommandName.home_pipette, - CommandName.toggle_lights}) + super().__init__(hardware, {RobotCommand.home_all_motors, + RobotCommand.home_pipette, + RobotCommand.toggle_lights}) diff --git a/robot-server/robot_server/service/session/models.py b/robot-server/robot_server/service/session/models.py index 446669743fc..d7ffbdea53f 100644 --- a/robot-server/robot_server/service/session/models.py +++ b/robot-server/robot_server/service/session/models.py @@ -1,6 +1,7 @@ from datetime import datetime from enum import Enum import typing +from functools import lru_cache from uuid import uuid4 from pydantic import BaseModel, Field, validator @@ -50,13 +51,50 @@ class CommandStatus(str, Enum): failed = "failed" -class CommandName(str, Enum): - """The available session commands""" +class CommandDefinition(str, Enum): + def __new__(cls, value, model=EmptyModel): + """Create a string enum with the expected model""" + namespace = cls.namespace() + full_name = f"{namespace}.{value}" if namespace else value + obj = str.__new__(cls, full_name) + obj._value_ = full_name + obj._localname = value + obj._model = model + return obj + + @property + def model(self): + """Get the data model of the payload of the command""" + return self._model + + @staticmethod + def namespace(): + """ + This is primarily for allowing definitions to define a + namespace. The name space will be used to make the value of the + enum. It will be "{namespace}.{value}" + """ + return None + + @property + def localname(self): + """Get the name of the command without the namespace""" + return self._localname + + +class RobotCommand(CommandDefinition): + """Generic commands""" home_all_motors = "homeAllMotors" home_pipette = "homePipette" toggle_lights = "toggleLights" - # Shared Between Calibration Flows + @staticmethod + def namespace(): + return "robot" + + +class CalibrationCommand(CommandDefinition): + """Shared Between Calibration Flows""" load_labware = "loadLabware" prepare_pipette = "preparePipette" jog = ("jog", JogPosition) @@ -64,27 +102,32 @@ class CommandName(str, Enum): confirm_tip_attached = "confirmTip" invalidate_tip = "invalidateTip" save_offset = "saveOffset" + exit = "exitSession" + + @staticmethod + def namespace(): + return "calibration" - # Cal Check Specific + +class CalibrationCheckCommand(CommandDefinition): + """Cal Check Specific""" compare_point = "comparePoint" go_to_next_check = "goToNextCheck" - exit = "exit" # TODO: remove unused command name and trigger reject_calibration = "rejectCalibration" - # Tip Length Calibration Specific - move_to_reference_point = "moveToReferencePoint" + @staticmethod + def namespace(): + return "calibration.check" - def __new__(cls, value, model=EmptyModel): - """Create a string enum with the expected model""" - obj = str.__new__(cls, value) - obj._value_ = value - obj._model = model - return obj - @property - def model(self): - return self._model +class TipLengthCalibrationCommand(CommandDefinition): + """Tip Length Calibration Specific""" + move_to_reference_point = "moveToReferencePoint" + + @staticmethod + def namespace(): + return "calibration.tipLength" CommandDataType = typing.Union[ @@ -93,6 +136,15 @@ def model(self): ] +# A Union of all CommandDefinition enumerations accepted +CommandDefinitionType = typing.Union[ + RobotCommand, + CalibrationCommand, + CalibrationCheckCommand, + TipLengthCalibrationCommand +] + + class BasicSession(BaseModel): """Minimal session description""" sessionType: SessionType =\ @@ -114,8 +166,9 @@ class BasicSessionCommand(BaseModel): """A session command""" data: CommandDataType # For validation, command MUST appear after data - command: CommandName = Field(..., - description="The command description") + command: CommandDefinitionType = Field( + ..., + description="The command description") @validator('command', always=True, allow_reuse=True) def check_data_type(cls, v, values): @@ -126,6 +179,24 @@ def check_data_type(cls, v, values): f"Expecting {v.model}") return v + @validator('command', pre=True) + def pre_namespace_backwards_compatibility(cls, v): + """Support commands that were released before namespace.""" + # TODO: AmitL 2020.7.9. Remove this backward compatibility once + # clients reliably use fully namespaced command names + return BasicSessionCommand._pre_namespace_mapping().get(v, v) + + @staticmethod + @lru_cache(maxsize=1) + def _pre_namespace_mapping() -> typing.Dict[str, CommandDefinition]: + """Create a dictionary of pre-namespace name to CommandDefintion""" + # A tuple of CommandDefinition enums which need to be identified by + # localname and full namespaced name + pre_namespace_ns = CalibrationCheckCommand, CalibrationCommand + # Flatten + t = tuple(v for k in pre_namespace_ns for v in k) + return {k.localname: k for k in t} + class SessionCommand(BasicSessionCommand): """A session command response""" diff --git a/robot-server/tests/integration/sessions/test_default.tavern.yaml b/robot-server/tests/integration/sessions/test_default.tavern.yaml index 26f64ff20d8..0e8e8938452 100644 --- a/robot-server/tests/integration/sessions/test_default.tavern.yaml +++ b/robot-server/tests/integration/sessions/test_default.tavern.yaml @@ -72,7 +72,7 @@ stages: data: type: SessionCommand attributes: - command: homeAllMotors + command: robot.homeAllMotors data: {} response: status_code: 200 @@ -84,7 +84,7 @@ stages: data: type: SessionCommand attributes: - command: toggleLights + command: robot.toggleLights data: {} response: status_code: 200 @@ -96,7 +96,7 @@ stages: data: type: SessionCommand attributes: - command: loadLabware + command: calibration.loadLabware data: {} response: status_code: 400 diff --git a/robot-server/tests/integration/sessions/test_tip_length_calibration.tavern.yaml b/robot-server/tests/integration/sessions/test_tip_length_calibration.tavern.yaml index 1ee6403fbac..fc03e4b9a35 100644 --- a/robot-server/tests/integration/sessions/test_tip_length_calibration.tavern.yaml +++ b/robot-server/tests/integration/sessions/test_tip_length_calibration.tavern.yaml @@ -44,7 +44,7 @@ stages: data: type: SessionCommand attributes: - command: loadLabware + command: calibration.loadLabware data: {} response: status_code: 200 @@ -55,7 +55,7 @@ stages: type: SessionCommand attributes: status: executed - command: loadLabware + command: calibration.loadLabware created_at: &dt !re_match "\\d+-\\d+-\\d+T" started_at: *dt diff --git a/robot-server/tests/robot/calibration/tip_length/test_state_machine.py b/robot-server/tests/robot/calibration/tip_length/test_state_machine.py index 12ae20ad727..4ed01027fc5 100644 --- a/robot-server/tests/robot/calibration/tip_length/test_state_machine.py +++ b/robot-server/tests/robot/calibration/tip_length/test_state_machine.py @@ -1,30 +1,33 @@ import pytest from typing import List, Tuple -from robot_server.service.session.models import CommandName +from robot_server.service.session.models import CalibrationCommand, \ + TipLengthCalibrationCommand from robot_server.robot.calibration.tip_length.state_machine import \ TipCalibrationStateMachine valid_commands: List[Tuple[str, str, str]] = [ - (CommandName.load_labware, 'sessionStarted', 'labwareLoaded'), - (CommandName.move_to_reference_point, 'labwareLoaded', + (CalibrationCommand.load_labware, 'sessionStarted', 'labwareLoaded'), + (TipLengthCalibrationCommand.move_to_reference_point, 'labwareLoaded', 'measuringNozzleOffset'), - (CommandName.jog, 'measuringNozzleOffset', + (CalibrationCommand.jog, 'measuringNozzleOffset', 'measuringNozzleOffset'), - (CommandName.save_offset, 'measuringNozzleOffset', 'preparingPipette'), - (CommandName.jog, 'preparingPipette', 'preparingPipette'), - (CommandName.pick_up_tip, 'preparingPipette', 'preparingPipette'), - (CommandName.invalidate_tip, 'preparingPipette', 'preparingPipette'), - (CommandName.move_to_reference_point, 'preparingPipette', + (CalibrationCommand.save_offset, 'measuringNozzleOffset', + 'preparingPipette'), + (CalibrationCommand.jog, 'preparingPipette', 'preparingPipette'), + (CalibrationCommand.pick_up_tip, 'preparingPipette', 'preparingPipette'), + (CalibrationCommand.invalidate_tip, 'preparingPipette', 'preparingPipette'), + (TipLengthCalibrationCommand.move_to_reference_point, 'preparingPipette', 'measuringTipOffset'), - (CommandName.jog, 'measuringTipOffset', 'measuringTipOffset'), - (CommandName.save_offset, 'measuringTipOffset', 'calibrationComplete'), - (CommandName.exit, 'calibrationComplete', 'sessionExited'), - (CommandName.exit, 'sessionStarted', 'sessionExited'), - (CommandName.exit, 'labwareLoaded', 'sessionExited'), - (CommandName.exit, 'measuringNozzleOffset', 'sessionExited'), - (CommandName.exit, 'preparingPipette', 'sessionExited'), - (CommandName.exit, 'measuringTipOffset', 'sessionExited'), + (CalibrationCommand.jog, 'measuringTipOffset', 'measuringTipOffset'), + (CalibrationCommand.save_offset, 'measuringTipOffset', + 'calibrationComplete'), + (CalibrationCommand.exit, 'calibrationComplete', 'sessionExited'), + (CalibrationCommand.exit, 'sessionStarted', 'sessionExited'), + (CalibrationCommand.exit, 'labwareLoaded', 'sessionExited'), + (CalibrationCommand.exit, 'measuringNozzleOffset', 'sessionExited'), + (CalibrationCommand.exit, 'preparingPipette', 'sessionExited'), + (CalibrationCommand.exit, 'measuringTipOffset', 'sessionExited'), ] diff --git a/robot-server/tests/robot/calibration/tip_length/test_tip_length_calibration.py b/robot-server/tests/robot/calibration/tip_length/test_tip_length_calibration.py index d76f4ab6810..fc19316ef08 100644 --- a/robot-server/tests/robot/calibration/tip_length/test_tip_length_calibration.py +++ b/robot-server/tests/robot/calibration/tip_length/test_tip_length_calibration.py @@ -4,19 +4,20 @@ from opentrons.types import Mount, Point from opentrons.hardware_control import pipette -from robot_server.service.session.models import CommandName +from robot_server.service.session.models import TipLengthCalibrationCommand, \ + CalibrationCommand from robot_server.robot.calibration.tip_length.user_flow import \ TipCalibrationUserFlow stub_jog_data = {'vector': Point(1, 1, 1)} valid_commands: List[Tuple[str, str, Dict[Any, Any]]] = [ - (CommandName.move_to_reference_point, 'labwareLoaded', {}), - (CommandName.jog, 'measuringNozzleOffset', stub_jog_data), - (CommandName.pick_up_tip, 'preparingPipette', {}), - (CommandName.invalidate_tip, 'preparingPipette', {}), - (CommandName.save_offset, 'measuringTipOffset', {}), - (CommandName.exit, 'calibrationComplete', {}), + (TipLengthCalibrationCommand.move_to_reference_point, 'labwareLoaded', {}), + (CalibrationCommand.jog, 'measuringNozzleOffset', stub_jog_data), + (CalibrationCommand.pick_up_tip, 'preparingPipette', {}), + (CalibrationCommand.invalidate_tip, 'preparingPipette', {}), + (CalibrationCommand.save_offset, 'measuringTipOffset', {}), + (CalibrationCommand.exit, 'calibrationComplete', {}), ] @@ -43,9 +44,9 @@ async def async_mock(*args, **kwargs): hw_commands: List[Tuple[str, str, Dict[Any, Any], str]] = [ - (CommandName.jog, 'measuringNozzleOffset', stub_jog_data, 'move_rel'), - (CommandName.pick_up_tip, 'preparingPipette', {}, 'pick_up_tip'), - (CommandName.invalidate_tip, 'preparingPipette', {}, 'drop_tip'), + (CalibrationCommand.jog, 'measuringNozzleOffset', stub_jog_data, 'move_rel'), + (CalibrationCommand.pick_up_tip, 'preparingPipette', {}, 'pick_up_tip'), + (CalibrationCommand.invalidate_tip, 'preparingPipette', {}, 'drop_tip'), ] diff --git a/robot-server/tests/service/session/session_types/test_check_session.py b/robot-server/tests/service/session/session_types/test_check_session.py index 0c70a1ec663..cef7d546770 100644 --- a/robot-server/tests/service/session/session_types/test_check_session.py +++ b/robot-server/tests/service/session/session_types/test_check_session.py @@ -12,8 +12,8 @@ from robot_server.service.session.command_execution import create_command from robot_server.service.session.configuration import SessionConfiguration -from robot_server.service.session.models import (CommandName, EmptyModel, - JogPosition) +from robot_server.service.session.models import (EmptyModel, JogPosition, + CalibrationCommand) from robot_server.service.session.session_types import CheckSession, \ SessionMetaData, BaseSession @@ -170,12 +170,12 @@ async def test_session_command_execute(check_session_instance, mock_cal_session): await check_session_instance.command_executor.execute( create_command( - CommandName.jog, + CalibrationCommand.jog, JogPosition(vector=(1, 2, 3))) ) mock_cal_session.trigger_transition.assert_called_once_with( - trigger="jog", + trigger="calibration.jog", vector=(1.0, 2.0, 3.0) ) @@ -184,12 +184,12 @@ async def test_session_command_execute_no_body(check_session_instance, mock_cal_session): await check_session_instance.command_executor.execute( create_command( - CommandName.load_labware, + CalibrationCommand.load_labware, EmptyModel()) ) mock_cal_session.trigger_transition.assert_called_once_with( - trigger="loadLabware" + trigger="calibration.loadLabware" ) @@ -209,5 +209,6 @@ async def raiser(*args, **kwargs): with pytest.raises(SessionCommandException): await check_session_instance.command_executor.execute( - create_command(CommandName.jog, JogPosition(vector=(1, 2, 3))) + create_command(CalibrationCommand.jog, + JogPosition(vector=(1, 2, 3))) ) diff --git a/robot-server/tests/service/session/test_models.py b/robot-server/tests/service/session/test_models.py index 04fa70b8d92..1247e1a637f 100644 --- a/robot-server/tests/service/session/test_models.py +++ b/robot-server/tests/service/session/test_models.py @@ -3,14 +3,14 @@ def test_command_type_validation_jog(): - c = models.BasicSessionCommand(**{'command': models.CommandName.jog, + c = models.BasicSessionCommand(**{'command': models.CalibrationCommand.jog, 'data': {'vector': [1, 2, 3]}}) assert c.data == models.JogPosition(vector=(1, 2, 3,)) def test_command_type_validation_jog_fail(): with pytest.raises(ValueError): - models.BasicSessionCommand(**{'command': models.CommandName.jog, + models.BasicSessionCommand(**{'command': models.CalibrationCommand.jog, 'data': {}}) @@ -18,6 +18,6 @@ def test_command_type_empty(): """Test that we create command correctly for commands that have no added data.""" c = models.BasicSessionCommand( - **{'command': models.CommandName.prepare_pipette, + **{'command': models.CalibrationCommand.prepare_pipette, 'data': {}}) assert c.data == models.EmptyModel() diff --git a/robot-server/tests/service/session/test_router.py b/robot-server/tests/service/session/test_router.py index c126784ac68..f79d696274f 100644 --- a/robot-server/tests/service/session/test_router.py +++ b/robot-server/tests/service/session/test_router.py @@ -13,8 +13,8 @@ CommandResult, CompletedCommand, CommandContent, CommandMeta, CommandStatus from robot_server.service.session.errors import SessionCreationException, \ UnsupportedCommandException, CommandExecutionException -from robot_server.service.session.models import CommandName, EmptyModel, \ - SessionType, JogPosition +from robot_server.service.session.models import CalibrationCommand, \ + EmptyModel, SessionType, JogPosition from robot_server.service.session.session_types import NullSession, \ SessionMetaData @@ -291,13 +291,13 @@ def test_execute_command(api_client, patch_create_command): response = api_client.post( f"/sessions/{mock_session_meta.identifier}/commands/execute", - json=command("jog", + json=command("calibration.jog", JogPosition(vector=(1, 2, 3,)))) mock_command_executor.execute.assert_called_once_with( Command( content=CommandContent( - name=CommandName.jog, + name=CalibrationCommand.jog, data=JogPosition(vector=(1, 2, 3,)) ), meta=CommandMeta(identifier=command_id, @@ -308,7 +308,7 @@ def test_execute_command(api_client, assert response.json() == { 'data': { 'attributes': { - 'command': 'jog', + 'command': 'calibration.jog', 'data': {'vector': [1.0, 2.0, 3.0]}, 'status': 'executed', 'created_at': '2000-01-01T00:00:00', @@ -343,13 +343,13 @@ def test_execute_command_no_body(api_client, """Test that a command with empty body can be accepted""" response = api_client.post( f"/sessions/{mock_session_meta.identifier}/commands/execute", - json=command("loadLabware", None) + json=command("calibration.loadLabware", None) ) mock_command_executor.execute.assert_called_once_with( Command( content=CommandContent( - name=CommandName.load_labware, + name=CalibrationCommand.load_labware, data=EmptyModel()), meta=CommandMeta(command_id, command_created_at) ) @@ -358,7 +358,7 @@ def test_execute_command_no_body(api_client, assert response.json() == { 'data': { 'attributes': { - 'command': 'loadLabware', + 'command': 'calibration.loadLabware', 'data': {}, 'status': 'executed', 'created_at': '2000-01-01T00:00:00',