Skip to content

Commit

Permalink
use LabwareDefinition instead of labware id
Browse files Browse the repository at this point in the history
validate wavelengths for analysis
update max height to 16mm and clean up
  • Loading branch information
vegano1 committed Nov 1, 2024
1 parent f05e9ba commit a950f15
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 26 deletions.
29 changes: 28 additions & 1 deletion api/src/opentrons/protocol_api/core/engine/module_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,34 @@ def initialize(
"Cannot perform Initialize action on Absorbance Reader without calling `.close_lid()` first."
)

# TODO: check that the wavelengths are within the supported wavelengths
wavelength_len = len(wavelengths)
if mode == "single" and wavelength_len != 1:
raise ValueError(
f"Single mode can only be initialized with 1 wavelength"
f" {wavelength_len} wavelengths provided instead."
)

if mode == "multi" and (wavelength_len < 1 or wavelength_len > 6):
raise ValueError(
f"Multi mode can only be initialized with 1 - 6 wavelengths."
f" {wavelength_len} wavelengths provided instead."
)

if reference_wavelength is not None and (
reference_wavelength < 350 or reference_wavelength > 1000
):
raise ValueError(
f"Unsupported reference wavelength: ({reference_wavelength}) needs"
f" to between 350 and 1000 nm."
)

for wavelength in wavelengths:
if not isinstance(wavelength, int) or wavelength < 350 or wavelength > 1000:
raise ValueError(
f"Unsupported sample wavelength: ({wavelength}) needs"
f" to between 350 and 1000 nm."
)

