From d91df8ecba7d2c2284810d080b4e58753a9920d8 Mon Sep 17 00:00:00 2001 From: CaseyBatten Date: Fri, 1 Mar 2024 13:32:59 -0500 Subject: [PATCH] test fixes --- .../opentrons/protocol_engine/state/tips.py | 2 +- .../core/engine/test_labware_core.py | 19 ++- .../protocol_api_old/test_context.py | 2 +- .../protocol_api_old/test_labware.py | 29 ++-- .../protocol_engine/state/test_tip_state.py | 125 +++++++++++++++++- .../advanced_control/test_transfers.py | 2 +- shared-data/command/schemas/8.json | 2 +- 7 files changed, 155 insertions(+), 26 deletions(-) diff --git a/api/src/opentrons/protocol_engine/state/tips.py b/api/src/opentrons/protocol_engine/state/tips.py index 568f8617486..88728515db9 100644 --- a/api/src/opentrons/protocol_engine/state/tips.py +++ b/api/src/opentrons/protocol_engine/state/tips.py @@ -307,7 +307,7 @@ def _cluster_search_H12() -> Optional[str]: critical_row = len(columns[critical_column]) - num_nozzle_rows return None - if starting_tip_name is None: + if starting_tip_name is None and columns: if self.get_pipette_channels(pipette_id) == 1: # for a single channel pipette, always begin at A1 on the tiprack return _cluster_search_A1() diff --git a/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py b/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py index 9f68a2467c7..b4d76451d76 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py @@ -4,6 +4,7 @@ import pytest from decoy import Decoy +from opentrons_shared_data.pipette.dev_types import PipetteNameType from opentrons_shared_data.labware.dev_types import ( LabwareDefinition as LabwareDefDict, LabwareParameters as LabwareParamsDict, @@ -16,7 +17,8 @@ Metadata as LabwareDefinitionMetadata, ) -from opentrons.types import DeckSlotName, Point, Mount +from opentrons.types import DeckSlotName, Point, Mount, MountType +from opentrons.protocol_engine.types import LoadedPipette from opentrons.protocol_engine.clients import SyncClient as EngineClient from opentrons.protocol_engine.errors import LabwareNotOnDeckError @@ -244,6 +246,17 @@ def test_get_next_tip( decoy: Decoy, mock_engine_client: EngineClient, subject: LabwareCore ) -> None: """It should get the next available tip from the core.""" + mount = Mount.LEFT + decoy.when( + mock_engine_client.state.pipettes.get_by_mount(MountType.from_hw_mount(mount)) + ).then_return( + LoadedPipette.construct( + pipetteName=PipetteNameType.P300_MULTI, + id="pipette-id", + mount=MountType.from_hw_mount(mount), + ) + ) + decoy.when( mock_engine_client.state.tips.get_next_tip( pipette_id="pipette-id", @@ -256,9 +269,7 @@ def test_get_next_tip( starting_tip = WellCore( name="B1", labware_id="cool-labware", engine_client=mock_engine_client ) - result = subject.get_next_tip( - mount=Mount.LEFT, num_tips=8, starting_tip=starting_tip - ) + result = subject.get_next_tip(mount=mount, num_tips=8, starting_tip=starting_tip) assert result == "A2" diff --git a/api/tests/opentrons/protocol_api_old/test_context.py b/api/tests/opentrons/protocol_api_old/test_context.py index bb8b8f6c7ca..02e428ca67b 100644 --- a/api/tests/opentrons/protocol_api_old/test_context.py +++ b/api/tests/opentrons/protocol_api_old/test_context.py @@ -422,7 +422,7 @@ def test_pick_up_tip_no_location(ctx, get_labware_def, pipette_model, tiprack_ki if well.has_tip: tiprack1.use_tips(well) - assert tiprack1.next_tip() is None + assert tiprack1.next_tip(mount) is None assert tiprack2.wells()[0].has_tip instr.pick_up_tip() diff --git a/api/tests/opentrons/protocol_api_old/test_labware.py b/api/tests/opentrons/protocol_api_old/test_labware.py index 0edf6884176..c7a39e1e3bb 100644 --- a/api/tests/opentrons/protocol_api_old/test_labware.py +++ b/api/tests/opentrons/protocol_api_old/test_labware.py @@ -375,46 +375,47 @@ def test_select_next_tip( ) -> None: tiprack = opentrons_96_tiprack_300ul well_list = tiprack.wells() + mount = Mount.LEFT - next_one = tiprack.next_tip() + next_one = tiprack.next_tip(mount) assert next_one == well_list[0] - next_five = tiprack.next_tip(5) + next_five = tiprack.next_tip(mount, 5) assert next_five == well_list[0] - next_eight = tiprack.next_tip(8) + next_eight = tiprack.next_tip(mount, 8) assert next_eight == well_list[0] - next_nine = tiprack.next_tip(9) + next_nine = tiprack.next_tip(mount, 9) assert next_nine is None # A1 tip only has been used tiprack.use_tips(well_list[0]) - next_one = tiprack.next_tip() + next_one = tiprack.next_tip(mount) assert next_one == well_list[1] - next_five = tiprack.next_tip(5) + next_five = tiprack.next_tip(mount, 5) assert next_five == well_list[1] - next_eight = tiprack.next_tip(8) + next_eight = tiprack.next_tip(mount, 8) assert next_eight == well_list[8] # 2nd column has also been used tiprack.use_tips(well_list[8], num_channels=8) - next_one = tiprack.next_tip() + next_one = tiprack.next_tip(mount) assert next_one == well_list[1] - next_five = tiprack.next_tip(5) + next_five = tiprack.next_tip(mount, 5) assert next_five == well_list[1] - next_eight = tiprack.next_tip(8) + next_eight = tiprack.next_tip(mount, 8) assert next_eight == well_list[16] # Bottom 4 tips of 1rd column are also used tiprack.use_tips(well_list[4], num_channels=4) - next_one = tiprack.next_tip() + next_one = tiprack.next_tip(mount) assert next_one == well_list[1] - next_three = tiprack.next_tip(3) + next_three = tiprack.next_tip(mount, 3) assert next_three == well_list[1] - next_five = tiprack.next_tip(5) + next_five = tiprack.next_tip(mount, 5) assert next_five == well_list[16] - next_eight = tiprack.next_tip(8) + next_eight = tiprack.next_tip(mount, 8) assert next_eight == well_list[16] # you can reuse tips infinitely on api level 2.2 diff --git a/api/tests/opentrons/protocol_engine/state/test_tip_state.py b/api/tests/opentrons/protocol_engine/state/test_tip_state.py index b3098ca16f8..060f548cdb3 100644 --- a/api/tests/opentrons/protocol_engine/state/test_tip_state.py +++ b/api/tests/opentrons/protocol_engine/state/test_tip_state.py @@ -266,9 +266,6 @@ def test_get_next_tip_used_starting_tip( private_result=load_pipette_private_result, command=load_pipette_command ) ) - # subject.handle_action( - # actions.UpdateCommandAction(command=pick_up_tip_command, private_result=None) - # ) result = TipView(subject.state).get_next_tip( pipette_id="pipette-id", @@ -410,11 +407,41 @@ def test_get_next_tip_skips_picked_up_tip( def test_get_next_tip_with_starting_tip( subject: TipStore, load_labware_command: commands.LoadLabware, + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, ) -> None: """It should return the starting tip, and then the following tip after that.""" subject.handle_action( actions.UpdateCommandAction(private_result=None, command=load_labware_command) ) + load_pipette_command = commands.LoadPipette.construct( # type: ignore[call-arg] + result=commands.LoadPipetteResult(pipetteId="pipette-id") + ) + load_pipette_private_result = commands.LoadPipettePrivateResult( + pipette_id="pipette-id", + serial_number="pipette-serial", + config=LoadedStaticPipetteData( + channels=1, + max_volume=15, + min_volume=3, + model="gen a", + display_name="display name", + flow_rates=FlowRates( + default_aspirate={}, + default_dispense={}, + default_blow_out={}, + ), + tip_configuration_lookup_table={15: supported_tip_fixture}, + nominal_tip_overlap={}, + nozzle_offset_z=1.23, + home_position=4.56, + nozzle_map=get_default_nozzle_map(PipetteNameType.P300_SINGLE_GEN2), + ), + ) + subject.handle_action( + actions.UpdateCommandAction( + private_result=load_pipette_private_result, command=load_pipette_command + ) + ) result = TipView(subject.state).get_next_tip( pipette_id="pipette-id", @@ -453,11 +480,41 @@ def test_get_next_tip_with_starting_tip( def test_get_next_tip_with_starting_tip_8_channel( subject: TipStore, load_labware_command: commands.LoadLabware, + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, ) -> None: """It should return the starting tip, and then the following tip after that.""" subject.handle_action( actions.UpdateCommandAction(private_result=None, command=load_labware_command) ) + load_pipette_command = commands.LoadPipette.construct( # type: ignore[call-arg] + result=commands.LoadPipetteResult(pipetteId="pipette-id") + ) + load_pipette_private_result = commands.LoadPipettePrivateResult( + pipette_id="pipette-id", + serial_number="pipette-serial", + config=LoadedStaticPipetteData( + channels=8, + max_volume=15, + min_volume=3, + model="gen a", + display_name="display name", + flow_rates=FlowRates( + default_aspirate={}, + default_dispense={}, + default_blow_out={}, + ), + tip_configuration_lookup_table={15: supported_tip_fixture}, + nominal_tip_overlap={}, + nozzle_offset_z=1.23, + home_position=4.56, + nozzle_map=get_default_nozzle_map(PipetteNameType.P300_MULTI_GEN2), + ), + ) + subject.handle_action( + actions.UpdateCommandAction( + private_result=load_pipette_private_result, command=load_pipette_command + ) + ) result = TipView(subject.state).get_next_tip( pipette_id="pipette-id", @@ -496,11 +553,41 @@ def test_get_next_tip_with_starting_tip_8_channel( def test_get_next_tip_with_starting_tip_out_of_tips( subject: TipStore, load_labware_command: commands.LoadLabware, + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, ) -> None: """It should return the starting tip of H12 and then None after that.""" subject.handle_action( actions.UpdateCommandAction(private_result=None, command=load_labware_command) ) + load_pipette_command = commands.LoadPipette.construct( # type: ignore[call-arg] + result=commands.LoadPipetteResult(pipetteId="pipette-id") + ) + load_pipette_private_result = commands.LoadPipettePrivateResult( + pipette_id="pipette-id", + serial_number="pipette-serial", + config=LoadedStaticPipetteData( + channels=1, + max_volume=15, + min_volume=3, + model="gen a", + display_name="display name", + flow_rates=FlowRates( + default_aspirate={}, + default_dispense={}, + default_blow_out={}, + ), + tip_configuration_lookup_table={15: supported_tip_fixture}, + nominal_tip_overlap={}, + nozzle_offset_z=1.23, + home_position=4.56, + nozzle_map=get_default_nozzle_map(PipetteNameType.P300_SINGLE_GEN2), + ), + ) + subject.handle_action( + actions.UpdateCommandAction( + private_result=load_pipette_private_result, command=load_pipette_command + ) + ) result = TipView(subject.state).get_next_tip( pipette_id="pipette-id", @@ -539,11 +626,41 @@ def test_get_next_tip_with_starting_tip_out_of_tips( def test_get_next_tip_with_column_and_starting_tip( subject: TipStore, load_labware_command: commands.LoadLabware, + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, ) -> None: """It should return the first tip in a column, taking starting tip into account.""" subject.handle_action( actions.UpdateCommandAction(private_result=None, command=load_labware_command) ) + load_pipette_command = commands.LoadPipette.construct( # type: ignore[call-arg] + result=commands.LoadPipetteResult(pipetteId="pipette-id") + ) + load_pipette_private_result = commands.LoadPipettePrivateResult( + pipette_id="pipette-id", + serial_number="pipette-serial", + config=LoadedStaticPipetteData( + channels=8, + max_volume=15, + min_volume=3, + model="gen a", + display_name="display name", + flow_rates=FlowRates( + default_aspirate={}, + default_dispense={}, + default_blow_out={}, + ), + tip_configuration_lookup_table={15: supported_tip_fixture}, + nominal_tip_overlap={}, + nozzle_offset_z=1.23, + home_position=4.56, + nozzle_map=get_default_nozzle_map(PipetteNameType.P300_MULTI_GEN2), + ), + ) + subject.handle_action( + actions.UpdateCommandAction( + private_result=load_pipette_private_result, command=load_pipette_command + ) + ) result = TipView(subject.state).get_next_tip( pipette_id="pipette-id", @@ -572,7 +689,7 @@ def test_reset_tips( pipette_id="pipette-id", serial_number="pipette-serial", config=LoadedStaticPipetteData( - channels=8, + channels=1, max_volume=15, min_volume=3, model="gen a", diff --git a/api/tests/opentrons/protocols/advanced_control/test_transfers.py b/api/tests/opentrons/protocols/advanced_control/test_transfers.py index 21f6c30dae9..e270eaf880d 100644 --- a/api/tests/opentrons/protocols/advanced_control/test_transfers.py +++ b/api/tests/opentrons/protocols/advanced_control/test_transfers.py @@ -380,7 +380,7 @@ def test_new_tip_always(_instr_labware, monkeypatch): assert xfer_plan_list == exp1 for cmd in xfer_plan_list: getattr(i_ctx, cmd["method"])(*cmd["args"], **cmd["kwargs"]) - assert tiprack.next_tip() == tiprack.columns()[0][4] + assert tiprack.next_tip(Mount.LEFT) == tiprack.columns()[0][4] def test_transfer_w_touchtip_blowout(_instr_labware): diff --git a/shared-data/command/schemas/8.json b/shared-data/command/schemas/8.json index c2eb0a0e2a8..a17be9ee690 100644 --- a/shared-data/command/schemas/8.json +++ b/shared-data/command/schemas/8.json @@ -612,7 +612,7 @@ "frontRightNozzle": { "title": "Frontrightnozzle", "description": "The front right nozzle in your configuration.", - "pattern": "[A-Z][0-100]", + "pattern": "[A-Z]\\d{1,2}", "type": "string" } },