Skip to content

Commit

Permalink
add aspirate test
Browse files Browse the repository at this point in the history
  • Loading branch information
sanni-t committed Dec 12, 2024
1 parent aa189fa commit 1851696
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 24 deletions.
35 changes: 11 additions & 24 deletions api/src/opentrons/protocol_api/core/engine/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,9 @@
)
from opentrons.protocol_api._nozzle_layout import NozzleLayout
from . import overlap_versions, pipette_movement_conflict
from . import transfer_components_executor as tx_comps_executor

from .well import WellCore
from .transfer_components_executor import (
TransferComponentsExecutor,
absolute_point_from_position_reference_and_offset,
)
from ..instrument import AbstractInstrument
from ...disposal_locations import TrashBin, WasteChute

Expand Down Expand Up @@ -980,20 +977,6 @@ def transfer_liquid(
alternate_drop_location=True,
)

def _get_transfer_components_executor(
self,
transfer_properties: TransferProperties,
target_location: Location,
target_well: WellCore,
) -> TransferComponentsExecutor:
"""Get a TransferComponentsExecutor."""
return TransferComponentsExecutor(
instrument_core=self,
transfer_properties=transfer_properties,
target_location=target_location,
target_well=target_well,
)

def aspirate_liquid_class(
self,
volume: float,
Expand All @@ -1011,21 +994,25 @@ def aspirate_liquid_class(
"""
aspirate_props = transfer_properties.aspirate
source_loc, source_well = source
aspirate_point = absolute_point_from_position_reference_and_offset(
well=source_well,
position_reference=aspirate_props.position_reference,
offset=aspirate_props.offset,
aspirate_point = (
tx_comps_executor.absolute_point_from_position_reference_and_offset(
well=source_well,
position_reference=aspirate_props.position_reference,
offset=aspirate_props.offset,
)
)
aspirate_location = Location(aspirate_point, labware=source_loc.labware)

components_executer = self._get_transfer_components_executor(
components_executer = tx_comps_executor.get_transfer_components_executor(
instrument_core=self,
transfer_properties=transfer_properties,
target_location=aspirate_location,
target_well=source_well,
)
components_executer.submerge(
submerge_properties=aspirate_props.submerge,
# Assuming aspirate is not called with *liquid*git swta in the tip
# Assuming aspirate is not called with *liquid* in the tip
# TODO: evaluate if using the current volume to find air gap is not a good idea.
air_gap_volume=self.get_current_volume(),
)
# TODO: when aspirating for consolidation, do not perform mix
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,21 @@ def _remove_air_gap(self, location: Location, volume: float) -> None:
self._instrument.delay(dispense_delay.duration)


def get_transfer_components_executor(
instrument_core: InstrumentCore,
transfer_properties: TransferProperties,
target_location: Location,
target_well: WellCore,
) -> TransferComponentsExecutor:
"""Get a TransferComponentsExecutor."""
return TransferComponentsExecutor(
instrument_core=instrument_core,
transfer_properties=transfer_properties,
target_location=target_location,
target_well=target_well,
)


def absolute_point_from_position_reference_and_offset(
well: WellCore,
position_reference: PositionReference,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@
from decoy import errors
from opentrons_shared_data.liquid_classes.liquid_class_definition import (
LiquidClassSchemaV1,
PositionReference,
Coordinate,
)

from opentrons_shared_data.pipette.types import PipetteNameType

from opentrons.hardware_control import SyncHardwareAPI
from opentrons.hardware_control.dev_types import PipetteDict
from opentrons.protocol_api._liquid_properties import TransferProperties
from opentrons.protocol_api.core.engine import transfer_components_executor
from opentrons.protocol_api.core.engine.transfer_components_executor import (
TransferComponentsExecutor,
)
from opentrons.protocol_engine import (
DeckPoint,
LoadedPipette,
Expand Down Expand Up @@ -90,6 +96,34 @@ def patch_mock_pipette_movement_safety_check(
)


@pytest.fixture
def mock_transfer_components_executor(
decoy: Decoy,
) -> TransferComponentsExecutor:
"""Get a mocked out TransferComponentsExecutor."""
return decoy.mock(cls=TransferComponentsExecutor)


@pytest.fixture(autouse=True)
def patch_mock_transfer_components_executor(
decoy: Decoy,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Replace transfer_components_executor functions with mocks."""
monkeypatch.setattr(
transfer_components_executor,
"get_transfer_components_executor",
decoy.mock(func=transfer_components_executor.get_transfer_components_executor),
)
monkeypatch.setattr(
transfer_components_executor,
"absolute_point_from_position_reference_and_offset",
decoy.mock(
func=transfer_components_executor.absolute_point_from_position_reference_and_offset
),
)


@pytest.fixture
def subject(
decoy: Decoy,
Expand Down Expand Up @@ -1556,3 +1590,54 @@ def test_load_liquid_class(
tiprack_uri="opentrons_flex_96_tiprack_50ul",
)
assert result == "liquid-class-id"


def test_aspirate_liquid_class(
decoy: Decoy,
mock_engine_client: EngineClient,
subject: InstrumentCore,
minimal_liquid_class_def2: LiquidClassSchemaV1,
mock_transfer_components_executor: TransferComponentsExecutor,
) -> None:
"""It should call aspirate sub-steps execution based on liquid class."""
source_well = decoy.mock(cls=WellCore)
source_location = Location(Point(1, 2, 3), labware=None)
test_liquid_class = LiquidClass.create(minimal_liquid_class_def2)
test_transfer_properties = test_liquid_class.get_for(
"flex_1channel_50", "opentrons_flex_96_tiprack_50ul"
)
decoy.when(
transfer_components_executor.absolute_point_from_position_reference_and_offset(
well=source_well,
position_reference=PositionReference.WELL_BOTTOM,
offset=Coordinate(x=0, y=0, z=-5),
)
).then_return(Point(1, 2, 3))
decoy.when(
transfer_components_executor.get_transfer_components_executor(
instrument_core=subject,
transfer_properties=test_transfer_properties,
target_location=Location(Point(1, 2, 3), labware=None),
target_well=source_well,
)
).then_return(mock_transfer_components_executor)
decoy.when(
mock_engine_client.state.pipettes.get_aspirated_volume("abc123")
).then_return(111)
subject.aspirate_liquid_class(
volume=123,
source=(source_location, source_well),
transfer_properties=test_transfer_properties,
)
decoy.verify(
mock_transfer_components_executor.submerge(
submerge_properties=test_transfer_properties.aspirate.submerge,
air_gap_volume=111,
),
mock_transfer_components_executor.mix(
mix_properties=test_transfer_properties.aspirate.mix
),
mock_transfer_components_executor.pre_wet(volume=123),
mock_transfer_components_executor.aspirate_and_wait(volume=123),
mock_transfer_components_executor.retract_after_aspiration(volume=123),
)

0 comments on commit 1851696

Please sign in to comment.