self._engine_client.execute_command(
cmd.absorbance_reader.InitializeParams(
moduleId=self.module_id,
Expand Down
4 changes: 2 additions & 2 deletions api/src/opentrons/protocol_engine/commands/load_labware.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,12 @@ async def execute(
top_labware_definition=loaded_labware.definition,
bottom_labware_id=verified_location.labwareId,
)
# Labware needs to be 15mm or less to fit into the absorbance reader
# Validate labware for the absorbance reader
elif isinstance(params.location, ModuleLocation):
module = self._state_view.modules.get(params.location.moduleId)
if module is not None and module.model == ModuleModel.ABSORBANCE_READER_V1:
self._state_view.labware.raise_if_labware_incompatible_with_plate_reader(
loaded_labware.labware_id
loaded_labware.definition
)

return SuccessData(
Expand Down
4 changes: 2 additions & 2 deletions api/src/opentrons/protocol_engine/commands/move_labware.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,12 @@ async def execute(self, params: MoveLabwareParams) -> _ExecuteReturn: # noqa: C
raise LabwareMovementNotAllowedError(
"Cannot move a labware onto itself."
)
# Labware needs to be 15mm or less to fit into the absorbance reader
# Validate labware for the absorbance reader
elif isinstance(available_new_location, ModuleLocation):
module = self._state_view.modules.get(available_new_location.moduleId)
if module is not None and module.model == ModuleModel.ABSORBANCE_READER_V1:
self._state_view.labware.raise_if_labware_incompatible_with_plate_reader(
params.labwareId
current_labware_definition
)

# Allow propagation of ModuleNotLoadedError.
Expand Down
19 changes: 9 additions & 10 deletions api/src/opentrons/protocol_engine/state/labware.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@


# The max height of the labware that can fit in a plate reader
_PLATE_READER_MAX_LABWARE_Z_MM = 15
_PLATE_READER_MAX_LABWARE_Z_MM = 16


class LabwareLoadParams(NamedTuple):
Expand Down Expand Up @@ -824,26 +824,25 @@ def raise_if_labware_in_location(

def raise_if_labware_incompatible_with_plate_reader(
self,
labware_id: str,
labware_definition: LabwareDefinition,
) -> None:
"""Raise an error if the labware is not compatible with the plate reader."""
labware_definition = self.get_definition(labware_id)
if labware_definition is not None:
# TODO: (ba, 2024-11-1): the plate reader lid should not be a labware.
load_name = labware_definition.parameters.loadName
if load_name != "opentrons_flex_lid_absorbance_plate_reader_module":
number_of_wells = len(labware_definition.wells)
if number_of_wells != 96:
raise errors.LabwareMovementNotAllowedError(
f"Cannot move '{labware_definition.parameters.loadName}'"
f" into plate reader because the labware contains {number_of_wells}"
f" wells where 96 wells is expected."
f"Cannot move '{load_name}' into plate reader because the"
f" labware contains {number_of_wells} wells where 96 wells is expected."
)
elif (
labware_definition.dimensions.zDimension
> _PLATE_READER_MAX_LABWARE_Z_MM
):
raise errors.LabwareMovementNotAllowedError(
f"Cannot move '{labware_definition.parameters.loadName}'"
f" into plate reader because the maximum allowed labware height"
f" is {_PLATE_READER_MAX_LABWARE_Z_MM}mm."
f"Cannot move '{load_name}' into plate reader because the"
f" maximum allowed labware height is {_PLATE_READER_MAX_LABWARE_Z_MM}mm."
)

def raise_if_labware_cannot_be_stacked( # noqa: C901
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,67 +69,75 @@ def test_initialize(
) -> None:
"""It should set the sample wavelength with the engine client."""
subject._ready_to_initialize = True
subject.initialize("single", [123])
subject.initialize("single", [350])

decoy.verify(
mock_engine_client.execute_command(
cmd.absorbance_reader.InitializeParams(
moduleId="1234",
measureMode="single",
sampleWavelengths=[123],
sampleWavelengths=[350],
referenceWavelength=None,
),
),
times=1,
)
assert subject._initialized_value == [123]
assert subject._initialized_value == [350]

# Test reference wavelength
subject.initialize("single", [124], 450)
subject.initialize("single", [350], 450)

decoy.verify(
mock_engine_client.execute_command(
cmd.absorbance_reader.InitializeParams(
moduleId="1234",
measureMode="single",
sampleWavelengths=[124],
sampleWavelengths=[350],
referenceWavelength=450,
),
),
times=1,
)
assert subject._initialized_value == [124]
assert subject._initialized_value == [250]

# Test initialize multi
subject.initialize("multi", [124, 125, 126])
subject.initialize("multi", [350, 400, 450])

decoy.verify(
mock_engine_client.execute_command(
cmd.absorbance_reader.InitializeParams(
moduleId="1234",
measureMode="multi",
sampleWavelengths=[124, 125, 126],
sampleWavelengths=[350, 400, 450],
referenceWavelength=None,
),
),
times=1,
)
assert subject._initialized_value == [124, 125, 126]
assert subject._initialized_value == [350, 400, 450]


def test_initialize_not_ready(subject: AbsorbanceReaderCore) -> None:
"""It should raise CannotPerformModuleAction if you dont call .close_lid() command."""
subject._ready_to_initialize = False
with pytest.raises(CannotPerformModuleAction):
subject.initialize("single", [123])
subject.initialize("single", [350])


@pytest.mark.parametrize("wavelength", [-350, 0, 1200, "wda"])
def test_invalid_wavelengths(wavelength: int, subject: AbsorbanceReaderCore) -> None:
"""It should raise ValueError if you provide an invalid wavelengthi."""
subject._ready_to_initialize = True
with pytest.raises(ValueError):
subject.initialize("single", [wavelength])


def test_read(
decoy: Decoy, mock_engine_client: EngineClient, subject: AbsorbanceReaderCore
) -> None:
"""It should call absorbance reader to read with the engine client."""
subject._ready_to_initialize = True
subject._initialized_value = [123]
subject._initialized_value = [350]
substate = AbsorbanceReaderSubState(
module_id=AbsorbanceReaderId(subject.module_id),
configured=True,
Expand All @@ -152,6 +160,7 @@ def test_read(
mock_engine_client.execute_command(
cmd.absorbance_reader.ReadAbsorbanceParams(
moduleId="1234",
fileName=None,
),
),
times=1,
Expand Down

0 comments on commit a950f15

Please sign in to comment.