diff --git a/api/src/opentrons/protocol_api/core/engine/instrument.py b/api/src/opentrons/protocol_api/core/engine/instrument.py index abdd6872289..77bf92fc4d1 100644 --- a/api/src/opentrons/protocol_api/core/engine/instrument.py +++ b/api/src/opentrons/protocol_api/core/engine/instrument.py @@ -698,7 +698,7 @@ def get_mount(self) -> Mount: ).mount.to_hw_mount() def get_pipette_name(self) -> str: - """Get the pipette's load name as a string. + """Get the pipette's name as a string. Will match the load name of the actually loaded pipette, which may differ from the requested load name. @@ -712,19 +712,23 @@ def get_pipette_name(self) -> str: else pipette.pipetteName ) - def get_pipette_load_name(self) -> str: + def get_load_name(self) -> str: """Get the pipette's requested API load name. This is the load name that is specified in the `ProtocolContext.load_instrument()` method. This name might differ from the engine-specific pipette name. """ pipette = self._engine_client.state.pipettes.get(self._pipette_id) - assert pipette.pipetteName in PIPETTE_API_NAMES_MAP.values() - return [ - pip_api_name - for pip_api_name, pip_name in PIPETTE_API_NAMES_MAP.items() - if pip_name == pipette.pipetteName - ][0] + load_name = next( + ( + pip_api_name + for pip_api_name, pip_name in PIPETTE_API_NAMES_MAP.items() + if pip_name == pipette.pipetteName + ), + None, + ) + assert load_name, "Load name not found." + return load_name def get_model(self) -> str: return self._engine_client.state.pipettes.get_model_name(self._pipette_id) @@ -893,23 +897,28 @@ def configure_nozzle_layout( def load_liquid_class( self, - liquid_class: LiquidClass, - pipette_load_name: str, + name: str, + transfer_properties: TransferProperties, tiprack_uri: str, ) -> str: - """Load a liquid class into the engine and return its ID.""" - transfer_props = liquid_class.get_for( - pipette=pipette_load_name, tiprack=tiprack_uri - ) + """Load a liquid class into the engine and return its ID. + + Args: + name: Name of the liquid class + transfer_properties: Liquid class properties for a specific pipette & tiprack combination + tiprack_uri: URI of the tiprack whose transfer properties we will be using. + Returns: + Liquid class record's ID, as generated by the protocol engine. + """ liquid_class_record = LiquidClassRecord( - liquidClassName=liquid_class.name, - pipetteModel=pipette_load_name, # TODO: verify this is the correct 'model' to use + liquidClassName=name, + pipetteModel=self.get_load_name(), tiprack=tiprack_uri, - aspirate=transfer_props.aspirate.as_shared_data_model(), - singleDispense=transfer_props.dispense.as_shared_data_model(), - multiDispense=transfer_props.multi_dispense.as_shared_data_model() - if transfer_props.multi_dispense + aspirate=transfer_properties.aspirate.as_shared_data_model(), + singleDispense=transfer_properties.dispense.as_shared_data_model(), + multiDispense=transfer_properties.multi_dispense.as_shared_data_model() + if transfer_properties.multi_dispense else None, ) result = self._engine_client.execute_command_without_recovery( @@ -965,17 +974,17 @@ def transfer_liquid( # noqa: C901 "No tipracks found for pipette in order to perform transfer" ) tiprack_uri_for_transfer_props = tip_racks[0][1].get_uri() - + transfer_props = liquid_class.get_for( + pipette=self.get_load_name(), + tiprack=tiprack_uri_for_transfer_props, + ) # TODO: use the ID returned by load_liquid_class in command annotations self.load_liquid_class( - liquid_class=liquid_class, - pipette_load_name=self.get_pipette_load_name(), + name=liquid_class.name, + transfer_properties=transfer_props, tiprack_uri=tiprack_uri_for_transfer_props, ) - transfer_props = liquid_class.get_for( - pipette=self.get_pipette_load_name(), - tiprack=tiprack_uri_for_transfer_props, - ) + # TODO: add multi-channel pipette handling here source_dest_per_volume_step = tx_commons.expand_for_volume_constraints( volumes=[volume for _ in range(len(source))], diff --git a/api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py b/api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py index 34dad58d84b..fe19b400990 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py @@ -206,12 +206,12 @@ def test_get_pipette_load_name( decoy.when(mock_engine_client.state.pipettes.get("abc123")).then_return( LoadedPipette.construct(pipetteName=PipetteNameType.P300_SINGLE) # type: ignore[call-arg] ) - assert subject.get_pipette_load_name() == "p300_single" + assert subject.get_load_name() == "p300_single" decoy.when(mock_engine_client.state.pipettes.get("abc123")).then_return( LoadedPipette.construct(pipetteName=PipetteNameType.P1000_96) # type: ignore[call-arg] ) - assert subject.get_pipette_load_name() == "flex_96channel_1000" + assert subject.get_load_name() == "flex_96channel_1000" def test_get_mount( @@ -1596,6 +1596,9 @@ def test_load_liquid_class( test_liq_class = decoy.mock(cls=LiquidClass) test_transfer_props = decoy.mock(cls=TransferProperties) + decoy.when(mock_engine_client.state.pipettes.get("abc123")).then_return( + LoadedPipette.construct(pipetteName=PipetteNameType.P50_SINGLE_FLEX) # type: ignore[call-arg] + ) decoy.when( test_liq_class.get_for("flex_1channel_50", "opentrons_flex_96_tiprack_50ul") ).then_return(test_transfer_props) @@ -1627,8 +1630,8 @@ def test_load_liquid_class( ) ).then_return(cmd.LoadLiquidClassResult(liquidClassId="liquid-class-id")) result = subject.load_liquid_class( - liquid_class=test_liq_class, - pipette_load_name="flex_1channel_50", + name=test_liq_class.name, + transfer_properties=test_transfer_props, tiprack_uri="opentrons_flex_96_tiprack_50ul", ) assert result == "liquid-class-id"