diff --git a/api/src/opentrons/protocol_api/instrument_context.py b/api/src/opentrons/protocol_api/instrument_context.py index 7b119dad436f..3ade9d389c23 100644 --- a/api/src/opentrons/protocol_api/instrument_context.py +++ b/api/src/opentrons/protocol_api/instrument_context.py @@ -498,6 +498,7 @@ def mix( # noqa: C901 rate: float = 1.0, aspirate_delay: Optional[float] = None, dispense_delay: Optional[float] = None, + final_push_out: Optional[float] = None, ) -> InstrumentContext: """ Mix a volume of liquid by repeatedly aspirating and dispensing it in a single location. @@ -524,6 +525,10 @@ def mix( # noqa: C901 :ref:`new-plunger-flow-rates`. :param aspirate_delay: How long to wait after each aspirate in the mix, in seconds. :param dispense_delay: How long to wait after each dispense in the mix, in seconds. + :param final_push_out: How much to push out after the final mix repetition. The + pipette will not push out after earlier repetitions. If + not specified or ``None``, the pipette will push out the + default non-zero amount. See :ref:`push-out-dispense`. :raises: ``UnexpectedTipRemovalError`` -- If no tip is attached to the pipette. :returns: This instance. @@ -537,7 +542,7 @@ def mix( # noqa: C901 .. versionchanged:: 2.21 Does not repeatedly check for liquid presence. .. versionchanged:: 2.24 - Adds the ``aspirate_delay`` and ``dispense_delay`` parameters. + Adds the ``aspirate_delay``, ``dispense_delay``, and ``final_push_out`` parameters. """ _log.debug( "mixing {}uL with {} repetitions in {} at rate={}".format( @@ -564,6 +569,12 @@ def mix( # noqa: C901 until_version="2.24", current_version=f"{self._api_version}", ) + if final_push_out and self.api_version < APIVersion(2, 24): + raise APIVersionError( + api_element="final_push_out", + until_version="2.24", + current_version=f"{self._api_version}", + ) def delay_with_publish(seconds: float) -> None: # We don't have access to ProtocolContext.delay() which would automatically @@ -611,7 +622,10 @@ def dispense_with_delay(push_out: Optional[float]) -> None: # aspirate location was set above, do subsequent aspirates in-place: aspirate_with_delay(location=None) repetitions -= 1 - dispense_with_delay(push_out=None) + if final_push_out is not None: + dispense_with_delay(push_out=final_push_out) + else: + dispense_with_delay(push_out=None) return self @requires_version(2, 0) diff --git a/api/tests/opentrons/protocol_api/test_instrument_context.py b/api/tests/opentrons/protocol_api/test_instrument_context.py index 5b232e97d655..8a1cdcf55d60 100644 --- a/api/tests/opentrons/protocol_api/test_instrument_context.py +++ b/api/tests/opentrons/protocol_api/test_instrument_context.py @@ -1666,13 +1666,13 @@ def test_mix_with_lpd( ) -def test_mix_with_delay( +def test_mix_with_delay_and_final_push_out( decoy: Decoy, mock_instrument_core: InstrumentCore, subject: InstrumentContext, mock_protocol_core: ProtocolCore, ) -> None: - """It should delay after the aspirate/dispense in a mix.""" + """It should delay after the aspirate/dispense and emit the specified push out for the final dispense in a mix.""" mock_well = decoy.mock(cls=Well) input_location = Location(point=Point(2, 2, 2), labware=mock_well) decoy.when(mock_protocol_core.get_last_location(Mount.LEFT)).then_return( @@ -1689,6 +1689,7 @@ def test_mix_with_delay( location=input_location, aspirate_delay=3, dispense_delay=4, + final_push_out=2, ) decoy.verify( mock_instrument_core.aspirate( @@ -1729,7 +1730,7 @@ def test_mix_with_delay( rate=1, flow_rate=5.67, in_place=True, - push_out=None, + push_out=2, # final push out meniscus_tracking=None, ), mock_protocol_core.delay(4, msg=None), # dispense delay