From 8803b47e10c824d70df21677006bb544d03f5b59 Mon Sep 17 00:00:00 2001 From: caila-marashaj Date: Wed, 15 Jan 2025 17:05:11 -0500 Subject: [PATCH] aspirate while tracking hw testing stuff --- .../protocol_api/core/engine/instrument.py | 105 ++++++++++++------ .../opentrons/protocol_api/core/instrument.py | 12 +- .../core/legacy/legacy_instrument_core.py | 12 +- .../legacy_instrument_core.py | 4 - .../protocol_api/instrument_context.py | 66 +++++------ api/src/opentrons/protocol_api/labware.py | 12 +- .../protocol_engine/commands/__init__.py | 28 +++++ .../protocol_engine/commands/aspirate.py | 1 - .../commands/aspirate_while_tracking.py | 35 +++--- .../commands/command_unions.py | 26 +++++ .../protocol_engine/commands/dispense.py | 2 - .../commands/dispense_while_tracking.py | 7 +- .../commands/movement_common.py | 4 +- .../commands/pipetting_common.py | 9 -- .../protocol_engine/execution/movement.py | 2 - .../protocol_engine/execution/pipetting.py | 28 ++++- .../protocol_engine/state/geometry.py | 27 +++-- .../opentrons/protocol_engine/state/motion.py | 2 - api/src/opentrons/types.py | 27 ++++- .../core/engine/test_instrument_core.py | 4 - .../protocol_api/test_instrument_context.py | 15 +-- api/tests/opentrons/protocol_api/test_well.py | 1 - .../protocol_engine/commands/test_aspirate.py | 9 -- .../protocol_engine/commands/test_blow_out.py | 3 - .../protocol_engine/commands/test_dispense.py | 3 - .../protocol_engine/commands/test_drop_tip.py | 4 - .../commands/test_liquid_probe.py | 3 - .../commands/test_move_to_well.py | 2 - .../commands/test_pick_up_tip.py | 3 - .../commands/test_touch_tip.py | 2 - .../execution/test_movement_handler.py | 2 - .../state/test_geometry_view.py | 1 - .../protocol_engine/state/test_motion_view.py | 1 - api/tests/opentrons/test_types.py | 9 +- 34 files changed, 255 insertions(+), 216 deletions(-) diff --git a/api/src/opentrons/protocol_api/core/engine/instrument.py b/api/src/opentrons/protocol_api/core/engine/instrument.py index 89996dc75c1..407334bfc45 100644 --- a/api/src/opentrons/protocol_api/core/engine/instrument.py +++ b/api/src/opentrons/protocol_api/core/engine/instrument.py @@ -3,7 +3,13 @@ from __future__ import annotations from typing import Optional, TYPE_CHECKING, cast, Union, List, Tuple -from opentrons.types import Location, Mount, NozzleConfigurationType, NozzleMapInterface +from opentrons.types import ( + Location, + Mount, + NozzleConfigurationType, + NozzleMapInterface, + MeniscusTracking, +) from opentrons.hardware_control import SyncHardwareAPI from opentrons.hardware_control.dev_types import PipetteDict from opentrons.protocols.api_support.util import FlowRates, find_value_for_api_version @@ -134,8 +140,7 @@ def aspirate( rate: float, flow_rate: float, in_place: bool, - is_meniscus: Optional[bool] = None, - is_tracking: Optional[bool] = False, + meniscus_tracking: Optional[MeniscusTracking] = None, ) -> None: """Aspirate a given volume of liquid from the specified location. Args: @@ -145,8 +150,7 @@ def aspirate( rate: Not used in this core. flow_rate: The flow rate in µL/s to aspirate at. in_place: whether this is a in-place command. - is_meniscus: whether the aspirate location specified is relative to a liquid meniscus. - is_tracking: whether the z motor is to move with the liquid meniscus. + meniscus_tracking: Optional data about where to aspirate from. """ if well_core is None: if not in_place: @@ -176,10 +180,15 @@ def aspirate( labware_id=labware_id, well_name=well_name, absolute_point=location.point, - is_meniscus=is_meniscus, + meniscus_tracking=meniscus_tracking, ) - if well_location.origin == WellOrigin.MENISCUS: - well_location.volumeOffset = "operationVolume" + dynamic_liquid_tracking = False + # caila bookmark + if meniscus_tracking: + if meniscus_tracking.target == "end": + well_location.volumeOffset = "operationVolume" + elif meniscus_tracking.target == "dynamic_meniscus": + dynamic_liquid_tracking = True pipette_movement_conflict.check_safe_for_pipette_movement( engine_state=self._engine_client.state, pipette_id=self._pipette_id, @@ -187,17 +196,28 @@ def aspirate( well_name=well_name, well_location=well_location, ) - self._engine_client.execute_command( - cmd.AspirateParams( - pipetteId=self._pipette_id, - labwareId=labware_id, - wellName=well_name, - wellLocation=well_location, - volume=volume, - flowRate=flow_rate, - is_tracking=is_tracking if is_tracking else False, + if dynamic_liquid_tracking: + self._engine_client.execute_command( + cmd.AspirateWhileTrackingParams( + pipetteId=self._pipette_id, + labwareId=labware_id, + wellName=well_name, + wellLocation=well_location, + volume=volume, + flowRate=flow_rate, + ) + ) + else: + self._engine_client.execute_command( + cmd.AspirateParams( + pipetteId=self._pipette_id, + labwareId=labware_id, + wellName=well_name, + wellLocation=well_location, + volume=volume, + flowRate=flow_rate, + ) ) - ) self._protocol_core.set_last_location(location=location, mount=self.get_mount()) @@ -210,8 +230,7 @@ def dispense( flow_rate: float, in_place: bool, push_out: Optional[float], - is_meniscus: Optional[bool] = None, - is_tracking: Optional[bool] = False, + meniscus_tracking: Optional[MeniscusTracking] = None, ) -> None: """Dispense a given volume of liquid into the specified location. Args: @@ -222,9 +241,9 @@ def dispense( flow_rate: The flow rate in µL/s to dispense at. in_place: whether this is a in-place command. push_out: The amount to push the plunger below bottom position. - is_meniscus: whether the aspirate location specified is relative to a liquid meniscus. - is_tracking: whether the z motor is to move with the liquid meniscus. + meniscus_tracking: Optional data about where to dispense from. """ + # raise ValueError(f"well location = {location}") if self._protocol_core.api_version < _DISPENSE_VOLUME_VALIDATION_ADDED_IN: # In older API versions, when you try to dispense more than you can, # it gets clamped. @@ -273,8 +292,14 @@ def dispense( labware_id=labware_id, well_name=well_name, absolute_point=location.point, - is_meniscus=is_meniscus, + meniscus_tracking=meniscus_tracking, ) + dynamic_liquid_tracking = False + if meniscus_tracking: + if meniscus_tracking.target == "end": + well_location.volumeOffset = "operationVolume" + elif meniscus_tracking.target == "dynamic_meniscus": + dynamic_liquid_tracking = True pipette_movement_conflict.check_safe_for_pipette_movement( engine_state=self._engine_client.state, pipette_id=self._pipette_id, @@ -282,18 +307,30 @@ def dispense( well_name=well_name, well_location=well_location, ) - self._engine_client.execute_command( - cmd.DispenseParams( - pipetteId=self._pipette_id, - labwareId=labware_id, - wellName=well_name, - wellLocation=well_location, - volume=volume, - flowRate=flow_rate, - pushOut=push_out, - is_tracking=is_tracking if is_tracking else False, + if dynamic_liquid_tracking: + self._engine_client.execute_command( + cmd.DispenseWhileTrackingParams( + pipetteId=self._pipette_id, + labwareId=labware_id, + wellName=well_name, + wellLocation=well_location, + volume=volume, + flowRate=flow_rate, + pushOut=push_out, + ) + ) + else: + self._engine_client.execute_command( + cmd.DispenseParams( + pipetteId=self._pipette_id, + labwareId=labware_id, + wellName=well_name, + wellLocation=well_location, + volume=volume, + flowRate=flow_rate, + pushOut=push_out, + ) ) - ) if isinstance(location, (TrashBin, WasteChute)): self._protocol_core.set_last_location(location=None, mount=self.get_mount()) diff --git a/api/src/opentrons/protocol_api/core/instrument.py b/api/src/opentrons/protocol_api/core/instrument.py index 941e3aa583d..f76ad2eadc8 100644 --- a/api/src/opentrons/protocol_api/core/instrument.py +++ b/api/src/opentrons/protocol_api/core/instrument.py @@ -41,8 +41,7 @@ def aspirate( rate: float, flow_rate: float, in_place: bool, - is_meniscus: Optional[bool] = None, - is_tracking: Optional[bool] = False, + meniscus_tracking: Optional[types.MeniscusTracking] = None, ) -> None: """Aspirate a given volume of liquid from the specified location. Args: @@ -52,8 +51,7 @@ def aspirate( rate: The rate for how quickly to aspirate. flow_rate: The flow rate in µL/s to aspirate at. in_place: Whether this is in-place. - is_meniscus: whether the aspirate location specified is relative to a liquid meniscus. - is_tracking: whether the z motor is to move with the liquid meniscus. + meniscus_tracking: Optional data about where to aspirate from. """ ... @@ -67,8 +65,7 @@ def dispense( flow_rate: float, in_place: bool, push_out: Optional[float], - is_meniscus: Optional[bool] = None, - is_tracking: Optional[bool] = None, + meniscus_tracking: Optional[types.MeniscusTracking] = None, ) -> None: """Dispense a given volume of liquid into the specified location. Args: @@ -79,8 +76,7 @@ def dispense( flow_rate: The flow rate in µL/s to dispense at. in_place: Whether this is in-place. push_out: The amount to push the plunger below bottom position. - is_meniscus: whether the aspirate location specified is relative to a liquid meniscus. - is_tracking: whether the z motor is to move with the liquid meniscus. + meniscus_tracking: Optional data about where to dispense from. """ ... diff --git a/api/src/opentrons/protocol_api/core/legacy/legacy_instrument_core.py b/api/src/opentrons/protocol_api/core/legacy/legacy_instrument_core.py index 44e88309385..abf0e352e10 100644 --- a/api/src/opentrons/protocol_api/core/legacy/legacy_instrument_core.py +++ b/api/src/opentrons/protocol_api/core/legacy/legacy_instrument_core.py @@ -84,8 +84,7 @@ def aspirate( rate: float, flow_rate: float, in_place: bool, - is_meniscus: Optional[bool] = None, - is_tracking: Optional[bool] = None, + meniscus_tracking: Optional[types.MeniscusTracking] = None, ) -> None: """Aspirate a given volume of liquid from the specified location. Args: @@ -95,8 +94,7 @@ def aspirate( rate: The rate in µL/s to aspirate at. flow_rate: Not used in this core. in_place: Whether we should move_to location. - is_meniscus: whether the aspirate location specified is relative to a liquid meniscus. - is_tracking: whether the z motor is to move with the liquid meniscus. + meniscus_tracking: Optional data about where to aspirate from. """ if self.get_current_volume() == 0: # Make sure we're at the top of the labware and clear of any @@ -130,8 +128,7 @@ def dispense( flow_rate: float, in_place: bool, push_out: Optional[float], - is_meniscus: Optional[bool] = None, - is_tracking: Optional[bool] = None, + meniscus_tracking: Optional[types.MeniscusTracking] = None, ) -> None: """Dispense a given volume of liquid into the specified location. Args: @@ -142,8 +139,7 @@ def dispense( flow_rate: Not used in this core. in_place: Whether we should move_to location. push_out: The amount to push the plunger below bottom position. - is_meniscus: whether the aspirate location specified is relative to a liquid meniscus. - is_tracking: whether the z motor is to move with the liquid meniscus. + meniscus_tracking: Optional data about where to dispense from. """ if isinstance(location, (TrashBin, WasteChute)): raise APIVersionError( diff --git a/api/src/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py b/api/src/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py index 70bba0f5dd2..3e6d02c2ab9 100644 --- a/api/src/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +++ b/api/src/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py @@ -95,8 +95,6 @@ def aspirate( rate: float, flow_rate: float, in_place: bool, - is_meniscus: Optional[bool] = None, - is_tracking: Optional[bool] = None, ) -> None: if self.get_current_volume() == 0: # Make sure we're at the top of the labware and clear of any @@ -138,8 +136,6 @@ def dispense( flow_rate: float, in_place: bool, push_out: Optional[float], - is_meniscus: Optional[bool] = None, - is_tracking: Optional[bool] = None, ) -> None: if isinstance(location, (TrashBin, WasteChute)): raise APIVersionError( diff --git a/api/src/opentrons/protocol_api/instrument_context.py b/api/src/opentrons/protocol_api/instrument_context.py index 453ed1c8edc..4cca7d7655e 100644 --- a/api/src/opentrons/protocol_api/instrument_context.py +++ b/api/src/opentrons/protocol_api/instrument_context.py @@ -1,7 +1,7 @@ from __future__ import annotations import logging from contextlib import ExitStack -from typing import Any, List, Optional, Sequence, Union, cast, Dict, Tuple +from typing import Any, List, Optional, Sequence, Union, cast, Dict, Tuple, Literal from opentrons_shared_data.errors.exceptions import ( CommandPreconditionViolated, CommandParameterLimitViolated, @@ -172,6 +172,7 @@ def aspirate( volume: Optional[float] = None, location: Optional[Union[types.Location, labware.Well]] = None, rate: float = 1.0, + # meniscus_tracking: Optional[Literal["start", "end", "dynamic_meniscus"]] = None ) -> InstrumentContext: """ Draw liquid into a pipette tip. @@ -207,6 +208,11 @@ def aspirate( as ``rate`` multiplied by :py:attr:`flow_rate.aspirate `. If not specified, defaults to 1.0. See :ref:`new-plunger-flow-rates`. + :param meniscus_tracking: Whether to aspirate relative to the liquid meniscus + "start" - aspirate from the current liquid meniscus at the start of the operation + "end" - aspirate from the projected liquid meniscus at the end of the operation + "dynamic_meniscus" - move the pipette down while aspirating to maintain a given depth relative + to the liquid meniscus. :type rate: float :returns: This instance. @@ -226,7 +232,6 @@ def aspirate( move_to_location: types.Location well: Optional[labware.Well] = None - is_meniscus: Optional[bool] = None last_location = self._get_last_location_by_api_version() try: target = validation.validate_location( @@ -244,7 +249,7 @@ def aspirate( raise ValueError( "Trash Bin and Waste Chute are not acceptable location parameters for Aspirate commands." ) - move_to_location, well, is_meniscus = self._handle_aspirate_target( + move_to_location, well, meniscus_tracking = self._handle_aspirate_target( target=target ) if self.api_version >= APIVersion(2, 11): @@ -287,7 +292,7 @@ def aspirate( rate=rate, flow_rate=flow_rate, in_place=target.in_place, - is_meniscus=is_meniscus, + meniscus_tracking=meniscus_tracking, ) return self @@ -352,7 +357,6 @@ def aspirate_while_tracking( move_to_location: types.Location well: Optional[labware.Well] = None - is_meniscus: Optional[bool] = None last_location = self._get_last_location_by_api_version() try: target = validation.validate_location( @@ -370,7 +374,7 @@ def aspirate_while_tracking( raise ValueError( "Trash Bin and Waste Chute are not acceptable location parameters for Aspirate commands." ) - move_to_location, well, is_meniscus = self._handle_aspirate_target( + move_to_location, well, meniscus_tracking = self._handle_aspirate_target( target=target ) if self.api_version >= APIVersion(2, 11): @@ -413,8 +417,7 @@ def aspirate_while_tracking( rate=rate, flow_rate=flow_rate, in_place=target.in_place, - is_meniscus=is_meniscus, - is_tracking=True, + meniscus_tracking=meniscus_tracking, ) return self @@ -480,7 +483,6 @@ def dispense_while_tracking( move_to_location: types.Location well: Optional[labware.Well] = None - is_meniscus: Optional[bool] = None last_location = self._get_last_location_by_api_version() try: target = validation.validate_location( @@ -498,7 +500,7 @@ def dispense_while_tracking( raise ValueError( "Trash Bin and Waste Chute are not acceptable location parameters for dispense commands." ) - move_to_location, well, is_meniscus = self._handle_dispense_target( + move_to_location, well, meniscus_tracking = self._handle_dispense_target( target=target ) if self.api_version >= APIVersion(2, 11): @@ -542,8 +544,7 @@ def dispense_while_tracking( flow_rate=flow_rate, in_place=target.in_place, push_out=push_out, - is_meniscus=is_meniscus, - is_tracking=True, + # meniscus_tracking=meniscus_tracking, ) return self @@ -645,8 +646,7 @@ def dispense( # noqa: C901 volume, location if location else "current position", rate ) ) - well: Optional[labware.Well] = None - is_meniscus: Optional[bool] = None + # well: Optional[labware.Well] = None last_location = self._get_last_location_by_api_version() try: @@ -661,19 +661,9 @@ def dispense( # noqa: C901 "knows where it is." ) from e - if isinstance(target, validation.WellTarget): - well = target.well - if target.location: - move_to_location = target.location - is_meniscus = target.location.is_meniscus - elif well.parent._core.is_fixed_trash(): - move_to_location = target.well.top() - else: - move_to_location = target.well.bottom( - z=self._well_bottom_clearances.dispense - ) - if isinstance(target, validation.PointTarget): - move_to_location = target.location + move_to_location, well, meniscus_tracking = self._handle_dispense_target( + target=target + ) if self.api_version >= APIVersion(2, 11) and not isinstance( target, (TrashBin, WasteChute) @@ -710,6 +700,7 @@ def dispense( # noqa: C901 flow_rate=flow_rate, in_place=False, push_out=push_out, + meniscus_tracking=None, ) return self @@ -731,7 +722,7 @@ def dispense( # noqa: C901 flow_rate=flow_rate, in_place=target.in_place, push_out=push_out, - is_meniscus=is_meniscus, + meniscus_tracking=meniscus_tracking, ) return self @@ -2588,15 +2579,15 @@ def _raise_if_pressure_not_supported_by_pipette(self) -> None: def _handle_aspirate_target( self, target: validation.ValidTarget - ) -> tuple[types.Location, Optional[labware.Well], Optional[bool]]: + ) -> tuple[types.Location, Optional[labware.Well], Optional[types.MeniscusTracking]]: move_to_location: types.Location well: Optional[labware.Well] = None - is_meniscus: Optional[bool] = None + meniscus_tracking: Optional[types.MeniscusTracking] = None if isinstance(target, validation.WellTarget): well = target.well if target.location: move_to_location = target.location - is_meniscus = target.location.is_meniscus + meniscus_tracking = target.location.meniscus_tracking else: move_to_location = target.well.bottom( @@ -2604,27 +2595,28 @@ def _handle_aspirate_target( ) if isinstance(target, validation.PointTarget): move_to_location = target.location - return (move_to_location, well, is_meniscus) + return move_to_location, well, meniscus_tracking def _handle_dispense_target( self, target: validation.ValidTarget - ) -> tuple[types.Location, Optional[labware.Well], Optional[bool]]: + ) -> tuple[types.Location, Optional[labware.Well], Optional[types.MeniscusTracking]]: move_to_location: types.Location well: Optional[labware.Well] = None - is_meniscus: Optional[bool] = None + meniscus_tracking: Optional[types.MeniscusTracking] = None if isinstance(target, validation.WellTarget): well = target.well if target.location: move_to_location = target.location - is_meniscus = target.location.is_meniscus - + meniscus_tracking = target.location.meniscus_tracking + elif well.parent._core.is_fixed_trash(): + move_to_location = target.well.top() else: move_to_location = target.well.bottom( z=self._well_bottom_clearances.dispense ) if isinstance(target, validation.PointTarget): move_to_location = target.location - return move_to_location, well, is_meniscus + return move_to_location, well, meniscus_tracking class AutoProbeDisable: diff --git a/api/src/opentrons/protocol_api/labware.py b/api/src/opentrons/protocol_api/labware.py index bb8a094e4c2..778cf8cf106 100644 --- a/api/src/opentrons/protocol_api/labware.py +++ b/api/src/opentrons/protocol_api/labware.py @@ -24,11 +24,12 @@ cast, Sequence, Mapping, + Literal, ) from opentrons_shared_data.labware.types import LabwareDefinition, LabwareParameters -from opentrons.types import Location, Point, NozzleMapInterface +from opentrons.types import Location, Point, NozzleMapInterface, MeniscusTracking from opentrons.protocols.api_support.types import APIVersion from opentrons.protocols.api_support.util import ( requires_version, @@ -233,16 +234,21 @@ def center(self) -> Location: return Location(self._core.get_center(), self) @requires_version(2, 21) - def meniscus(self, z: float = 0.0) -> Location: + def meniscus( + self, target: Literal["beginning", "end", "dynamic_meniscus"], z: float = 0.0 + ) -> Location: """ :param z: An offset on the z-axis, in mm. Positive offsets are higher and negative offsets are lower. + :param target: The relative position inside the well to target with respect to a liquid handling operation. :return: A :py:class:`~opentrons.types.Location` that indicates location is meniscus and that holds the ``z`` offset in its point.z field. :meta private: """ return Location( - point=Point(x=0, y=0, z=z), labware=self, _ot_internal_is_meniscus=True + point=Point(x=0, y=0, z=z), + labware=self, + _meniscus_tracking=MeniscusTracking(target=target), ) @requires_version(2, 8) diff --git a/api/src/opentrons/protocol_engine/commands/__init__.py b/api/src/opentrons/protocol_engine/commands/__init__.py index 4ad91012b11..acb7d74b69f 100644 --- a/api/src/opentrons/protocol_engine/commands/__init__.py +++ b/api/src/opentrons/protocol_engine/commands/__init__.py @@ -60,6 +60,14 @@ AspirateCommandType, ) +from .aspirate_while_tracking import ( + AspirateWhileTracking, + AspirateWhileTrackingParams, + AspirateWhileTrackingCreate, + AspirateWhileTrackingResult, + AspirateWhileTrackingCommandType, +) + from .aspirate_in_place import ( AspirateInPlace, AspirateInPlaceParams, @@ -92,6 +100,14 @@ DispenseCommandType, ) +from .dispense_while_tracking import ( + DispenseWhileTracking, + DispenseWhileTrackingParams, + DispenseWhileTrackingCreate, + DispenseWhileTrackingResult, + DispenseWhileTrackingCommandType, +) + from .dispense_in_place import ( DispenseInPlace, DispenseInPlaceParams, @@ -413,6 +429,12 @@ "AspirateParams", "AspirateResult", "AspirateCommandType", + # aspirate while tracking command models + "AspirateWhileTracking", + "AspirateWhileTrackingCreate", + "AspirateWhileTrackingParams", + "AspirateWhileTrackingResult", + "AspirateWhileTrackingCommandType", # aspirate in place command models "AspirateInPlace", "AspirateInPlaceCreate", @@ -437,6 +459,12 @@ "DispenseParams", "DispenseResult", "DispenseCommandType", + # dispense while tracking command models + "DispenseWhileTracking", + "DispenseWhileTrackingCreate", + "DispenseWhileTrackingParams", + "DispenseWhileTrackingResult", + "DispenseWhileTrackingCommandType", # dispense in place command models "DispenseInPlace", "DispenseInPlaceCreate", diff --git a/api/src/opentrons/protocol_engine/commands/aspirate.py b/api/src/opentrons/protocol_engine/commands/aspirate.py index 5b47b78efbb..b07cd522f93 100644 --- a/api/src/opentrons/protocol_engine/commands/aspirate.py +++ b/api/src/opentrons/protocol_engine/commands/aspirate.py @@ -161,7 +161,6 @@ async def execute(self, params: AspirateParams) -> _ExecuteReturn: well_location=well_location, current_well=current_well, operation_volume=-params.volume, - is_tracking=False, ) state_update.append(move_result.state_update) if isinstance(move_result, DefinedErrorData): diff --git a/api/src/opentrons/protocol_engine/commands/aspirate_while_tracking.py b/api/src/opentrons/protocol_engine/commands/aspirate_while_tracking.py index 2d6f6a7e567..5ea29af8f6e 100644 --- a/api/src/opentrons/protocol_engine/commands/aspirate_while_tracking.py +++ b/api/src/opentrons/protocol_engine/commands/aspirate_while_tracking.py @@ -43,7 +43,7 @@ from ..notes import CommandNoteAdder -AspirateCommandType = Literal["aspirate"] +AspirateWhileTrackingCommandType = Literal["aspirateWhileTracking"] class AspirateWhileTrackingParams( @@ -57,22 +57,22 @@ class AspirateWhileTrackingParams( pass -class AspirateResult(BaseLiquidHandlingResult, DestinationPositionResult): +class AspirateWhileTrackingResult(BaseLiquidHandlingResult, DestinationPositionResult): """Result data from execution of an Aspirate command.""" pass _ExecuteReturn = Union[ - SuccessData[AspirateResult], + SuccessData[AspirateWhileTrackingResult], DefinedErrorData[OverpressureError] | DefinedErrorData[StallOrCollisionError], ] -class AspirateImplementation( +class AspirateWhileTrackingImplementation( AbstractCommandImpl[AspirateWhileTrackingParams, _ExecuteReturn] ): - """Aspirate command implementation.""" + """AspirateWhileTracking command implementation.""" def __init__( self, @@ -153,7 +153,6 @@ async def execute(self, params: AspirateWhileTrackingParams) -> _ExecuteReturn: labware_id=labware_id, well_name=well_name, ) - move_result = await move_to_well( movement=self._movement, model_utils=self._model_utils, @@ -162,8 +161,6 @@ async def execute(self, params: AspirateWhileTrackingParams) -> _ExecuteReturn: well_name=well_name, well_location=well_location, current_well=current_well, - operation_volume=-params.volume, - is_tracking=True, ) state_update.append(move_result.state_update) if isinstance(move_result, DefinedErrorData): @@ -217,7 +214,7 @@ async def execute(self, params: AspirateWhileTrackingParams) -> _ExecuteReturn: ) return SuccessData( - public=AspirateResult( + public=AspirateWhileTrackingResult( volume=aspirate_result.public.volume, position=move_result.public.position, ), @@ -225,26 +222,28 @@ async def execute(self, params: AspirateWhileTrackingParams) -> _ExecuteReturn: ) -class Aspirate( +class AspirateWhileTracking( BaseCommand[ AspirateWhileTrackingParams, - AspirateResult, + AspirateWhileTrackingResult, OverpressureError | StallOrCollisionError, ] ): - """Aspirate command model.""" + """AspirateWhileTracking command model.""" - commandType: AspirateCommandType = "aspirate" + commandType: AspirateWhileTrackingCommandType = "aspirateWhileTracking" params: AspirateWhileTrackingParams - result: Optional[AspirateResult] = None + result: Optional[AspirateWhileTrackingResult] = None - _ImplementationCls: Type[AspirateImplementation] = AspirateImplementation + _ImplementationCls: Type[ + AspirateWhileTrackingImplementation + ] = AspirateWhileTrackingImplementation -class AspirateCreate(BaseCommandCreate[AspirateWhileTrackingParams]): +class AspirateWhileTrackingCreate(BaseCommandCreate[AspirateWhileTrackingParams]): """Create aspirate command request model.""" - commandType: AspirateCommandType = "aspirate" + commandType: AspirateWhileTrackingCommandType = "aspirateWhileTracking" params: AspirateWhileTrackingParams - _CommandCls: Type[Aspirate] = Aspirate + _CommandCls: Type[AspirateWhileTracking] = AspirateWhileTracking diff --git a/api/src/opentrons/protocol_engine/commands/command_unions.py b/api/src/opentrons/protocol_engine/commands/command_unions.py index b04b381ae6b..72151002811 100644 --- a/api/src/opentrons/protocol_engine/commands/command_unions.py +++ b/api/src/opentrons/protocol_engine/commands/command_unions.py @@ -57,6 +57,14 @@ AspirateInPlaceCommandType, ) +from .aspirate_while_tracking import ( + AspirateWhileTracking, + AspirateWhileTrackingParams, + AspirateWhileTrackingCreate, + AspirateWhileTrackingResult, + AspirateWhileTrackingCommandType +) + from .comment import ( Comment, CommentParams, @@ -81,6 +89,14 @@ DispenseCommandType, ) +from .dispense_while_tracking import ( + DispenseWhileTracking, + DispenseWhileTrackingParams, + DispenseWhileTrackingCreate, + DispenseWhileTrackingResult, + DispenseWhileTrackingCommandType +) + from .dispense_in_place import ( DispenseInPlace, DispenseInPlaceParams, @@ -365,10 +381,12 @@ AirGapInPlace, Aspirate, AspirateInPlace, + AspirateWhileTracking, Comment, Custom, Dispense, DispenseInPlace, + DispenseWhileTracking, BlowOut, BlowOutInPlace, ConfigureForVolume, @@ -452,6 +470,7 @@ CommandParams = Union[ AirGapInPlaceParams, AspirateParams, + AspirateWhileTrackingParams, AspirateInPlaceParams, CommentParams, ConfigureForVolumeParams, @@ -459,6 +478,7 @@ CustomParams, DispenseParams, DispenseInPlaceParams, + DispenseWhileTrackingParams, BlowOutParams, BlowOutInPlaceParams, DropTipParams, @@ -538,6 +558,7 @@ CommandType = Union[ AirGapInPlaceCommandType, AspirateCommandType, + AspirateWhileTrackingCommandType, AspirateInPlaceCommandType, CommentCommandType, ConfigureForVolumeCommandType, @@ -545,6 +566,7 @@ CustomCommandType, DispenseCommandType, DispenseInPlaceCommandType, + DispenseWhileTrackingCommandType, BlowOutCommandType, BlowOutInPlaceCommandType, DropTipCommandType, @@ -625,6 +647,7 @@ Union[ AirGapInPlaceCreate, AspirateCreate, + AspirateWhileTrackingCreate, AspirateInPlaceCreate, CommentCreate, ConfigureForVolumeCreate, @@ -632,6 +655,7 @@ CustomCreate, DispenseCreate, DispenseInPlaceCreate, + DispenseWhileTrackingCreate, BlowOutCreate, BlowOutInPlaceCreate, DropTipCreate, @@ -720,6 +744,7 @@ CommandResult = Union[ AirGapInPlaceResult, AspirateResult, + AspirateWhileTrackingResult, AspirateInPlaceResult, CommentResult, ConfigureForVolumeResult, @@ -727,6 +752,7 @@ CustomResult, DispenseResult, DispenseInPlaceResult, + DispenseWhileTrackingResult, BlowOutResult, BlowOutInPlaceResult, DropTipResult, diff --git a/api/src/opentrons/protocol_engine/commands/dispense.py b/api/src/opentrons/protocol_engine/commands/dispense.py index 3acb789b7f4..3b4b84f6b75 100644 --- a/api/src/opentrons/protocol_engine/commands/dispense.py +++ b/api/src/opentrons/protocol_engine/commands/dispense.py @@ -16,7 +16,6 @@ BaseLiquidHandlingResult, OverpressureError, dispense_in_place, - IsTrackingMixin, ) from .movement_common import ( LiquidHandlingWellLocationMixin, @@ -103,7 +102,6 @@ async def execute(self, params: DispenseParams) -> _ExecuteReturn: labware_id=labware_id, well_name=well_name, well_location=well_location, - is_tracking=False, ) if isinstance(move_result, DefinedErrorData): return move_result diff --git a/api/src/opentrons/protocol_engine/commands/dispense_while_tracking.py b/api/src/opentrons/protocol_engine/commands/dispense_while_tracking.py index 30357e936ba..de4904f5295 100644 --- a/api/src/opentrons/protocol_engine/commands/dispense_while_tracking.py +++ b/api/src/opentrons/protocol_engine/commands/dispense_while_tracking.py @@ -37,7 +37,7 @@ from ..state.state import StateView -DispenseCommandType = Literal["dispense"] +DispenseWhileTrackingCommandType = Literal["dispenseWhileTracking"] def _remove_default(s: dict[str, Any]) -> None: @@ -104,7 +104,6 @@ async def execute(self, params: DispenseWhileTrackingParams) -> _ExecuteReturn: labware_id=labware_id, well_name=well_name, well_location=well_location, - is_tracking=True, ) if isinstance(move_result, DefinedErrorData): return move_result @@ -185,7 +184,7 @@ class DispenseWhileTracking( ): """Dispense command model.""" - commandType: DispenseCommandType = "dispense" + commandType: DispenseWhileTrackingCommandType = "dispenseWhileTracking" params: DispenseWhileTrackingParams result: Optional[DispenseWhileTrackingResult] = None @@ -197,7 +196,7 @@ class DispenseWhileTracking( class DispenseWhileTrackingCreate(BaseCommandCreate[DispenseWhileTrackingParams]): """Create dispense command request model.""" - commandType: DispenseCommandType = "dispense" + commandType: DispenseWhileTrackingCommandType = "dispenseWhileTracking" params: DispenseWhileTrackingParams _CommandCls: Type[DispenseWhileTracking] = DispenseWhileTracking diff --git a/api/src/opentrons/protocol_engine/commands/movement_common.py b/api/src/opentrons/protocol_engine/commands/movement_common.py index ebb55128c3b..5cff8d5f358 100644 --- a/api/src/opentrons/protocol_engine/commands/movement_common.py +++ b/api/src/opentrons/protocol_engine/commands/movement_common.py @@ -61,7 +61,7 @@ class LiquidHandlingWellLocationMixin(BaseModel): ) wellLocation: LiquidHandlingWellLocation = Field( default_factory=LiquidHandlingWellLocation, - description="Relative well location at which to perform the operation", + description="Relative wwellell location at which to perform the operation", ) @@ -152,7 +152,6 @@ async def move_to_well( minimum_z_height: Optional[float] = None, speed: Optional[float] = None, operation_volume: Optional[float] = None, - is_tracking: Optional[bool] = False, ) -> MoveToWellOperationReturn: """Execute a move to well microoperation.""" try: @@ -166,7 +165,6 @@ async def move_to_well( minimum_z_height=minimum_z_height, speed=speed, operation_volume=operation_volume, - is_tracking=is_tracking, ) except StallOrCollisionDetectedError as e: return DefinedErrorData( diff --git a/api/src/opentrons/protocol_engine/commands/pipetting_common.py b/api/src/opentrons/protocol_engine/commands/pipetting_common.py index cfaf67f6375..6740a4babb3 100644 --- a/api/src/opentrons/protocol_engine/commands/pipetting_common.py +++ b/api/src/opentrons/protocol_engine/commands/pipetting_common.py @@ -63,15 +63,6 @@ class FlowRateMixin(BaseModel): ) -class IsTrackingMixin(BaseModel): - """Mixin for the 'is_tracking' field of aspirate commands.""" - - is_tracking: bool = Field( - False, - description="Whether or not the pipette should move with the liquid while aspirating.", - ) - - class BaseLiquidHandlingResult(BaseModel): """Base properties of a liquid handling result.""" diff --git a/api/src/opentrons/protocol_engine/execution/movement.py b/api/src/opentrons/protocol_engine/execution/movement.py index b5e3c5aeeac..be8bbbb8de2 100644 --- a/api/src/opentrons/protocol_engine/execution/movement.py +++ b/api/src/opentrons/protocol_engine/execution/movement.py @@ -74,7 +74,6 @@ async def move_to_well( minimum_z_height: Optional[float] = None, speed: Optional[float] = None, operation_volume: Optional[float] = None, - is_tracking: Optional[bool] = False, ) -> Point: """Move to a specific well.""" self._state_store.labware.raise_if_labware_inaccessible_by_pipette( @@ -138,7 +137,6 @@ async def move_to_well( force_direct=force_direct, minimum_z_height=minimum_z_height, operation_volume=operation_volume, - is_tracking=is_tracking, ) speed = self._state_store.pipettes.get_movement_speed( diff --git a/api/src/opentrons/protocol_engine/execution/pipetting.py b/api/src/opentrons/protocol_engine/execution/pipetting.py index a64cd8b0141..4f850592b25 100644 --- a/api/src/opentrons/protocol_engine/execution/pipetting.py +++ b/api/src/opentrons/protocol_engine/execution/pipetting.py @@ -188,7 +188,7 @@ async def aspirate_while_tracking( flow_rate=flow_rate, volume=adjusted_volume, ) - + # raise ValueError(f"adjusted volume = {adjusted_volume}\n volume = {volume}") return adjusted_volume async def dispense_while_tracking( @@ -384,6 +384,7 @@ async def dispense_in_place( raise InvalidPushOutVolumeError( "push out value cannot have a negative value." ) + raise ValueError("why am i here") self._validate_tip_attached(pipette_id=pipette_id, command_name="dispense") return _validate_dispense_volume( state_view=self._state_view, pipette_id=pipette_id, dispense_volume=volume @@ -424,8 +425,15 @@ async def aspirate_while_tracking( flow_rate: float, command_note_adder: CommandNoteAdder, ) -> float: - """Aspirate while moving the z stage with the liquid meniscus.""" - return 0.0 + """Virtually aspirate (no-op).""" + self._validate_tip_attached(pipette_id=pipette_id, command_name="aspirate") + + return _validate_aspirate_volume( + state_view=self._state_view, + pipette_id=pipette_id, + aspirate_volume=volume, + command_note_adder=command_note_adder, + ) async def dispense_while_tracking( self, @@ -436,8 +444,18 @@ async def dispense_while_tracking( flow_rate: float, push_out: Optional[float], ) -> float: - """Dispense while moving the z stage with the liquid meniscus.""" - return 0.0 + """Virtually dispense (no-op).""" + # TODO (tz, 8-23-23): add a check for push_out not larger that the max volume allowed when working on this https://opentrons.atlassian.net/browse/RSS-329 + if push_out and push_out < 0: + raise InvalidPushOutVolumeError( + "push out value cannot have a negative value." + ) + # raise ValueError("here") + self._validate_tip_attached(pipette_id=pipette_id, command_name="dispense") + return _validate_dispense_volume( + state_view=self._state_view, pipette_id=pipette_id, dispense_volume=volume + ) + # return volume def create_pipetting_handler( diff --git a/api/src/opentrons/protocol_engine/state/geometry.py b/api/src/opentrons/protocol_engine/state/geometry.py index d3633044e31..19a34ee3fa4 100644 --- a/api/src/opentrons/protocol_engine/state/geometry.py +++ b/api/src/opentrons/protocol_engine/state/geometry.py @@ -9,7 +9,13 @@ from dataclasses import dataclass from functools import cached_property -from opentrons.types import Point, DeckSlotName, StagingSlotName, MountType +from opentrons.types import ( + Point, + DeckSlotName, + StagingSlotName, + MountType, + MeniscusTracking, +) from opentrons_shared_data.errors.exceptions import InvalidStoredData from opentrons_shared_data.labware.constants import WELL_NAME_PATTERN @@ -465,7 +471,8 @@ def validate_well_position( ) else: raise OperationLocationNotInWellError( - f"Specifying {well_location.origin} with an offset of {well_location.offset} and a volume offset of {well_location.volumeOffset} results in an operation location below the bottom of the well" + # f"Specifying {well_location.origin} with an offset of {well_location.offset} and a volume offset of {well_location.volumeOffset} results in an operation location below the bottom of the well" + f"well = {well_location}" ) def get_well_position( @@ -475,7 +482,6 @@ def get_well_position( well_location: Optional[WellLocations] = None, operation_volume: Optional[float] = None, pipette_id: Optional[str] = None, - is_tracking: Optional[bool] = False, ) -> Point: """Given relative well location in a labware, get absolute position.""" labware_pos = self.get_labware_position(labware_id) @@ -491,7 +497,6 @@ def get_well_position( well_location=well_location, well_depth=well_depth, operation_volume=operation_volume, - is_tracking=is_tracking, ) offset = offset.model_copy(update={"z": offset.z + offset_adjustment}) self.validate_well_position( @@ -536,13 +541,13 @@ def get_relative_liquid_handling_well_location( labware_id: str, well_name: str, absolute_point: Point, - is_meniscus: Optional[bool] = None, + meniscus_tracking: Optional[MeniscusTracking] = None, ) -> LiquidHandlingWellLocation: """Given absolute position, get relative location of a well in a labware. If is_meniscus is True, absolute_point will hold the z-offset in its z field. """ - if is_meniscus: + if meniscus_tracking: return LiquidHandlingWellLocation( origin=WellOrigin.MENISCUS, offset=WellOffset(x=0, y=0, z=absolute_point.z), @@ -1433,7 +1438,6 @@ def get_well_offset_adjustment( well_location: WellLocations, well_depth: float, operation_volume: Optional[float] = None, - is_tracking: Optional[bool] = False, ) -> float: """Return a z-axis distance that accounts for well handling height and operation volume. @@ -1446,11 +1450,10 @@ def get_well_offset_adjustment( well_location=well_location, well_depth=well_depth, ) - # _log = logging.getLogger(__name__) - # raise ValueError( - # f"initial handling height {initial_handling_height} \n is_tracking {is_tracking}" - # ) - if is_tracking: + if ( + well_location.origin == WellOrigin.MENISCUS + and not well_location.volumeOffset + ): return initial_handling_height if isinstance(well_location, PickUpTipWellLocation): volume = 0.0 diff --git a/api/src/opentrons/protocol_engine/state/motion.py b/api/src/opentrons/protocol_engine/state/motion.py index 9cb566156ec..15a8d6a633c 100644 --- a/api/src/opentrons/protocol_engine/state/motion.py +++ b/api/src/opentrons/protocol_engine/state/motion.py @@ -98,7 +98,6 @@ def get_movement_waypoints_to_well( force_direct: bool = False, minimum_z_height: Optional[float] = None, operation_volume: Optional[float] = None, - is_tracking: Optional[bool] = False, ) -> List[motion_planning.Waypoint]: """Calculate waypoints to a destination that's specified as a well.""" location = current_well or self._pipettes.get_current_location() @@ -115,7 +114,6 @@ def get_movement_waypoints_to_well( well_location=well_location, operation_volume=operation_volume, pipette_id=pipette_id, - is_tracking=is_tracking, ) move_type = _move_types.get_move_type_to_well( diff --git a/api/src/opentrons/types.py b/api/src/opentrons/types.py index 09e138513c1..7551b8a67f2 100644 --- a/api/src/opentrons/types.py +++ b/api/src/opentrons/types.py @@ -11,6 +11,7 @@ Optional, Protocol, Dict, + Literal, ) from opentrons_shared_data.robot.types import RobotType @@ -88,6 +89,20 @@ def magnitude_to(self, other: Any) -> float: ] +class MeniscusTracking: + def __init__( + self, + target: Union[ + Literal["beginning"], Literal["end"], Literal["dynamic_meniscus"] + ] = "end", + ) -> None: + self._target = target + + @property + def target(self) -> str: + return str(self._target) + + class Location: """Location(point: Point, labware: Union["Labware", "Well", str, "ModuleGeometry", LabwareLike, None, "ModuleContext"]) @@ -129,12 +144,12 @@ def __init__( "ModuleContext", ], *, - _ot_internal_is_meniscus: Optional[bool] = None, + _meniscus_tracking: Optional[MeniscusTracking] = None, ): self._point = point self._given_labware = labware self._labware = LabwareLike(labware) - self._is_meniscus = _ot_internal_is_meniscus + self._meniscus_tracking = _meniscus_tracking # todo(mm, 2021-10-01): Figure out how to get .point and .labware to show up # in the rendered docs, and then update the class docstring to use cross-references. @@ -148,8 +163,8 @@ def labware(self) -> LabwareLike: return self._labware @property - def is_meniscus(self) -> Optional[bool]: - return self._is_meniscus + def meniscus_tracking(self) -> Optional[MeniscusTracking]: + return self._meniscus_tracking def __iter__(self) -> Iterator[Union[Point, LabwareLike]]: """Iterable interface to support unpacking. Like a tuple. @@ -167,7 +182,7 @@ def __eq__(self, other: object) -> bool: isinstance(other, Location) and other._point == self._point and other._labware == self._labware - and other._is_meniscus == self._is_meniscus + and other._meniscus_tracking == self._meniscus_tracking ) def move(self, point: Point) -> "Location": @@ -193,7 +208,7 @@ def move(self, point: Point) -> "Location": return Location(point=self.point + point, labware=self._given_labware) def __repr__(self) -> str: - return f"Location(point={repr(self._point)}, labware={self._labware}, is_meniscus={self._is_meniscus if self._is_meniscus is not None else False})" + return f"Location(point={repr(self._point)}, labware={self._labware}, meniscus_tracking={self._meniscus_tracking})" # TODO(mc, 2020-10-22): use MountType implementation for Mount 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 73f39006299..23d2f4bcf58 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 @@ -508,7 +508,6 @@ def test_aspirate_from_well( labware_id="123abc", well_name="my cool well", absolute_point=Point(1, 2, 3), - is_meniscus=None, ) ).then_return( LiquidHandlingWellLocation( @@ -607,7 +606,6 @@ def test_aspirate_from_meniscus( labware_id="123abc", well_name="my cool well", absolute_point=Point(1, 2, 3), - is_meniscus=True, ) ).then_return( LiquidHandlingWellLocation( @@ -622,7 +620,6 @@ def test_aspirate_from_meniscus( rate=5.6, flow_rate=7.8, in_place=False, - is_meniscus=True, ) decoy.verify( @@ -805,7 +802,6 @@ def test_dispense_to_well( labware_id="123abc", well_name="my cool well", absolute_point=Point(1, 2, 3), - is_meniscus=None, ) ).then_return( LiquidHandlingWellLocation( diff --git a/api/tests/opentrons/protocol_api/test_instrument_context.py b/api/tests/opentrons/protocol_api/test_instrument_context.py index 3f639aff922..6a72054a02f 100644 --- a/api/tests/opentrons/protocol_api/test_instrument_context.py +++ b/api/tests/opentrons/protocol_api/test_instrument_context.py @@ -342,7 +342,6 @@ def test_aspirate( volume=42.0, rate=1.23, flow_rate=5.67, - is_meniscus=None, ), times=1, ) @@ -380,7 +379,6 @@ def test_aspirate_well_location( volume=42.0, rate=1.23, flow_rate=5.67, - is_meniscus=None, ), times=1, ) @@ -394,9 +392,7 @@ def test_aspirate_meniscus_well_location( ) -> None: """It should aspirate to a well.""" mock_well = decoy.mock(cls=Well) - input_location = Location( - point=Point(2, 2, 2), labware=mock_well, _ot_internal_is_meniscus=True - ) + input_location = Location(point=Point(2, 2, 2), labware=mock_well) last_location = Location(point=Point(9, 9, 9), labware=None) decoy.when(mock_instrument_core.get_mount()).then_return(Mount.RIGHT) @@ -420,7 +416,6 @@ def test_aspirate_meniscus_well_location( volume=42.0, rate=1.23, flow_rate=5.67, - is_meniscus=True, ), times=1, ) @@ -457,7 +452,6 @@ def test_aspirate_from_coordinates( volume=42.0, rate=1.23, flow_rate=5.67, - is_meniscus=None, ), times=1, ) @@ -971,7 +965,6 @@ def test_dispense_with_location( rate=1.23, flow_rate=5.67, push_out=None, - is_meniscus=None, ), times=1, ) @@ -1010,7 +1003,6 @@ def test_dispense_with_well_location( rate=1.23, flow_rate=3.0, push_out=7, - is_meniscus=None, ), times=1, ) @@ -1051,7 +1043,6 @@ def test_dispense_with_well( rate=1.23, flow_rate=5.67, push_out=None, - is_meniscus=None, ), times=1, ) @@ -1306,7 +1297,6 @@ def test_dispense_0_volume_means_dispense_everything( rate=1.23, flow_rate=5.67, push_out=None, - is_meniscus=None, ), times=1, ) @@ -1336,7 +1326,6 @@ def test_dispense_0_volume_means_dispense_nothing( rate=1.23, flow_rate=5.67, push_out=None, - is_meniscus=None, ), times=1, ) @@ -1376,7 +1365,6 @@ def test_aspirate_0_volume_means_aspirate_everything( volume=200, rate=1.23, flow_rate=5.67, - is_meniscus=None, ), times=1, ) @@ -1416,7 +1404,6 @@ def test_aspirate_0_volume_means_aspirate_nothing( volume=0, rate=1.23, flow_rate=5.67, - is_meniscus=None, ), times=1, ) diff --git a/api/tests/opentrons/protocol_api/test_well.py b/api/tests/opentrons/protocol_api/test_well.py index c0ef530289b..fd9555fb3b9 100644 --- a/api/tests/opentrons/protocol_api/test_well.py +++ b/api/tests/opentrons/protocol_api/test_well.py @@ -108,7 +108,6 @@ def test_well_meniscus(decoy: Decoy, mock_well_core: WellCore, subject: Well) -> assert isinstance(result, Location) assert result.point == Point(0, 0, 4.2) - assert result.is_meniscus is True assert result.labware.as_well() is subject diff --git a/api/tests/opentrons/protocol_engine/commands/test_aspirate.py b/api/tests/opentrons/protocol_engine/commands/test_aspirate.py index 6954a74cf57..4a8adbcdc76 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_aspirate.py +++ b/api/tests/opentrons/protocol_engine/commands/test_aspirate.py @@ -117,7 +117,6 @@ async def test_aspirate_implementation_no_prep( minimum_z_height=None, speed=None, operation_volume=-50, - is_tracking=False, ), ).then_return(Point(x=1, y=2, z=3)) @@ -210,7 +209,6 @@ async def test_aspirate_implementation_with_prep( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ), ).then_return(Point()) @@ -229,7 +227,6 @@ async def test_aspirate_implementation_with_prep( minimum_z_height=None, speed=None, operation_volume=-volume, - is_tracking=False, ), ).then_return(Point(x=1, y=2, z=3)) @@ -320,7 +317,6 @@ async def test_aspirate_raises_volume_error( minimum_z_height=None, speed=None, operation_volume=-50, - is_tracking=False, ), ).then_return(Point(1, 2, 3)) @@ -397,7 +393,6 @@ async def test_overpressure_error( minimum_z_height=None, speed=None, operation_volume=-50, - is_tracking=False, ), ).then_return(position) @@ -498,7 +493,6 @@ async def test_aspirate_implementation_meniscus( minimum_z_height=None, speed=None, operation_volume=-50, - is_tracking=False, ), ).then_return(Point(x=1, y=2, z=3)) @@ -578,7 +572,6 @@ async def test_stall_during_final_movement( minimum_z_height=None, speed=None, operation_volume=-50, - is_tracking=False, ), ).then_raise(StallOrCollisionDetectedError()) @@ -639,7 +632,6 @@ async def test_stall_during_preparation( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ), ).then_raise(StallOrCollisionDetectedError()) decoy.when(model_utils.generate_id()).then_return(error_id) @@ -712,7 +704,6 @@ async def test_overpressure_during_preparation( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ), ).then_return(prep_location) diff --git a/api/tests/opentrons/protocol_engine/commands/test_blow_out.py b/api/tests/opentrons/protocol_engine/commands/test_blow_out.py index b7731f1d93b..7549141be5b 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_blow_out.py +++ b/api/tests/opentrons/protocol_engine/commands/test_blow_out.py @@ -80,7 +80,6 @@ async def test_blow_out_implementation( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=1, y=2, z=3)) @@ -153,7 +152,6 @@ async def test_overpressure_error( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=1, y=2, z=3)) @@ -229,7 +227,6 @@ async def test_stall_error( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_raise(StallOrCollisionDetectedError()) diff --git a/api/tests/opentrons/protocol_engine/commands/test_dispense.py b/api/tests/opentrons/protocol_engine/commands/test_dispense.py index 2c48c6359de..5b60b61d4df 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_dispense.py +++ b/api/tests/opentrons/protocol_engine/commands/test_dispense.py @@ -80,7 +80,6 @@ async def test_dispense_implementation( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=1, y=2, z=3)) @@ -189,7 +188,6 @@ async def test_overpressure_error( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ), ).then_return(position) @@ -281,7 +279,6 @@ async def test_stall_error( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ), ).then_raise(StallOrCollisionDetectedError()) diff --git a/api/tests/opentrons/protocol_engine/commands/test_drop_tip.py b/api/tests/opentrons/protocol_engine/commands/test_drop_tip.py index bf908dceb9e..430fa8dff32 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_drop_tip.py +++ b/api/tests/opentrons/protocol_engine/commands/test_drop_tip.py @@ -132,7 +132,6 @@ async def test_drop_tip_implementation( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=111, y=222, z=333)) @@ -219,7 +218,6 @@ async def test_drop_tip_with_alternating_locations( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=111, y=222, z=333)) @@ -291,7 +289,6 @@ async def test_tip_attached_error( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=111, y=222, z=333)) decoy.when( @@ -388,7 +385,6 @@ async def test_stall_error( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_raise(StallOrCollisionDetectedError()) diff --git a/api/tests/opentrons/protocol_engine/commands/test_liquid_probe.py b/api/tests/opentrons/protocol_engine/commands/test_liquid_probe.py index eed15d26abb..c9661512aaa 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_liquid_probe.py +++ b/api/tests/opentrons/protocol_engine/commands/test_liquid_probe.py @@ -155,7 +155,6 @@ async def test_liquid_probe_implementation( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ), ).then_return(Point(x=1, y=2, z=3)) @@ -316,7 +315,6 @@ async def test_liquid_not_found_error( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ), ).then_return(position) @@ -717,7 +715,6 @@ async def test_liquid_probe_stall( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ), ).then_raise(StallOrCollisionDetectedError()) diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_to_well.py b/api/tests/opentrons/protocol_engine/commands/test_move_to_well.py index 8e0f3b6b735..56a2691bbee 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_to_well.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_to_well.py @@ -72,7 +72,6 @@ async def test_move_to_well_implementation( speed=7.89, current_well=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=9, y=8, z=7)) @@ -137,7 +136,6 @@ async def test_move_to_well_stall_defined_error( speed=7.89, current_well=None, operation_volume=None, - is_tracking=False, ) ).then_raise(StallOrCollisionDetectedError()) decoy.when(mock_model_utils.generate_id()).then_return(error_id) diff --git a/api/tests/opentrons/protocol_engine/commands/test_pick_up_tip.py b/api/tests/opentrons/protocol_engine/commands/test_pick_up_tip.py index df99b42c927..d4c53ea5992 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_pick_up_tip.py +++ b/api/tests/opentrons/protocol_engine/commands/test_pick_up_tip.py @@ -67,7 +67,6 @@ async def test_success( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=111, y=222, z=333)) @@ -153,7 +152,6 @@ async def test_tip_physically_missing_error( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=111, y=222, z=333)) decoy.when( @@ -246,7 +244,6 @@ async def test_stall_error( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_raise(StallOrCollisionDetectedError()) diff --git a/api/tests/opentrons/protocol_engine/commands/test_touch_tip.py b/api/tests/opentrons/protocol_engine/commands/test_touch_tip.py index 0d343c8179b..5756810c9ee 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_touch_tip.py +++ b/api/tests/opentrons/protocol_engine/commands/test_touch_tip.py @@ -88,7 +88,6 @@ async def test_touch_tip_implementation( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=1, y=2, z=3)) @@ -179,7 +178,6 @@ async def test_touch_tip_implementation_with_mm_to_edge( minimum_z_height=None, speed=None, operation_volume=None, - is_tracking=False, ) ).then_return(Point(x=1, y=2, z=3)) diff --git a/api/tests/opentrons/protocol_engine/execution/test_movement_handler.py b/api/tests/opentrons/protocol_engine/execution/test_movement_handler.py index e775382ecf0..73b293fdbef 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_movement_handler.py +++ b/api/tests/opentrons/protocol_engine/execution/test_movement_handler.py @@ -150,7 +150,6 @@ async def test_move_to_well( force_direct=True, minimum_z_height=12.3, operation_volume=None, - is_tracking=False, ) ).then_return( [Waypoint(Point(1, 2, 3), CriticalPoint.XY_CENTER), Waypoint(Point(4, 5, 6))] @@ -260,7 +259,6 @@ async def test_move_to_well_from_starting_location( force_direct=False, minimum_z_height=None, operation_volume=None, - is_tracking=False, ) ).then_return([Waypoint(Point(1, 2, 3), CriticalPoint.XY_CENTER)]) diff --git a/api/tests/opentrons/protocol_engine/state/test_geometry_view.py b/api/tests/opentrons/protocol_engine/state/test_geometry_view.py index bf82c17c6bc..805c255fa60 100644 --- a/api/tests/opentrons/protocol_engine/state/test_geometry_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_geometry_view.py @@ -2006,7 +2006,6 @@ def test_get_relative_liquid_handling_well_location( labware_id="labware-id", well_name="B2", absolute_point=Point(x=0, y=0, z=-2), - is_meniscus=True, ) assert result == LiquidHandlingWellLocation( diff --git a/api/tests/opentrons/protocol_engine/state/test_motion_view.py b/api/tests/opentrons/protocol_engine/state/test_motion_view.py index 65aa2192846..18e765cb438 100644 --- a/api/tests/opentrons/protocol_engine/state/test_motion_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_motion_view.py @@ -466,7 +466,6 @@ def test_get_movement_waypoints_to_well_raises( well_location=None, operation_volume=None, pipette_id="pipette-id", - is_tracking=False, ) ).then_return(Point(x=4, y=5, z=6)) decoy.when(pipette_view.get_current_location()).then_return(None) diff --git a/api/tests/opentrons/test_types.py b/api/tests/opentrons/test_types.py index 77249fa0492..6cd93dce125 100644 --- a/api/tests/opentrons/test_types.py +++ b/api/tests/opentrons/test_types.py @@ -29,7 +29,7 @@ def test_location_repr_labware(min_lw: Labware) -> None: loc = Location(point=Point(x=1.1, y=2.1, z=3.5), labware=min_lw) assert ( f"{loc}" - == "Location(point=Point(x=1.1, y=2.1, z=3.5), labware=minimal labware on deck, is_meniscus=False)" + == "Location(point=Point(x=1.1, y=2.1, z=3.5), labware=minimal labware on deck)" ) @@ -38,17 +38,14 @@ def test_location_repr_well(min_lw: Labware) -> None: loc = Location(point=Point(x=1, y=2, z=3), labware=min_lw.wells()[0]) assert ( f"{loc}" - == "Location(point=Point(x=1, y=2, z=3), labware=A1 of minimal labware on deck, is_meniscus=False)" + == "Location(point=Point(x=1, y=2, z=3), labware=A1 of minimal labware on deck)" ) def test_location_repr_slot() -> None: """It should represent labware as a slot""" loc = Location(point=Point(x=-1, y=2, z=3), labware="1") - assert ( - f"{loc}" - == "Location(point=Point(x=-1, y=2, z=3), labware=1, is_meniscus=False)" - ) + assert f"{loc}" == "Location(point=Point(x=-1, y=2, z=3), labware=1)" @pytest.mark.parametrize(