Skip to content

Commit

Permalink
refactor(api): Port remaining TipStore bits to StateUpdate (#16620)
Browse files Browse the repository at this point in the history
  • Loading branch information
SyntaxColoring authored Oct 29, 2024
1 parent 1a91bf4 commit f16d3fb
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 270 deletions.
1 change: 0 additions & 1 deletion api/src/opentrons/protocol_engine/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@
LoadPipetteCreate,
LoadPipetteResult,
LoadPipetteCommandType,
LoadPipettePrivateResult,
)

from .move_labware import (
Expand Down
16 changes: 4 additions & 12 deletions api/src/opentrons/protocol_engine/commands/command_unions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Union types of concrete command definitions."""

from collections.abc import Collection
from typing import Annotated, Type, Union, get_type_hints
from typing import Annotated, Literal, Type, Union, get_type_hints

from pydantic import Field

Expand Down Expand Up @@ -141,7 +141,6 @@
LoadPipetteCreate,
LoadPipetteResult,
LoadPipetteCommandType,
LoadPipettePrivateResult,
)

from .move_labware import (
Expand Down Expand Up @@ -272,7 +271,6 @@
ConfigureForVolumeCreate,
ConfigureForVolumeResult,
ConfigureForVolumeCommandType,
ConfigureForVolumePrivateResult,
)

from .prepare_to_aspirate import (
Expand Down Expand Up @@ -701,15 +699,9 @@
unsafe.UnsafeUngripLabwareResult,
]

# todo(mm, 2024-06-12): Ideally, command return types would have specific
# CommandPrivateResults paired with specific CommandResults. For example,
# a TouchTipResult can never be paired with a LoadPipettePrivateResult in practice,
# and ideally our types would reflect that.
CommandPrivateResult = Union[
None,
LoadPipettePrivateResult,
ConfigureForVolumePrivateResult,
]
# todo(mm, 2024-10-28): This has been obsoleted by StateUpdate. Delete this.
# https://opentrons.atlassian.net/browse/EXEC-639
CommandPrivateResult = Literal[None]

# All `DefinedErrorData`s that implementations will actually return in practice.
CommandDefinedErrorData = Union[
Expand Down
17 changes: 3 additions & 14 deletions api/src/opentrons/protocol_engine/commands/configure_for_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from .pipetting_common import PipetteIdMixin
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
from ..errors.error_occurrence import ErrorOccurrence
from .configuring_common import PipetteConfigUpdateResultMixin
from ..state.update_types import StateUpdate

if TYPE_CHECKING:
Expand Down Expand Up @@ -35,12 +34,6 @@ class ConfigureForVolumeParams(PipetteIdMixin):
)


class ConfigureForVolumePrivateResult(PipetteConfigUpdateResultMixin):
"""Result sent to the store but not serialized."""

pass


class ConfigureForVolumeResult(BaseModel):
"""Result data from execution of an ConfigureForVolume command."""

Expand All @@ -50,7 +43,7 @@ class ConfigureForVolumeResult(BaseModel):
class ConfigureForVolumeImplementation(
AbstractCommandImpl[
ConfigureForVolumeParams,
SuccessData[ConfigureForVolumeResult, ConfigureForVolumePrivateResult],
SuccessData[ConfigureForVolumeResult, None],
]
):
"""Configure for volume command implementation."""
Expand All @@ -60,7 +53,7 @@ def __init__(self, equipment: EquipmentHandler, **kwargs: object) -> None:

async def execute(
self, params: ConfigureForVolumeParams
) -> SuccessData[ConfigureForVolumeResult, ConfigureForVolumePrivateResult]:
) -> SuccessData[ConfigureForVolumeResult, None]:
"""Check that requested pipette can be configured for the given volume."""
pipette_result = await self._equipment.configure_for_volume(
pipette_id=params.pipetteId,
Expand All @@ -77,11 +70,7 @@ async def execute(

return SuccessData(
public=ConfigureForVolumeResult(),
private=ConfigureForVolumePrivateResult(
pipette_id=pipette_result.pipette_id,
serial_number=pipette_result.serial_number,
config=pipette_result.static_config,
),
private=None,
state_update=state_update,
)

Expand Down
13 changes: 0 additions & 13 deletions api/src/opentrons/protocol_engine/commands/configuring_common.py

This file was deleted.

19 changes: 3 additions & 16 deletions api/src/opentrons/protocol_engine/commands/load_pipette.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
from ..errors.error_occurrence import ErrorOccurrence
from .configuring_common import PipetteConfigUpdateResultMixin
from ..errors import InvalidSpecificationForRobotTypeError, InvalidLoadPipetteSpecsError

if TYPE_CHECKING:
Expand All @@ -28,12 +27,6 @@
LoadPipetteCommandType = Literal["loadPipette"]


class LoadPipettePrivateResult(PipetteConfigUpdateResultMixin):
"""The not-to-be-exposed results of a load pipette call."""

...


class LoadPipetteParams(BaseModel):
"""Payload needed to load a pipette on to a mount."""

Expand Down Expand Up @@ -73,9 +66,7 @@ class LoadPipetteResult(BaseModel):


class LoadPipetteImplementation(
AbstractCommandImpl[
LoadPipetteParams, SuccessData[LoadPipetteResult, LoadPipettePrivateResult]
]
AbstractCommandImpl[LoadPipetteParams, SuccessData[LoadPipetteResult, None]]
):
"""Load pipette command implementation."""

Expand All @@ -87,7 +78,7 @@ def __init__(

async def execute(
self, params: LoadPipetteParams
) -> SuccessData[LoadPipetteResult, LoadPipettePrivateResult]:
) -> SuccessData[LoadPipetteResult, None]:
"""Check that requested pipette is attached and assign its identifier."""
pipette_generation = convert_to_pipette_name_type(
params.pipetteName.value
Expand Down Expand Up @@ -139,11 +130,7 @@ async def execute(

return SuccessData(
public=LoadPipetteResult(pipetteId=loaded_pipette.pipette_id),
private=LoadPipettePrivateResult(
pipette_id=loaded_pipette.pipette_id,
serial_number=loaded_pipette.serial_number,
config=loaded_pipette.static_config,
),
private=None,
state_update=state_update,
)

Expand Down
59 changes: 24 additions & 35 deletions api/src/opentrons/protocol_engine/state/tips.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@
from opentrons.protocol_engine.state import update_types

from ._abstract_store import HasState, HandlesActions
from ..actions import Action, SucceedCommandAction, ResetTipsAction, get_state_updates
from ..commands import (
Command,
LoadLabwareResult,
)
from ..commands.configuring_common import PipetteConfigUpdateResultMixin
from ..actions import Action, ResetTipsAction, get_state_updates

from opentrons.hardware_control.nozzle_manager import NozzleMap

Expand Down Expand Up @@ -66,43 +61,24 @@ def handle_action(self, action: Action) -> None:
for state_update in get_state_updates(action):
self._handle_state_update(state_update)

if isinstance(action, SucceedCommandAction):
if isinstance(action.private_result, PipetteConfigUpdateResultMixin):
pipette_id = action.private_result.pipette_id
config = action.private_result.config
self._state.pipette_info_by_pipette_id[pipette_id] = _PipetteInfo(
channels=config.channels,
active_channels=config.channels,
nozzle_map=config.nozzle_map,
)

self._handle_succeeded_command(action.command)

elif isinstance(action, ResetTipsAction):
if isinstance(action, ResetTipsAction):
labware_id = action.labware_id

for well_name in self._state.tips_by_labware_id[labware_id].keys():
self._state.tips_by_labware_id[labware_id][
well_name
] = TipRackWellState.CLEAN

def _handle_succeeded_command(self, command: Command) -> None:
if (
isinstance(command.result, LoadLabwareResult)
and command.result.definition.parameters.isTiprack
):
labware_id = command.result.labwareId
definition = command.result.definition
self._state.tips_by_labware_id[labware_id] = {
well_name: TipRackWellState.CLEAN
for column in definition.ordering
for well_name in column
}
self._state.column_by_labware_id[labware_id] = [
column for column in definition.ordering
]

def _handle_state_update(self, state_update: update_types.StateUpdate) -> None:
if state_update.pipette_config != update_types.NO_CHANGE:
self._state.pipette_info_by_pipette_id[
state_update.pipette_config.pipette_id
] = _PipetteInfo(
channels=state_update.pipette_config.config.channels,
active_channels=state_update.pipette_config.config.channels,
nozzle_map=state_update.pipette_config.config.nozzle_map,
)

if state_update.tips_used != update_types.NO_CHANGE:
self._set_used_tips(
pipette_id=state_update.tips_used.pipette_id,
Expand All @@ -119,6 +95,19 @@ def _handle_state_update(self, state_update: update_types.StateUpdate) -> None:
)
pipette_info.nozzle_map = state_update.pipette_nozzle_map.nozzle_map

if state_update.loaded_labware != update_types.NO_CHANGE:
labware_id = state_update.loaded_labware.labware_id
definition = state_update.loaded_labware.definition
if definition.parameters.isTiprack:
self._state.tips_by_labware_id[labware_id] = {
well_name: TipRackWellState.CLEAN
for column in definition.ordering
for well_name in column
}
self._state.column_by_labware_id[labware_id] = [
column for column in definition.ordering
]

def _set_used_tips( # noqa: C901
self, pipette_id: str, well_name: str, labware_id: str
) -> None:
Expand Down
19 changes: 10 additions & 9 deletions api/src/opentrons/protocol_runner/legacy_command_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,14 @@ def _map_instrument_load(
result=pe_commands.LoadPipetteResult.construct(pipetteId=pipette_id),
)
serial = instrument_load_info.pipette_dict.get("pipette_id", None) or ""
pipette_config_result = pe_commands.LoadPipettePrivateResult(
state_update = StateUpdate()
state_update.set_load_pipette(
pipette_id=pipette_id,
mount=succeeded_command.params.mount,
pipette_name=succeeded_command.params.pipetteName,
liquid_presence_detection=succeeded_command.params.liquidPresenceDetection,
)
state_update.update_pipette_config(
pipette_id=pipette_id,
serial_number=serial,
config=pipette_data_provider.get_pipette_static_config(
Expand All @@ -754,16 +761,10 @@ def _map_instrument_load(
# We just set this above, so we know it's not None.
started_at=succeeded_command.startedAt, # type: ignore[arg-type]
)
state_update = StateUpdate()
state_update.set_load_pipette(
pipette_id=pipette_id,
mount=succeeded_command.params.mount,
pipette_name=succeeded_command.params.pipetteName,
liquid_presence_detection=succeeded_command.params.liquidPresenceDetection,
)

succeed_action = pe_actions.SucceedCommandAction(
command=succeeded_command,
private_result=pipette_config_result,
private_result=None,
state_update=state_update,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from opentrons.protocol_engine.commands.configure_for_volume import (
ConfigureForVolumeParams,
ConfigureForVolumeResult,
ConfigureForVolumePrivateResult,
ConfigureForVolumeImplementation,
)
from opentrons_shared_data.pipette.types import PipetteNameType
Expand Down Expand Up @@ -85,9 +84,7 @@ async def test_configure_for_volume_implementation(

assert result == SuccessData(
public=ConfigureForVolumeResult(),
private=ConfigureForVolumePrivateResult(
pipette_id="pipette-id", serial_number="some number", config=config
),
private=None,
state_update=StateUpdate(
pipette_config=PipetteConfigUpdate(
pipette_id="pipette-id", serial_number="some number", config=config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from opentrons.protocol_engine.commands.load_pipette import (
LoadPipetteParams,
LoadPipetteResult,
LoadPipettePrivateResult,
LoadPipetteImplementation,
)
from ..pipette_fixtures import get_default_nozzle_map
Expand Down Expand Up @@ -90,9 +89,7 @@ async def test_load_pipette_implementation(

assert result == SuccessData(
public=LoadPipetteResult(pipetteId="some id"),
private=LoadPipettePrivateResult(
pipette_id="some id", serial_number="some-serial-number", config=config_data
),
private=None,
state_update=StateUpdate(
loaded_pipette=LoadPipetteUpdate(
pipette_name=PipetteNameType.P300_SINGLE,
Expand Down Expand Up @@ -158,9 +155,7 @@ async def test_load_pipette_implementation_96_channel(

assert result == SuccessData(
public=LoadPipetteResult(pipetteId="pipette-id"),
private=LoadPipettePrivateResult(
pipette_id="pipette-id", serial_number="some id", config=config_data
),
private=None,
state_update=StateUpdate(
loaded_pipette=LoadPipetteUpdate(
pipette_name=PipetteNameType.P1000_96,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -638,13 +638,10 @@ def test_add_pipette_config(
pipette_lld_settings={},
)

private_result = cmd.LoadPipettePrivateResult(
pipette_id="pipette-id", serial_number="pipette-serial", config=config
)
subject.handle_action(
SucceedCommandAction(
command=command,
private_result=private_result,
private_result=None,
state_update=update_types.StateUpdate(
pipette_config=update_types.PipetteConfigUpdate(
pipette_id="pipette-id",
Expand Down
Loading

0 comments on commit f16d3fb

Please sign in to comment.