Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(shared-data,api,robot-server): Use new OT-3 deck slot naming style #12571

Merged
merged 74 commits into from
Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
fdcd747
Update OT-3 deck definition IDs to be OT-3-style.
SyntaxColoring Apr 17, 2023
5962e86
Update module definitions to refer to new OT-3 deck IDs.
SyntaxColoring Apr 17, 2023
378b8ce
Remove internal stringification from legacy resolve_module_location().
SyntaxColoring Apr 21, 2023
8298053
Remove meddlesome assertion.
SyntaxColoring Apr 18, 2023
1d468d3
Hack together some canonicalization for load_labware.
SyntaxColoring Apr 21, 2023
1542195
Update command schema.
SyntaxColoring Apr 21, 2023
8fa9f6e
Fix module offset test.
SyntaxColoring Apr 24, 2023
57722e0
Canonicalize loadModule commands.
SyntaxColoring Apr 24, 2023
7832120
canonicalize->normalize
SyntaxColoring May 4, 2023
ae467cb
Add integration test for normalization over HTTP.
SyntaxColoring May 4, 2023
9e80b44
Fix bug in loadModule command normalization.
SyntaxColoring May 4, 2023
7d6c060
Merge branch 'edge' into flex_deck_slot_names
SyntaxColoring May 4, 2023
3f29948
Fix command turning itself into a non-setup command.
SyntaxColoring May 5, 2023
96ec51c
Normalize labware offset requests.
SyntaxColoring May 5, 2023
943960e
Merge branch 'edge' into flex_deck_slot_names
SyntaxColoring May 8, 2023
0a76173
use words more good
SyntaxColoring May 8, 2023
91c7891
by the robot type -> for the robot type
SyntaxColoring May 8, 2023
cf36fc1
Reconcile Jeremy's DeckSlotName changes with mine.
SyntaxColoring May 8, 2023
2c1af00
Add some more internal DeckSlotName documentation.
SyntaxColoring May 8, 2023
e9f5241
Leave todos on Deck methods that look private.
SyntaxColoring May 8, 2023
9117287
Normalize input slot in Deck.get_slot_definition().
jbleon95 May 8, 2023
ebb064c
Move labware offset standardization to a mockable function.
SyntaxColoring May 8, 2023
a3e3492
refactor: Delete a bunch of unused fixtures in test_protocol_engine.py.
SyntaxColoring May 9, 2023
63c2754
Test that ProtocolEngine.add_command() standardizes its input.
SyntaxColoring May 9, 2023
290e326
Start on some command standardization tests.
SyntaxColoring May 9, 2023
affb4fb
Also test ModuleLocations.
SyntaxColoring May 10, 2023
b6f927c
Boundless intelligence.
SyntaxColoring May 10, 2023
6b964e3
Test standardization of loadModule commands.
SyntaxColoring May 10, 2023
dce11e8
Also test off-deck locations.
SyntaxColoring May 10, 2023
db2a1de
Add failing tests for moveLabware standardization.
SyntaxColoring May 10, 2023
301407e
Add todo comment for Thermocycler dodging.
SyntaxColoring May 10, 2023
d5b7ca0
Fix get_edge_path_type() not accounting for OT-3 slots.
SyntaxColoring May 10, 2023
eed2450
Fix fixed trash slot.
SyntaxColoring May 10, 2023
7f16a61
Scaffold command standardization functions.
SyntaxColoring May 10, 2023
3aab9c9
Merge branch 'edge' into flex_deck_slot_names
SyntaxColoring May 18, 2023
cbb9e75
Lint/typecheck fixups.
SyntaxColoring May 18, 2023
05791c4
Update create_protocol_engine() test.
SyntaxColoring May 18, 2023
b5b3520
Work around test_geometry.py depending on legacy Deck class.
SyntaxColoring May 18, 2023
1b46a38
Add docstrings to test_slot_standardization.py.
SyntaxColoring May 18, 2023
ca87322
Extract into free-standing functions; implement for moveLabware.
SyntaxColoring May 18, 2023
248f8df
Docstrings and comments.
SyntaxColoring May 19, 2023
0829f2f
Update DeckDataProvider test.
SyntaxColoring May 19, 2023
165fa95
Revert "Remove internal stringification from legacy resolve_module_lo…
SyntaxColoring May 22, 2023
bf8ea77
Remove vestigial TypeVar from commands.py.
SyntaxColoring May 22, 2023
5e084e4
Undo unnecessary formatting changes.
SyntaxColoring May 22, 2023
d02e385
Fix comment typos.
SyntaxColoring May 22, 2023
a077f54
get_slot_definition(): Be explicit about id stringification.
SyntaxColoring May 22, 2023
b7a2be4
Document module calibration storing slots as an int.
SyntaxColoring May 22, 2023
3dabc07
Remove problematic assert from hardware_testing, and document `slot: …
SyntaxColoring May 22, 2023
37c437e
Add tests and improve documentation for DeckSlotName.
SyntaxColoring May 22, 2023
e675c08
Merge branch 'edge' into flex_deck_slot_names
SyntaxColoring May 22, 2023
a7f2a3f
Only guarantee nice errors if the caller obeys type-checking.
SyntaxColoring May 22, 2023
7631940
Document auto-conversion behavior at the HTTP level.
SyntaxColoring May 23, 2023
d064f1d
Add missing comma.
SyntaxColoring May 23, 2023
fb77c84
Add tests for get_edge_path_type().
SyntaxColoring May 23, 2023
b691461
Add test for get_fixed_trash_slot().
SyntaxColoring May 23, 2023
2410f19
Merge branch 'edge' into flex_deck_slot_names
SyntaxColoring May 25, 2023
f6d8c9d
Explicitly name right-side OT-3 slots.
SyntaxColoring May 25, 2023
177f459
Merge branch 'edge' into flex_deck_slot_names
SyntaxColoring May 26, 2023
15823b3
Merge branch 'edge' into flex_deck_slot_names
SyntaxColoring May 30, 2023
7efb245
Port Tavern test to Python so we can parametrize it over OT-2/OT-3 se…
SyntaxColoring May 30, 2023
f043491
Merge branch 'edge' into flex_deck_slot_names
SyntaxColoring May 31, 2023
4da0510
Leave a bunch of todo comments for hard-coded slots in PE.
SyntaxColoring May 30, 2023
f7a4a2c
Remove todo comment for loading Thermocycler in slot 7.
SyntaxColoring May 31, 2023
a04fcc7
Resolve todo about hard-coded _INSTRUMENT_ATTACH_SLOT.
SyntaxColoring May 31, 2023
f944ff6
Resolve todo for fetching the deck-appropriate middle slot for TC dod…
SyntaxColoring May 31, 2023
746aab4
Update slot pairs for Thermocycler dodging. Close RLAB-339.
SyntaxColoring May 31, 2023
6b9f4f1
Remove todo in LegacyCommandMapper.
SyntaxColoring May 31, 2023
4fc063b
Release dem notes.
SyntaxColoring Jun 1, 2023
14b5ff3
Merge branch 'edge' into flex_deck_slot_names
SyntaxColoring Jun 2, 2023
13560a5
Update expected slots in ReturnTip.test.tsx.
SyntaxColoring Jun 2, 2023
3ac7c46
Update expected slots in PickUpTip.test.tsx.
SyntaxColoring Jun 2, 2023
c9b7f78
Update expected slots in CheckItem.test.tsx.
SyntaxColoring Jun 2, 2023
0c52b1e
Hurl my computer and all peripherals into the ocean
SyntaxColoring Jun 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions api/src/opentrons/protocol_api/core/legacy/deck.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,23 +258,23 @@ def get_slot_center(self, slot_name: str) -> Point:
)

def resolve_module_location(
self, module_type: ModuleType, location: Optional[DeckLocation]
self, module_type: ModuleType, slot_id: Optional[str]
) -> DeckLocation:
dn_from_type = {
ModuleType.MAGNETIC: "Magnetic Module",
ModuleType.THERMOCYCLER: "Thermocycler",
ModuleType.TEMPERATURE: "Temperature Module",
ModuleType.HEATER_SHAKER: "Heater-Shaker",
}
if isinstance(location, str) or isinstance(location, int):
slot_def = self.get_slot_definition(str(location))
if slot_id is not None:
slot_def = self.get_slot_definition(slot_id)
compatible_modules = slot_def["compatibleModuleTypes"]
if module_type.value in compatible_modules:
return location
return slot_id
else:
raise ValueError(
f"A {dn_from_type[module_type]} cannot be loaded"
f" into slot {location}"
f" into slot {slot_id}"
)
else:
valid_slots = [
Expand Down
15 changes: 14 additions & 1 deletion api/src/opentrons/protocol_engine/commands/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
from abc import ABC, abstractmethod
from datetime import datetime
from enum import Enum
from typing import TYPE_CHECKING, Generic, Optional, TypeVar
from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar

from opentrons_shared_data.robot.dev_types import RobotType
from pydantic import BaseModel, Field
from pydantic.generics import GenericModel

Expand Down Expand Up @@ -47,6 +48,13 @@ class CommandIntent(str, Enum):
SETUP = "setup"


# Workaround for no Self type in Python 3.7.
# https://peps.python.org/pep-0673/
BaseCommandCreateSelfT = TypeVar(
"BaseCommandCreateSelfT", bound="BaseCommandCreate[Any]"
)


class BaseCommandCreate(GenericModel, Generic[CommandParamsT]):
"""Base class for command creation requests.

Expand Down Expand Up @@ -85,6 +93,11 @@ class BaseCommandCreate(GenericModel, Generic[CommandParamsT]):
),
)

def normalize(
SyntaxColoring marked this conversation as resolved.
Show resolved Hide resolved
self: BaseCommandCreateSelfT, robot_type: RobotType
) -> BaseCommandCreateSelfT:
return self


class BaseCommand(GenericModel, Generic[CommandParamsT, CommandResultT]):
"""Base command model.
Expand Down
28 changes: 27 additions & 1 deletion api/src/opentrons/protocol_engine/commands/load_labware.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
from typing import TYPE_CHECKING, Optional, Type
from typing_extensions import Literal

from opentrons_shared_data.robot.dev_types import RobotType
from opentrons_shared_data.labware.labware_definition import LabwareDefinition

from ..types import LabwareLocation
from ..types import DeckSlotLocation, LabwareLocation
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate

if TYPE_CHECKING:
Expand All @@ -16,6 +17,17 @@
LoadLabwareCommandType = Literal["loadLabware"]


def canonicalize_location(
SyntaxColoring marked this conversation as resolved.
Show resolved Hide resolved
SyntaxColoring marked this conversation as resolved.
Show resolved Hide resolved
location: LabwareLocation, robot_type: RobotType
) -> LabwareLocation:
if isinstance(location, DeckSlotLocation):
return DeckSlotLocation.construct(
slotName=location.slotName.to_equivalent_by_robot_type(robot_type)
)
else:
return location


class LoadLabwareParams(BaseModel):
"""Payload required to load a labware into a slot."""

Expand Down Expand Up @@ -49,6 +61,16 @@ class LoadLabwareParams(BaseModel):
# TODO: Make sure v6 JSON protocols don't do that.
)

def canonicalize(self, robot_type: RobotType) -> LoadLabwareParams:
SyntaxColoring marked this conversation as resolved.
Show resolved Hide resolved
return LoadLabwareParams.construct(
location=canonicalize_location(self.location, robot_type),
loadName=self.loadName,
namespace=self.namespace,
version=self.version,
labwareId=self.labwareId,
displayName=self.displayName,
)


class LoadLabwareResult(BaseModel):
"""Result data from the execution of a LoadLabware command."""
Expand Down Expand Up @@ -118,3 +140,7 @@ class LoadLabwareCreate(BaseCommandCreate[LoadLabwareParams]):
params: LoadLabwareParams

_CommandCls: Type[LoadLabware] = LoadLabware

def normalize(self, robot_type: RobotType) -> LoadLabwareCreate:
canonicalized_params = self.params.canonicalize(robot_type)
return self.copy(update={"params": canonicalized_params})
17 changes: 17 additions & 0 deletions api/src/opentrons/protocol_engine/commands/load_module.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""Implementation, request models, and response models for the load module command."""
from __future__ import annotations

from typing import TYPE_CHECKING, Optional, Type
from typing_extensions import Literal

from opentrons_shared_data.robot.dev_types import RobotType
from pydantic import BaseModel, Field

from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate
Expand Down Expand Up @@ -54,6 +57,17 @@ class LoadModuleParams(BaseModel):
),
)

def canonicalize(self, robot_type: RobotType) -> LoadModuleParams:
return self.copy(
update={
"location": DeckSlotLocation.construct(
slotName=self.location.slotName.to_equivalent_by_robot_type(
robot_type
)
)
}
)


class LoadModuleResult(BaseModel):
"""The results of loading a module."""
Expand Down Expand Up @@ -138,3 +152,6 @@ class LoadModuleCreate(BaseCommandCreate[LoadModuleParams]):
params: LoadModuleParams

_CommandCls: Type[LoadModule] = LoadModule

def normalize(self, robot_type: RobotType) -> LoadModuleCreate:
return self.copy(update={"params": self.params.canonicalize(robot_type)})
15 changes: 14 additions & 1 deletion api/src/opentrons/protocol_engine/protocol_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ def add_command(self, request: commands.CommandCreate) -> commands.Command:
RunStoppedError: the run has been stopped, so no new commands
may be added.
"""
request = request.normalize(robot_type=self.state_view.config.robot_type)
SyntaxColoring marked this conversation as resolved.
Show resolved Hide resolved

command_id = self._model_utils.generate_id()
request_hash = commands.hash_command_params(
create=request,
Expand Down Expand Up @@ -281,13 +283,24 @@ def add_labware_offset(self, request: LabwareOffsetCreate) -> LabwareOffset:

To retrieve offsets later, see `.state_view.labware`.
"""
normalized_request = request.copy(
SyntaxColoring marked this conversation as resolved.
Show resolved Hide resolved
update={
"location": request.location.copy(
update={
"slotName": request.location.slotName.to_equivalent_by_robot_type(
self.state_view.config.robot_type
)
}
)
}
)
labware_offset_id = self._model_utils.generate_id()
created_at = self._model_utils.get_timestamp()
self._action_dispatcher.dispatch(
AddLabwareOffsetAction(
labware_offset_id=labware_offset_id,
created_at=created_at,
request=request,
request=normalized_request,
)
)
return self.state_view.labware.get_labware_offset(
Expand Down
50 changes: 49 additions & 1 deletion api/src/opentrons/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from math import sqrt, isclose
from typing import TYPE_CHECKING, Any, NamedTuple, Iterable, Union

from opentrons_shared_data.robot.dev_types import RobotType

from .protocols.api_support.labware_like import LabwareLike

if TYPE_CHECKING:
Expand Down Expand Up @@ -223,6 +225,19 @@ class DeckSlotName(enum.Enum):
SLOT_11 = "11"
FIXED_TRASH = "12"

SLOT_A1 = "A1"
SLOT_A2 = "A2"
SLOT_A3 = "A3"
SLOT_B1 = "B1"
SLOT_B2 = "B2"
SLOT_B3 = "B3"
SLOT_C1 = "C1"
SLOT_C2 = "C2"
SLOT_C3 = "C3"
SLOT_D1 = "D1"
SLOT_D2 = "D2"
SLOT_D3 = "D3"

SyntaxColoring marked this conversation as resolved.
Show resolved Hide resolved
@classmethod
def from_primitive(cls, value: DeckLocation) -> DeckSlotName:
str_val = str(value).upper()
Expand All @@ -231,7 +246,19 @@ def from_primitive(cls, value: DeckLocation) -> DeckSlotName:
return cls(str_val)

def as_int(self) -> int:
return int(self.value)
return int(self.to_ot2_equivalent().value)

def to_ot3_equivalent(self) -> DeckSlotName:
return _ot2_to_ot3.get(self, self)

def to_ot2_equivalent(self) -> DeckSlotName:
return _ot3_to_ot2.get(self, self)

def to_equivalent_by_robot_type(self, robot_type: RobotType) -> DeckSlotName:
if robot_type == "OT-2 Standard":
return self.to_ot2_equivalent()
elif robot_type == "OT-3 Standard":
return self.to_ot3_equivalent()

def as_coordinate(self) -> str:
return DECK_SLOT_NAME_TO_COORDINATE[self.value]
Expand All @@ -254,6 +281,27 @@ def __str__(self) -> str:
return self.id


# fmt: off
_slot_equivalencies = [
TamarZanzouri marked this conversation as resolved.
Show resolved Hide resolved
(DeckSlotName.SLOT_1, DeckSlotName.SLOT_D1),
(DeckSlotName.SLOT_2, DeckSlotName.SLOT_D2),
(DeckSlotName.SLOT_3, DeckSlotName.SLOT_D3),
(DeckSlotName.SLOT_4, DeckSlotName.SLOT_C1),
(DeckSlotName.SLOT_5, DeckSlotName.SLOT_C2),
(DeckSlotName.SLOT_6, DeckSlotName.SLOT_C3),
(DeckSlotName.SLOT_7, DeckSlotName.SLOT_B1),
(DeckSlotName.SLOT_8, DeckSlotName.SLOT_B2),
(DeckSlotName.SLOT_9, DeckSlotName.SLOT_B3),
(DeckSlotName.SLOT_10, DeckSlotName.SLOT_A1),
(DeckSlotName.SLOT_11, DeckSlotName.SLOT_A2),
(DeckSlotName.FIXED_TRASH, DeckSlotName.SLOT_A3),
]
# fmt: on

_ot2_to_ot3 = {ot2: ot3 for ot2, ot3 in _slot_equivalencies}
_ot3_to_ot2 = {ot3: ot2 for ot2, ot3 in _slot_equivalencies}


class TransferTipPolicy(enum.Enum):
ONCE = enum.auto()
NEVER = enum.auto()
Expand Down
10 changes: 5 additions & 5 deletions api/tests/opentrons/protocol_engine/state/test_module_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,27 +333,27 @@ def test_get_module_offset_for_ot2_standard(
argvalues=[
(
lazy_fixture("tempdeck_v2_def"),
DeckSlotName.SLOT_1,
DeckSlotName.SLOT_1.to_ot3_equivalent(),
LabwareOffsetVector(x=0, y=0, z=9),
),
(
lazy_fixture("tempdeck_v2_def"),
DeckSlotName.SLOT_3,
DeckSlotName.SLOT_3.to_ot3_equivalent(),
LabwareOffsetVector(x=0, y=0, z=9),
),
(
lazy_fixture("thermocycler_v2_def"),
DeckSlotName.SLOT_7,
DeckSlotName.SLOT_7.to_ot3_equivalent(),
LabwareOffsetVector(x=-20.005, y=67.96, z=0.26),
),
(
lazy_fixture("heater_shaker_v1_def"),
DeckSlotName.SLOT_1,
DeckSlotName.SLOT_1.to_ot3_equivalent(),
LabwareOffsetVector(x=0, y=0, z=18.95),
),
(
lazy_fixture("heater_shaker_v1_def"),
DeckSlotName.SLOT_3,
DeckSlotName.SLOT_3.to_ot3_equivalent(),
LabwareOffsetVector(x=0, y=0, z=18.95),
),
],
Expand Down
Loading