Skip to content

Commit

Permalink
feat(api): return tip for liquid class based transfer functions (#17542)
Browse files Browse the repository at this point in the history
adds the ability to have tips be returned during a `transfer_liquid`, `consolidate_liquid` and `distribute_liquid`
  • Loading branch information
jbleon95 authored Feb 24, 2025
1 parent 6546cd4 commit ba74bab
Show file tree
Hide file tree
Showing 7 changed files with 335 additions and 8 deletions.
41 changes: 33 additions & 8 deletions api/src/opentrons/protocol_api/core/engine/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,7 @@ def transfer_liquid( # noqa: C901
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[Location, LabwareCore]],
trash_location: Union[Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""Execute transfer using liquid class properties.
Expand Down Expand Up @@ -1121,8 +1122,18 @@ def transfer_liquid( # noqa: C901
),
)

last_tip_picked_up_from: Optional[WellCore] = None

def _drop_tip() -> None:
if isinstance(trash_location, (TrashBin, WasteChute)):
if return_tip:
assert last_tip_picked_up_from is not None
self.drop_tip(
location=None,
well_core=last_tip_picked_up_from,
home_after=False,
alternate_drop_location=False,
)
elif isinstance(trash_location, (TrashBin, WasteChute)):
self.drop_tip_in_disposal_location(
disposal_location=trash_location,
home_after=False,
Expand All @@ -1136,7 +1147,7 @@ def _drop_tip() -> None:
alternate_drop_location=True,
)

def _pick_up_tip() -> None:
def _pick_up_tip() -> WellCore:
next_tip = self.get_next_tip(
tip_racks=[core for loc, core in tip_racks],
starting_well=None,
Expand All @@ -1161,9 +1172,10 @@ def _pick_up_tip() -> None:
presses=None,
increment=None,
)
return tip_well

if new_tip == TransferTipPolicyV2.ONCE:
_pick_up_tip()
last_tip_picked_up_from = _pick_up_tip()

prev_src: Optional[Tuple[Location, WellCore]] = None
post_disp_tip_contents = [
Expand All @@ -1190,7 +1202,7 @@ def _pick_up_tip() -> None:
):
if prev_src is not None:
_drop_tip()
_pick_up_tip()
last_tip_picked_up_from = _pick_up_tip()
post_disp_tip_contents = [
tx_comps_executor.LiquidAndAirGapPair(
liquid=0,
Expand Down Expand Up @@ -1230,6 +1242,7 @@ def distribute_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[Location, LabwareCore]],
trash_location: Union[Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
pass

Expand All @@ -1242,6 +1255,7 @@ def consolidate_liquid( # noqa: C901
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[Location, LabwareCore]],
trash_location: Union[Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
if not tip_racks:
raise RuntimeError(
Expand Down Expand Up @@ -1284,8 +1298,18 @@ def consolidate_liquid( # noqa: C901
max_volume=max_volume,
)

last_tip_picked_up_from: Optional[WellCore] = None

def _drop_tip() -> None:
if isinstance(trash_location, (TrashBin, WasteChute)):
if return_tip:
assert last_tip_picked_up_from is not None
self.drop_tip(
location=None,
well_core=last_tip_picked_up_from,
home_after=False,
alternate_drop_location=False,
)
elif isinstance(trash_location, (TrashBin, WasteChute)):
self.drop_tip_in_disposal_location(
disposal_location=trash_location,
home_after=False,
Expand All @@ -1299,7 +1323,7 @@ def _drop_tip() -> None:
alternate_drop_location=True,
)

def _pick_up_tip() -> None:
def _pick_up_tip() -> WellCore:
next_tip = self.get_next_tip(
tip_racks=[core for loc, core in tip_racks],
starting_well=None,
Expand All @@ -1324,9 +1348,10 @@ def _pick_up_tip() -> None:
presses=None,
increment=None,
)
return tip_well

if new_tip == TransferTipPolicyV2.ONCE:
_pick_up_tip()
last_tip_picked_up_from = _pick_up_tip()

prev_src: Optional[Tuple[Location, WellCore]] = None
tip_contents = [
Expand All @@ -1353,7 +1378,7 @@ def _pick_up_tip() -> None:
if new_tip == TransferTipPolicyV2.ALWAYS:
if prev_src is not None:
_drop_tip()
_pick_up_tip()
last_tip_picked_up_from = _pick_up_tip()
tip_contents = [
tx_comps_executor.LiquidAndAirGapPair(
liquid=0,
Expand Down
3 changes: 3 additions & 0 deletions api/src/opentrons/protocol_api/core/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ def transfer_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[types.Location, LabwareCoreType]],
trash_location: Union[types.Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""Transfer a liquid from source to dest according to liquid class properties."""
...
Expand All @@ -374,6 +375,7 @@ def distribute_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[types.Location, LabwareCoreType]],
trash_location: Union[types.Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""
Distribute a liquid from single source to multiple destinations
Expand All @@ -391,6 +393,7 @@ def consolidate_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[types.Location, LabwareCoreType]],
trash_location: Union[types.Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""
Consolidate liquid from multiple sources to a single destination
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ def transfer_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
trash_location: Union[types.Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""This will never be called because it was added in API 2.23"""
assert False, "transfer_liquid is not supported in legacy context"
Expand All @@ -638,6 +639,7 @@ def distribute_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
trash_location: Union[types.Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""This will never be called because it was added in API 2.23"""
assert False, "distribute_liquid is not supported in legacy context"
Expand All @@ -651,6 +653,7 @@ def consolidate_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
trash_location: Union[types.Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""This will never be called because it was added in API 2.23."""
assert False, "consolidate_liquid is not supported in legacy context"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,7 @@ def transfer_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
trash_location: Union[types.Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""This will never be called because it was added in API 2.23."""
assert False, "transfer_liquid is not supported in legacy context"
Expand All @@ -530,6 +531,7 @@ def distribute_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
trash_location: Union[types.Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""This will never be called because it was added in API 2.23."""
assert False, "distribute_liquid is not supported in legacy context"
Expand All @@ -543,6 +545,7 @@ def consolidate_liquid(
new_tip: TransferTipPolicyV2,
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
trash_location: Union[types.Location, TrashBin, WasteChute],
return_tip: bool,
) -> None:
"""This will never be called because it was added in API 2.23."""
assert False, "consolidate_liquid is not supported in legacy context"
Expand Down
6 changes: 6 additions & 0 deletions api/src/opentrons/protocol_api/instrument_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1528,6 +1528,7 @@ def transfer_liquid(
trash_location: Optional[
Union[types.Location, labware.Well, TrashBin, WasteChute]
] = None,
return_tip: bool = False,
) -> InstrumentContext:
"""Transfer liquid from source to dest using the specified liquid class properties.
Expand Down Expand Up @@ -1599,6 +1600,7 @@ def transfer_liquid(
for rack in tip_racks
],
trash_location=checked_trash_location,
return_tip=return_tip,
)
return self

Expand All @@ -1615,6 +1617,7 @@ def distribute_liquid(
trash_location: Optional[
Union[types.Location, labware.Well, TrashBin, WasteChute]
] = None,
return_tip: bool = False,
) -> InstrumentContext:
"""
Distribute liquid from a single source to multiple destinations
Expand Down Expand Up @@ -1678,6 +1681,7 @@ def distribute_liquid(
for rack in tip_racks
],
trash_location=checked_trash_location,
return_tip=return_tip,
)
return self

Expand All @@ -1694,6 +1698,7 @@ def consolidate_liquid(
trash_location: Optional[
Union[types.Location, labware.Well, TrashBin, WasteChute]
] = None,
return_tip: bool = False,
) -> InstrumentContext:
"""
Consolidate liquid from multiple sources to a single destination
Expand Down Expand Up @@ -1765,6 +1770,7 @@ def consolidate_liquid(
for rack in tip_racks
],
trash_location=checked_trash_location,
return_tip=return_tip,
)
return self

Expand Down
6 changes: 6 additions & 0 deletions api/tests/opentrons/protocol_api/test_instrument_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1948,6 +1948,7 @@ def test_transfer_liquid_delegates_to_engine_core(
dest=[mock_well],
new_tip="never",
trash_location=trash_location,
return_tip=True,
)
decoy.verify(
mock_instrument_core.transfer_liquid(
Expand All @@ -1958,6 +1959,7 @@ def test_transfer_liquid_delegates_to_engine_core(
new_tip=TransferTipPolicyV2.ONCE,
tip_racks=[(Location(Point(), labware=tip_racks[0]), tip_racks[0]._core)],
trash_location=trash_location.move(Point(1, 2, 3)),
return_tip=True,
)
)

Expand Down Expand Up @@ -2178,6 +2180,7 @@ def test_distribute_liquid_delegates_to_engine_core(
dest=[mock_well],
new_tip="never",
trash_location=trash_location,
return_tip=True,
)
decoy.verify(
mock_instrument_core.distribute_liquid(
Expand All @@ -2188,6 +2191,7 @@ def test_distribute_liquid_delegates_to_engine_core(
new_tip=TransferTipPolicyV2.ONCE,
tip_racks=[(Location(Point(), labware=tip_racks[0]), tip_racks[0]._core)],
trash_location=trash_location.move(Point(1, 2, 3)),
return_tip=True,
)
)

Expand Down Expand Up @@ -2433,6 +2437,7 @@ def test_consolidate_liquid_delegates_to_engine_core(
dest=mock_well,
new_tip="never",
trash_location=trash_location,
return_tip=True,
)
decoy.verify(
mock_instrument_core.consolidate_liquid(
Expand All @@ -2443,5 +2448,6 @@ def test_consolidate_liquid_delegates_to_engine_core(
new_tip=TransferTipPolicyV2.ONCE,
tip_racks=[(Location(Point(), labware=tip_racks[0]), tip_racks[0]._core)],
trash_location=trash_location.move(Point(1, 2, 3)),
return_tip=True,
)
)
Loading

0 comments on commit ba74bab

Please sign in to comment.