Skip to content

Commit

Permalink
fix(protocol-engine): Fix blowOutInPlace and aspirateInPlace not …
Browse files Browse the repository at this point in the history
…updating current volume (#14179)
  • Loading branch information
SyntaxColoring authored Dec 12, 2023
1 parent ec7bb74 commit a859387
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 31 deletions.
6 changes: 4 additions & 2 deletions api/src/opentrons/protocol_engine/state/pipettes.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
Command,
LoadPipetteResult,
AspirateResult,
AspirateInPlaceResult,
DispenseResult,
DispenseInPlaceResult,
MoveLabwareResult,
Expand All @@ -40,6 +41,7 @@
HomeResult,
RetractAxisResult,
BlowOutResult,
BlowOutInPlaceResult,
TouchTipResult,
thermocycler,
heater_shaker,
Expand Down Expand Up @@ -174,7 +176,7 @@ def _handle_command( # noqa: C901
self._state.attached_tip_by_id[pipette_id] = None
self._state.nozzle_configuration_by_id[pipette_id] = None

elif isinstance(command.result, AspirateResult):
elif isinstance(command.result, (AspirateResult, AspirateInPlaceResult)):
pipette_id = command.params.pipetteId
previous_volume = self._state.aspirated_volume_by_id[pipette_id] or 0
next_volume = previous_volume + command.result.volume
Expand Down Expand Up @@ -235,7 +237,7 @@ def _handle_command( # noqa: C901
default_aspirate=tip_configuration.default_aspirate_flowrate.values_by_api_level,
default_dispense=tip_configuration.default_dispense_flowrate.values_by_api_level,
)
elif isinstance(command.result, BlowOutResult):
elif isinstance(command.result, (BlowOutResult, BlowOutInPlaceResult)):
pipette_id = command.params.pipetteId
self._state.aspirated_volume_by_id[pipette_id] = None

Expand Down
44 changes: 44 additions & 0 deletions api/tests/opentrons/protocol_engine/state/command_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,29 @@ def create_aspirate_command(
)


def create_aspirate_in_place_command(
pipette_id: str,
volume: float,
flow_rate: float,
) -> cmd.AspirateInPlace:
"""Get a completed Aspirate command."""
params = cmd.AspirateInPlaceParams(
pipetteId=pipette_id,
volume=volume,
flowRate=flow_rate,
)
result = cmd.AspirateInPlaceResult(volume=volume)

return cmd.AspirateInPlace(
id="command-id",
key="command-key",
status=cmd.CommandStatus.SUCCEEDED,
createdAt=datetime.now(),
params=params,
result=result,
)


def create_dispense_command(
pipette_id: str,
volume: float,
Expand Down Expand Up @@ -467,6 +490,27 @@ def create_blow_out_command(
)


def create_blow_out_in_place_command(
pipette_id: str,
flow_rate: float,
) -> cmd.BlowOutInPlace:
"""Get a completed blowOutInPlace command."""
params = cmd.BlowOutInPlaceParams(
pipetteId=pipette_id,
flowRate=flow_rate,
)
result = cmd.BlowOutInPlaceResult()

return cmd.BlowOutInPlace(
id="command-id",
key="command-key",
status=cmd.CommandStatus.SUCCEEDED,
createdAt=datetime(year=2022, month=1, day=1),
params=params,
result=result,
)


def create_touch_tip_command(
pipette_id: str,
labware_id: str = "labware-id",
Expand Down
79 changes: 50 additions & 29 deletions api/tests/opentrons/protocol_engine/state/test_pipette_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from .command_fixtures import (
create_load_pipette_command,
create_aspirate_command,
create_aspirate_in_place_command,
create_dispense_command,
create_dispense_in_place_command,
create_pick_up_tip_command,
Expand All @@ -43,6 +44,7 @@
create_touch_tip_command,
create_move_to_well_command,
create_blow_out_command,
create_blow_out_in_place_command,
create_move_labware_command,
create_move_to_coordinates_command,
create_move_relative_command,
Expand Down Expand Up @@ -163,18 +165,24 @@ def test_handles_drop_tip_in_place(subject: PipetteStore) -> None:
assert subject.state.aspirated_volume_by_id["xyz"] is None


def test_pipette_volume_adds_aspirate(subject: PipetteStore) -> None:
@pytest.mark.parametrize(
"aspirate_command",
[
create_aspirate_command(pipette_id="pipette-id", volume=42, flow_rate=1.23),
create_aspirate_in_place_command(
pipette_id="pipette-id", volume=42, flow_rate=1.23
),
],
)
def test_aspirate_adds_volume(
subject: PipetteStore, aspirate_command: cmd.Command
) -> None:
"""It should add volume to pipette after an aspirate."""
load_command = create_load_pipette_command(
pipette_id="pipette-id",
pipette_name=PipetteNameType.P300_SINGLE,
mount=MountType.LEFT,
)
aspirate_command = create_aspirate_command(
pipette_id="pipette-id",
volume=42,
flow_rate=1.23,
)

subject.handle_action(
UpdateCommandAction(private_result=None, command=load_command)
Expand All @@ -192,28 +200,6 @@ def test_pipette_volume_adds_aspirate(subject: PipetteStore) -> None:
assert subject.state.aspirated_volume_by_id["pipette-id"] == 84


def test_handles_blow_out(subject: PipetteStore) -> None:
"""It should set volume to 0 and set current well."""
command = create_blow_out_command(
pipette_id="pipette-id",
labware_id="labware-id",
well_name="well-name",
flow_rate=1.23,
)

subject.handle_action(UpdateCommandAction(private_result=None, command=command))

result = subject.state

assert result.aspirated_volume_by_id["pipette-id"] is None

assert result.current_location == CurrentWell(
pipette_id="pipette-id",
labware_id="labware-id",
well_name="well-name",
)


@pytest.mark.parametrize(
"dispense_command",
[
Expand All @@ -225,7 +211,7 @@ def test_handles_blow_out(subject: PipetteStore) -> None:
),
],
)
def test_pipette_volume_subtracts_dispense(
def test_dispense_subtracts_volume(
subject: PipetteStore, dispense_command: cmd.Command
) -> None:
"""It should subtract volume from pipette after a dispense."""
Expand Down Expand Up @@ -265,6 +251,41 @@ def test_pipette_volume_subtracts_dispense(
assert subject.state.aspirated_volume_by_id["pipette-id"] == 0


@pytest.mark.parametrize(
"blow_out_command",
[
create_blow_out_command("pipette-id", 1.23),
create_blow_out_in_place_command("pipette-id", 1.23),
],
)
def test_blow_out_clears_volume(
subject: PipetteStore, blow_out_command: cmd.Command
) -> None:
"""It should wipe out the aspirated volume after a blowOut."""
load_command = create_load_pipette_command(
pipette_id="pipette-id",
pipette_name=PipetteNameType.P300_SINGLE,
mount=MountType.LEFT,
)
aspirate_command = create_aspirate_command(
pipette_id="pipette-id",
volume=42,
flow_rate=1.23,
)

subject.handle_action(
UpdateCommandAction(private_result=None, command=load_command)
)
subject.handle_action(
UpdateCommandAction(private_result=None, command=aspirate_command)
)
subject.handle_action(
UpdateCommandAction(private_result=None, command=blow_out_command)
)

assert subject.state.aspirated_volume_by_id["pipette-id"] is None


@pytest.mark.parametrize(
("command", "expected_location"),
(
Expand Down

0 comments on commit a859387

Please sign in to comment.