opentrons 8.3.0a0__py2.py3-none-any.whl → 8.3.0a1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of opentrons might be problematic. Click here for more details.
- opentrons/calibration_storage/deck_configuration.py +3 -3
- opentrons/calibration_storage/file_operators.py +3 -3
- opentrons/calibration_storage/helpers.py +3 -1
- opentrons/calibration_storage/ot2/models/v1.py +16 -29
- opentrons/calibration_storage/ot2/tip_length.py +7 -4
- opentrons/calibration_storage/ot3/models/v1.py +14 -23
- opentrons/cli/analyze.py +18 -6
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/errors.py +16 -3
- opentrons/drivers/asyncio/communication/serial_connection.py +24 -9
- opentrons/drivers/command_builder.py +2 -2
- opentrons/drivers/flex_stacker/__init__.py +9 -0
- opentrons/drivers/flex_stacker/abstract.py +89 -0
- opentrons/drivers/flex_stacker/driver.py +260 -0
- opentrons/drivers/flex_stacker/simulator.py +109 -0
- opentrons/drivers/flex_stacker/types.py +138 -0
- opentrons/drivers/heater_shaker/driver.py +18 -3
- opentrons/drivers/temp_deck/driver.py +13 -3
- opentrons/drivers/thermocycler/driver.py +17 -3
- opentrons/execute.py +3 -1
- opentrons/hardware_control/__init__.py +1 -2
- opentrons/hardware_control/api.py +28 -20
- opentrons/hardware_control/backends/flex_protocol.py +4 -6
- opentrons/hardware_control/backends/ot3controller.py +177 -59
- opentrons/hardware_control/backends/ot3simulator.py +10 -8
- opentrons/hardware_control/backends/ot3utils.py +3 -13
- opentrons/hardware_control/dev_types.py +2 -0
- opentrons/hardware_control/emulation/heater_shaker.py +4 -0
- opentrons/hardware_control/emulation/module_server/client.py +1 -1
- opentrons/hardware_control/emulation/module_server/server.py +5 -3
- opentrons/hardware_control/emulation/settings.py +3 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +2 -1
- opentrons/hardware_control/instruments/ot2/pipette.py +9 -21
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +8 -1
- opentrons/hardware_control/instruments/ot3/gripper.py +2 -2
- opentrons/hardware_control/instruments/ot3/pipette.py +13 -22
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -1
- opentrons/hardware_control/modules/mod_abc.py +2 -2
- opentrons/hardware_control/motion_utilities.py +68 -0
- opentrons/hardware_control/nozzle_manager.py +39 -41
- opentrons/hardware_control/ot3_calibration.py +1 -1
- opentrons/hardware_control/ot3api.py +34 -22
- opentrons/hardware_control/protocols/gripper_controller.py +3 -0
- opentrons/hardware_control/protocols/hardware_manager.py +5 -1
- opentrons/hardware_control/protocols/liquid_handler.py +18 -0
- opentrons/hardware_control/protocols/motion_controller.py +6 -0
- opentrons/hardware_control/robot_calibration.py +1 -1
- opentrons/hardware_control/types.py +61 -0
- opentrons/protocol_api/__init__.py +20 -1
- opentrons/protocol_api/_liquid.py +24 -49
- opentrons/protocol_api/_liquid_properties.py +754 -0
- opentrons/protocol_api/_types.py +24 -0
- opentrons/protocol_api/core/common.py +2 -0
- opentrons/protocol_api/core/engine/instrument.py +67 -10
- opentrons/protocol_api/core/engine/labware.py +29 -7
- opentrons/protocol_api/core/engine/protocol.py +130 -5
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/well.py +4 -1
- opentrons/protocol_api/core/instrument.py +42 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +32 -1
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +145 -43
- opentrons/protocol_api/labware.py +231 -7
- opentrons/protocol_api/module_contexts.py +21 -17
- opentrons/protocol_api/protocol_context.py +125 -4
- opentrons/protocol_api/robot_context.py +204 -32
- opentrons/protocol_api/validation.py +261 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/actions.py +2 -3
- opentrons/protocol_engine/clients/sync_client.py +18 -0
- opentrons/protocol_engine/commands/__init__.py +81 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +0 -2
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +19 -5
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +0 -1
- opentrons/protocol_engine/commands/absorbance_reader/read.py +32 -9
- opentrons/protocol_engine/commands/air_gap_in_place.py +160 -0
- opentrons/protocol_engine/commands/aspirate.py +103 -53
- opentrons/protocol_engine/commands/aspirate_in_place.py +55 -51
- opentrons/protocol_engine/commands/blow_out.py +44 -39
- opentrons/protocol_engine/commands/blow_out_in_place.py +21 -32
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +13 -6
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +1 -1
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +3 -3
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +1 -1
- opentrons/protocol_engine/commands/command.py +73 -66
- opentrons/protocol_engine/commands/command_unions.py +101 -1
- opentrons/protocol_engine/commands/comment.py +1 -1
- opentrons/protocol_engine/commands/configure_for_volume.py +10 -3
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +6 -4
- opentrons/protocol_engine/commands/custom.py +6 -12
- opentrons/protocol_engine/commands/dispense.py +82 -48
- opentrons/protocol_engine/commands/dispense_in_place.py +71 -51
- opentrons/protocol_engine/commands/drop_tip.py +52 -31
- opentrons/protocol_engine/commands/drop_tip_in_place.py +13 -3
- opentrons/protocol_engine/commands/generate_command_schema.py +4 -11
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/home.py +13 -4
- opentrons/protocol_engine/commands/liquid_probe.py +60 -25
- opentrons/protocol_engine/commands/load_labware.py +29 -7
- opentrons/protocol_engine/commands/load_lid.py +146 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +189 -0
- opentrons/protocol_engine/commands/load_liquid.py +12 -4
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +31 -10
- opentrons/protocol_engine/commands/load_pipette.py +19 -8
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +1 -1
- opentrons/protocol_engine/commands/magnetic_module/engage.py +1 -1
- opentrons/protocol_engine/commands/move_labware.py +19 -6
- opentrons/protocol_engine/commands/move_relative.py +35 -25
- opentrons/protocol_engine/commands/move_to_addressable_area.py +40 -27
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +53 -32
- opentrons/protocol_engine/commands/move_to_coordinates.py +36 -22
- opentrons/protocol_engine/commands/move_to_well.py +40 -24
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +49 -27
- opentrons/protocol_engine/commands/pipetting_common.py +169 -87
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +24 -33
- opentrons/protocol_engine/commands/reload_labware.py +1 -1
- opentrons/protocol_engine/commands/retract_axis.py +1 -1
- opentrons/protocol_engine/commands/robot/__init__.py +69 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +77 -0
- opentrons/protocol_engine/commands/save_position.py +14 -5
- opentrons/protocol_engine/commands/set_rail_lights.py +1 -1
- opentrons/protocol_engine/commands/set_status_bar.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +8 -2
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +9 -3
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +11 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/touch_tip.py +65 -16
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +1 -4
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -4
- opentrons/protocol_engine/commands/verify_tip_presence.py +11 -4
- opentrons/protocol_engine/commands/wait_for_duration.py +10 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +10 -3
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/error_occurrence.py +19 -20
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +73 -5
- opentrons/protocol_engine/execution/gantry_mover.py +364 -8
- opentrons/protocol_engine/execution/movement.py +27 -0
- opentrons/protocol_engine/execution/pipetting.py +5 -1
- opentrons/protocol_engine/execution/tip_handler.py +4 -6
- opentrons/protocol_engine/notes/notes.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +7 -6
- opentrons/protocol_engine/resources/labware_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_validation.py +5 -0
- opentrons/protocol_engine/resources/module_data_provider.py +1 -1
- opentrons/protocol_engine/resources/pipette_data_provider.py +12 -0
- opentrons/protocol_engine/slot_standardization.py +9 -9
- opentrons/protocol_engine/state/_move_types.py +9 -5
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +25 -61
- opentrons/protocol_engine/state/command_history.py +12 -0
- opentrons/protocol_engine/state/commands.py +17 -13
- opentrons/protocol_engine/state/files.py +10 -12
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/frustum_helpers.py +57 -32
- opentrons/protocol_engine/state/geometry.py +47 -1
- opentrons/protocol_engine/state/labware.py +79 -25
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +16 -4
- opentrons/protocol_engine/state/modules.py +52 -70
- opentrons/protocol_engine/state/motion.py +6 -1
- opentrons/protocol_engine/state/pipettes.py +135 -58
- opentrons/protocol_engine/state/state.py +21 -2
- opentrons/protocol_engine/state/state_summary.py +4 -2
- opentrons/protocol_engine/state/tips.py +11 -44
- opentrons/protocol_engine/state/update_types.py +343 -48
- opentrons/protocol_engine/state/wells.py +19 -11
- opentrons/protocol_engine/types.py +176 -28
- opentrons/protocol_reader/extract_labware_definitions.py +5 -2
- opentrons/protocol_reader/file_format_validator.py +5 -5
- opentrons/protocol_runner/json_file_reader.py +9 -3
- opentrons/protocol_runner/json_translator.py +51 -25
- opentrons/protocol_runner/legacy_command_mapper.py +66 -64
- opentrons/protocol_runner/protocol_runner.py +35 -4
- opentrons/protocol_runner/python_protocol_wrappers.py +1 -1
- opentrons/protocol_runner/run_orchestrator.py +13 -3
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +1 -1
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +56 -0
- opentrons/protocols/advanced_control/{transfers.py → transfers/transfer.py} +10 -85
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +1 -1
- opentrons/protocols/api_support/util.py +10 -0
- opentrons/protocols/labware.py +39 -6
- opentrons/protocols/models/json_protocol.py +5 -9
- opentrons/simulate.py +3 -1
- opentrons/types.py +162 -2
- opentrons/util/logging_config.py +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/METADATA +16 -15
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/RECORD +228 -201
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/WHEEL +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/LICENSE +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/top_level.txt +0 -0
|
@@ -11,7 +11,7 @@ from typing import (
|
|
|
11
11
|
NamedTuple,
|
|
12
12
|
TYPE_CHECKING,
|
|
13
13
|
)
|
|
14
|
-
|
|
14
|
+
from math import isinf, isnan
|
|
15
15
|
from typing_extensions import TypeGuard
|
|
16
16
|
|
|
17
17
|
from opentrons_shared_data.labware.labware_definition import LabwareRole
|
|
@@ -21,7 +21,16 @@ from opentrons_shared_data.robot.types import RobotType
|
|
|
21
21
|
from opentrons.protocols.api_support.types import APIVersion, ThermocyclerStep
|
|
22
22
|
from opentrons.protocols.api_support.util import APIVersionError
|
|
23
23
|
from opentrons.protocols.models import LabwareDefinition
|
|
24
|
-
from opentrons.
|
|
24
|
+
from opentrons.protocols.advanced_control.transfers.common import TransferTipPolicyV2
|
|
25
|
+
from opentrons.types import (
|
|
26
|
+
Mount,
|
|
27
|
+
DeckSlotName,
|
|
28
|
+
StagingSlotName,
|
|
29
|
+
Location,
|
|
30
|
+
AxisType,
|
|
31
|
+
AxisMapType,
|
|
32
|
+
StringAxisMap,
|
|
33
|
+
)
|
|
25
34
|
from opentrons.hardware_control.modules.types import (
|
|
26
35
|
ModuleModel,
|
|
27
36
|
MagneticModuleModel,
|
|
@@ -44,6 +53,9 @@ _COORDINATE_DECK_LABEL_VERSION_GATE = APIVersion(2, 15)
|
|
|
44
53
|
# The first APIVersion where Python protocols can specify staging deck slots (e.g. "D4")
|
|
45
54
|
_STAGING_DECK_SLOT_VERSION_GATE = APIVersion(2, 16)
|
|
46
55
|
|
|
56
|
+
# The first APIVersion where Python protocols can load lids as stacks and treat them as attributes of a parent labware.
|
|
57
|
+
LID_STACK_VERSION_GATE = APIVersion(2, 23)
|
|
58
|
+
|
|
47
59
|
# Mapping of public Python Protocol API pipette load names
|
|
48
60
|
# to names used by the internal Opentrons system
|
|
49
61
|
_PIPETTE_NAMES_MAP = {
|
|
@@ -65,6 +77,7 @@ _PIPETTE_NAMES_MAP = {
|
|
|
65
77
|
"flex_8channel_1000": PipetteNameType.P1000_MULTI_FLEX,
|
|
66
78
|
"flex_8channel_1000_em": PipetteNameType.P1000_MULTI_EM,
|
|
67
79
|
"flex_96channel_1000": PipetteNameType.P1000_96,
|
|
80
|
+
"flex_96channel_200": PipetteNameType.P200_96,
|
|
68
81
|
}
|
|
69
82
|
|
|
70
83
|
|
|
@@ -76,6 +89,14 @@ class PipetteMountTypeError(TypeError):
|
|
|
76
89
|
"""An error raised when an invalid mount type is used for loading pipettes."""
|
|
77
90
|
|
|
78
91
|
|
|
92
|
+
class InstrumentMountTypeError(TypeError):
|
|
93
|
+
"""An error raised when an invalid mount type is used for any available instruments."""
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class IncorrectAxisError(TypeError):
|
|
97
|
+
"""An error raised when an invalid axis key is provided in an axis map."""
|
|
98
|
+
|
|
99
|
+
|
|
79
100
|
class LabwareDefinitionIsNotAdapterError(ValueError):
|
|
80
101
|
"""An error raised when an adapter is attempted to be loaded as a labware."""
|
|
81
102
|
|
|
@@ -96,7 +117,7 @@ def ensure_mount_for_pipette(
|
|
|
96
117
|
mount: Union[str, Mount, None], pipette: PipetteNameType
|
|
97
118
|
) -> Mount:
|
|
98
119
|
"""Ensure that an input value represents a valid mount, and is valid for the given pipette."""
|
|
99
|
-
if pipette
|
|
120
|
+
if pipette in [PipetteNameType.P1000_96, PipetteNameType.P200_96]:
|
|
100
121
|
# Always validate the raw mount input, even if the pipette is a 96-channel and we're not going
|
|
101
122
|
# to use the mount value.
|
|
102
123
|
if mount is not None:
|
|
@@ -147,6 +168,25 @@ def _ensure_mount(mount: Union[str, Mount]) -> Mount:
|
|
|
147
168
|
)
|
|
148
169
|
|
|
149
170
|
|
|
171
|
+
def ensure_instrument_mount(mount: Union[str, Mount]) -> Mount:
|
|
172
|
+
"""Ensure that an input value represents a valid Mount for all instruments."""
|
|
173
|
+
if isinstance(mount, Mount):
|
|
174
|
+
return mount
|
|
175
|
+
|
|
176
|
+
if isinstance(mount, str):
|
|
177
|
+
if mount == "gripper":
|
|
178
|
+
# TODO (lc 08-02-2024) We should decide on the user facing name for
|
|
179
|
+
# the gripper mount axis.
|
|
180
|
+
mount = "extension"
|
|
181
|
+
try:
|
|
182
|
+
return Mount[mount.upper()]
|
|
183
|
+
except KeyError as e:
|
|
184
|
+
raise InstrumentMountTypeError(
|
|
185
|
+
"If mount is specified as a string, it must be 'left', 'right', 'gripper', or 'extension';"
|
|
186
|
+
f" instead, {mount} was given."
|
|
187
|
+
) from e
|
|
188
|
+
|
|
189
|
+
|
|
150
190
|
def ensure_pipette_name(pipette_name: str) -> PipetteNameType:
|
|
151
191
|
"""Ensure that an input value represents a valid pipette name."""
|
|
152
192
|
pipette_name = ensure_lowercase_name(pipette_name)
|
|
@@ -159,6 +199,79 @@ def ensure_pipette_name(pipette_name: str) -> PipetteNameType:
|
|
|
159
199
|
) from None
|
|
160
200
|
|
|
161
201
|
|
|
202
|
+
def _check_ot2_axis_type(
|
|
203
|
+
robot_type: RobotType, axis_map_keys: Union[List[str], List[AxisType]]
|
|
204
|
+
) -> None:
|
|
205
|
+
if robot_type == "OT-2 Standard" and isinstance(axis_map_keys[0], AxisType):
|
|
206
|
+
if any(k not in AxisType.ot2_axes() for k in axis_map_keys):
|
|
207
|
+
raise IncorrectAxisError(
|
|
208
|
+
f"An OT-2 Robot only accepts the following axes {AxisType.ot2_axes()}"
|
|
209
|
+
)
|
|
210
|
+
if robot_type == "OT-2 Standard" and isinstance(axis_map_keys[0], str):
|
|
211
|
+
if any(k.upper() not in [axis.value for axis in AxisType.ot2_axes()] for k in axis_map_keys): # type: ignore [union-attr]
|
|
212
|
+
raise IncorrectAxisError(
|
|
213
|
+
f"An OT-2 Robot only accepts the following axes {AxisType.ot2_axes()}"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _check_96_channel_axis_type(
|
|
218
|
+
is_96_channel: bool, axis_map_keys: Union[List[str], List[AxisType]]
|
|
219
|
+
) -> None:
|
|
220
|
+
if is_96_channel and any(
|
|
221
|
+
key_variation in axis_map_keys for key_variation in ["Z_R", "z_r", AxisType.Z_R]
|
|
222
|
+
):
|
|
223
|
+
raise IncorrectAxisError(
|
|
224
|
+
"A 96 channel is attached. You cannot move the `Z_R` mount."
|
|
225
|
+
)
|
|
226
|
+
if not is_96_channel and any(
|
|
227
|
+
key_variation in axis_map_keys for key_variation in ["Q", "q", AxisType.Q]
|
|
228
|
+
):
|
|
229
|
+
raise IncorrectAxisError(
|
|
230
|
+
"A 96 channel is not attached. The clamp `Q` motor does not exist."
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def ensure_axis_map_type(
|
|
235
|
+
axis_map: Union[AxisMapType, StringAxisMap],
|
|
236
|
+
robot_type: RobotType,
|
|
237
|
+
is_96_channel: bool = False,
|
|
238
|
+
) -> AxisMapType:
|
|
239
|
+
"""Ensure that the axis map provided is in the correct shape and contains the correct keys."""
|
|
240
|
+
axis_map_keys: Union[List[str], List[AxisType]] = list(axis_map.keys()) # type: ignore
|
|
241
|
+
key_type = set(type(k) for k in axis_map_keys)
|
|
242
|
+
|
|
243
|
+
if len(key_type) > 1:
|
|
244
|
+
raise IncorrectAxisError(
|
|
245
|
+
"Please provide an `axis_map` with only string or only AxisType keys."
|
|
246
|
+
)
|
|
247
|
+
_check_ot2_axis_type(robot_type, axis_map_keys)
|
|
248
|
+
_check_96_channel_axis_type(is_96_channel, axis_map_keys)
|
|
249
|
+
|
|
250
|
+
if all(isinstance(k, AxisType) for k in axis_map_keys):
|
|
251
|
+
return_map: AxisMapType = axis_map # type: ignore
|
|
252
|
+
return return_map
|
|
253
|
+
try:
|
|
254
|
+
return {AxisType[k.upper()]: v for k, v in axis_map.items()} # type: ignore [union-attr]
|
|
255
|
+
except KeyError as e:
|
|
256
|
+
raise IncorrectAxisError(f"{e} is not a supported `AxisMapType`")
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def ensure_only_gantry_axis_map_type(
|
|
260
|
+
axis_map: AxisMapType, robot_type: RobotType
|
|
261
|
+
) -> None:
|
|
262
|
+
"""Ensure that the axis map provided is in the correct shape and matches the gantry axes for the robot."""
|
|
263
|
+
if robot_type == "OT-2 Standard":
|
|
264
|
+
if any(k not in AxisType.ot2_gantry_axes() for k in axis_map.keys()):
|
|
265
|
+
raise IncorrectAxisError(
|
|
266
|
+
f"A critical point only accepts OT-2 gantry axes which are {AxisType.ot2_gantry_axes()}"
|
|
267
|
+
)
|
|
268
|
+
else:
|
|
269
|
+
if any(k not in AxisType.flex_gantry_axes() for k in axis_map.keys()):
|
|
270
|
+
raise IncorrectAxisError(
|
|
271
|
+
f"A critical point only accepts Flex gantry axes which are {AxisType.flex_gantry_axes()}"
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
|
|
162
275
|
# TODO(jbl 11-17-2023) this function's original purpose was ensure a valid deck slot for a given robot type
|
|
163
276
|
# With deck configuration, the shape of this should change to better represent it checking if a deck slot
|
|
164
277
|
# (and maybe any addressable area) being valid for that deck configuration
|
|
@@ -254,6 +367,27 @@ def ensure_definition_is_labware(definition: LabwareDefinition) -> None:
|
|
|
254
367
|
)
|
|
255
368
|
|
|
256
369
|
|
|
370
|
+
def ensure_definition_is_lid(definition: LabwareDefinition) -> None:
|
|
371
|
+
"""Ensure that one of the definition's allowed roles is `lid` or that that field is empty."""
|
|
372
|
+
if LabwareRole.lid not in definition.allowedRoles:
|
|
373
|
+
raise LabwareDefinitionIsNotLabwareError(
|
|
374
|
+
f"Labware {definition.parameters.loadName} is not a lid."
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def ensure_definition_is_not_lid_after_api_version(
|
|
379
|
+
api_version: APIVersion, definition: LabwareDefinition
|
|
380
|
+
) -> None:
|
|
381
|
+
"""Ensure that one of the definition's allowed roles is not `lid` or that the API Version is below the release where lid loading was seperated."""
|
|
382
|
+
if (
|
|
383
|
+
LabwareRole.lid in definition.allowedRoles
|
|
384
|
+
and api_version >= LID_STACK_VERSION_GATE
|
|
385
|
+
):
|
|
386
|
+
raise APIVersionError(
|
|
387
|
+
f"Labware Lids cannot be loaded like standard labware in Protocols written with an API version greater than {LID_STACK_VERSION_GATE}."
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
|
|
257
391
|
_MODULE_ALIASES: Dict[str, ModuleModel] = {
|
|
258
392
|
"magdeck": MagneticModuleModel.MAGNETIC_V1,
|
|
259
393
|
"magnetic module": MagneticModuleModel.MAGNETIC_V1,
|
|
@@ -484,3 +618,127 @@ def validate_location(
|
|
|
484
618
|
if well is not None
|
|
485
619
|
else PointTarget(location=target_location, in_place=in_place)
|
|
486
620
|
)
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
def ensure_boolean(value: bool) -> bool:
|
|
624
|
+
"""Ensure value is a boolean."""
|
|
625
|
+
if not isinstance(value, bool):
|
|
626
|
+
raise ValueError("Value must be a boolean.")
|
|
627
|
+
return value
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
def ensure_float(value: Union[int, float]) -> float:
|
|
631
|
+
"""Ensure value is a float (or an integer) and return it as a float."""
|
|
632
|
+
if not isinstance(value, (int, float)):
|
|
633
|
+
raise ValueError("Value must be a floating point number.")
|
|
634
|
+
return float(value)
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
def ensure_positive_float(value: Union[int, float]) -> float:
|
|
638
|
+
"""Ensure value is a positive and real float value."""
|
|
639
|
+
float_value = ensure_float(value)
|
|
640
|
+
if isnan(float_value) or isinf(float_value):
|
|
641
|
+
raise ValueError("Value must be a defined, non-infinite number.")
|
|
642
|
+
if float_value < 0:
|
|
643
|
+
raise ValueError("Value must be a positive float.")
|
|
644
|
+
return float_value
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
def ensure_positive_int(value: int) -> int:
|
|
648
|
+
"""Ensure value is a positive integer."""
|
|
649
|
+
if not isinstance(value, int):
|
|
650
|
+
raise ValueError("Value must be an integer.")
|
|
651
|
+
if value < 0:
|
|
652
|
+
raise ValueError("Value must be a positive integer.")
|
|
653
|
+
return value
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
def validate_coordinates(value: Sequence[float]) -> Tuple[float, float, float]:
|
|
657
|
+
"""Ensure value is a valid sequence of 3 floats and return a tuple of 3 floats."""
|
|
658
|
+
if len(value) != 3:
|
|
659
|
+
raise ValueError("Coordinates must be a sequence of exactly three numbers")
|
|
660
|
+
if not all(isinstance(v, (float, int)) for v in value):
|
|
661
|
+
raise ValueError("All values in coordinates must be floats.")
|
|
662
|
+
return float(value[0]), float(value[1]), float(value[2])
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
def ensure_new_tip_policy(value: str) -> TransferTipPolicyV2:
|
|
666
|
+
"""Ensure that new_tip value is a valid TransferTipPolicy value."""
|
|
667
|
+
try:
|
|
668
|
+
return TransferTipPolicyV2(value.lower())
|
|
669
|
+
except ValueError:
|
|
670
|
+
raise ValueError(
|
|
671
|
+
f"'{value}' is invalid value for 'new_tip'."
|
|
672
|
+
f" Acceptable value is either 'never', 'once', 'always' or 'per source'."
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def _verify_each_list_element_is_valid_location(locations: Sequence[Well]) -> None:
|
|
677
|
+
from .labware import Well
|
|
678
|
+
|
|
679
|
+
for loc in locations:
|
|
680
|
+
if not isinstance(loc, Well):
|
|
681
|
+
raise ValueError(
|
|
682
|
+
f"'{loc}' is not a valid location for transfer."
|
|
683
|
+
f" Location should be a well instance."
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
def ensure_valid_flat_wells_list_for_transfer_v2(
|
|
688
|
+
target: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
689
|
+
) -> List[Well]:
|
|
690
|
+
"""Ensure that the given target(s) for a liquid transfer are valid and in a flat list."""
|
|
691
|
+
from .labware import Well
|
|
692
|
+
|
|
693
|
+
if isinstance(target, Well):
|
|
694
|
+
return [target]
|
|
695
|
+
|
|
696
|
+
if isinstance(target, (list, tuple)):
|
|
697
|
+
if len(target) == 0:
|
|
698
|
+
raise ValueError("No target well(s) specified for transfer.")
|
|
699
|
+
if isinstance(target[0], (list, tuple)):
|
|
700
|
+
for sub_sequence in target:
|
|
701
|
+
_verify_each_list_element_is_valid_location(sub_sequence)
|
|
702
|
+
return [loc for sub_sequence in target for loc in sub_sequence]
|
|
703
|
+
else:
|
|
704
|
+
_verify_each_list_element_is_valid_location(target)
|
|
705
|
+
return list(target)
|
|
706
|
+
else:
|
|
707
|
+
raise ValueError(
|
|
708
|
+
f"'{target}' is not a valid location for transfer."
|
|
709
|
+
f" Location should be a well instance, or a 1-dimensional or"
|
|
710
|
+
f" 2-dimensional sequence of well instances."
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def ensure_valid_tip_drop_location_for_transfer_v2(
|
|
715
|
+
tip_drop_location: Union[Location, Well, TrashBin, WasteChute]
|
|
716
|
+
) -> Union[Location, Well, TrashBin, WasteChute]:
|
|
717
|
+
"""Ensure that the tip drop location is valid for v2 transfer."""
|
|
718
|
+
from .labware import Well
|
|
719
|
+
|
|
720
|
+
if (
|
|
721
|
+
isinstance(tip_drop_location, Well)
|
|
722
|
+
or isinstance(tip_drop_location, TrashBin)
|
|
723
|
+
or isinstance(tip_drop_location, WasteChute)
|
|
724
|
+
):
|
|
725
|
+
return tip_drop_location
|
|
726
|
+
elif isinstance(tip_drop_location, Location):
|
|
727
|
+
_, maybe_well = tip_drop_location.labware.get_parent_labware_and_well()
|
|
728
|
+
|
|
729
|
+
if maybe_well is None:
|
|
730
|
+
raise TypeError(
|
|
731
|
+
"If a location is specified as a `types.Location`"
|
|
732
|
+
" (for instance, as the result of a call to `Well.top()`),"
|
|
733
|
+
" it must be a location relative to a well,"
|
|
734
|
+
" since that is where a tip is dropped."
|
|
735
|
+
" However, the given location doesn't refer to any well."
|
|
736
|
+
)
|
|
737
|
+
return tip_drop_location
|
|
738
|
+
else:
|
|
739
|
+
raise TypeError(
|
|
740
|
+
f"If specified, location should be an instance of"
|
|
741
|
+
f" `types.Location` (e.g. the return value from `Well.top()`)"
|
|
742
|
+
f" or `Well` (e.g. `reservoir.wells()[0]`) or an instance of `TrashBin` or `WasteChute`."
|
|
743
|
+
f" However, it is '{tip_drop_location}'."
|
|
744
|
+
)
|
|
@@ -57,6 +57,8 @@ from .types import (
|
|
|
57
57
|
ModuleModel,
|
|
58
58
|
ModuleDefinition,
|
|
59
59
|
Liquid,
|
|
60
|
+
LiquidClassRecord,
|
|
61
|
+
LiquidClassRecordWithId,
|
|
60
62
|
AllNozzleLayoutConfiguration,
|
|
61
63
|
SingleNozzleLayoutConfiguration,
|
|
62
64
|
RowNozzleLayoutConfiguration,
|
|
@@ -122,6 +124,8 @@ __all__ = [
|
|
|
122
124
|
"ModuleModel",
|
|
123
125
|
"ModuleDefinition",
|
|
124
126
|
"Liquid",
|
|
127
|
+
"LiquidClassRecord",
|
|
128
|
+
"LiquidClassRecordWithId",
|
|
125
129
|
"AllNozzleLayoutConfiguration",
|
|
126
130
|
"SingleNozzleLayoutConfiguration",
|
|
127
131
|
"RowNozzleLayoutConfiguration",
|
|
@@ -27,7 +27,6 @@ from ..types import (
|
|
|
27
27
|
ModuleDefinition,
|
|
28
28
|
Liquid,
|
|
29
29
|
DeckConfigurationType,
|
|
30
|
-
AddressableAreaLocation,
|
|
31
30
|
)
|
|
32
31
|
|
|
33
32
|
|
|
@@ -235,12 +234,12 @@ class SetDeckConfigurationAction:
|
|
|
235
234
|
class AddAddressableAreaAction:
|
|
236
235
|
"""Add a single addressable area to state.
|
|
237
236
|
|
|
238
|
-
This differs from the deck configuration in
|
|
237
|
+
This differs from the deck configuration in SetDeckConfigurationAction which
|
|
239
238
|
sends over a mapping of cutout fixtures. This action will only load one addressable
|
|
240
239
|
area and that should be pre-validated before being sent via the action.
|
|
241
240
|
"""
|
|
242
241
|
|
|
243
|
-
|
|
242
|
+
addressable_area_name: str
|
|
244
243
|
|
|
245
244
|
|
|
246
245
|
@dataclasses.dataclass(frozen=True)
|
|
@@ -77,6 +77,18 @@ class SyncClient:
|
|
|
77
77
|
) -> commands.LoadPipetteResult:
|
|
78
78
|
pass
|
|
79
79
|
|
|
80
|
+
@overload
|
|
81
|
+
def execute_command_without_recovery(
|
|
82
|
+
self, params: commands.LoadLidStackParams
|
|
83
|
+
) -> commands.LoadLidStackResult:
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
@overload
|
|
87
|
+
def execute_command_without_recovery(
|
|
88
|
+
self, params: commands.LoadLidParams
|
|
89
|
+
) -> commands.LoadLidResult:
|
|
90
|
+
pass
|
|
91
|
+
|
|
80
92
|
@overload
|
|
81
93
|
def execute_command_without_recovery(
|
|
82
94
|
self, params: commands.LiquidProbeParams
|
|
@@ -89,6 +101,12 @@ class SyncClient:
|
|
|
89
101
|
) -> commands.TryLiquidProbeResult:
|
|
90
102
|
pass
|
|
91
103
|
|
|
104
|
+
@overload
|
|
105
|
+
def execute_command_without_recovery(
|
|
106
|
+
self, params: commands.LoadLiquidClassParams
|
|
107
|
+
) -> commands.LoadLiquidClassResult:
|
|
108
|
+
pass
|
|
109
|
+
|
|
92
110
|
def execute_command_without_recovery(
|
|
93
111
|
self, params: commands.CommandParams
|
|
94
112
|
) -> commands.CommandResult:
|
|
@@ -20,6 +20,7 @@ from . import temperature_module
|
|
|
20
20
|
from . import thermocycler
|
|
21
21
|
from . import calibration
|
|
22
22
|
from . import unsafe
|
|
23
|
+
from . import robot
|
|
23
24
|
|
|
24
25
|
from .hash_command_params import hash_protocol_command_params
|
|
25
26
|
from .generate_command_schema import generate_command_schema
|
|
@@ -34,13 +35,23 @@ from .command import (
|
|
|
34
35
|
|
|
35
36
|
from .command_unions import (
|
|
36
37
|
Command,
|
|
38
|
+
CommandAdapter,
|
|
37
39
|
CommandParams,
|
|
38
40
|
CommandCreate,
|
|
41
|
+
CommandCreateAdapter,
|
|
39
42
|
CommandResult,
|
|
40
43
|
CommandType,
|
|
41
44
|
CommandDefinedErrorData,
|
|
42
45
|
)
|
|
43
46
|
|
|
47
|
+
from .air_gap_in_place import (
|
|
48
|
+
AirGapInPlace,
|
|
49
|
+
AirGapInPlaceParams,
|
|
50
|
+
AirGapInPlaceCreate,
|
|
51
|
+
AirGapInPlaceResult,
|
|
52
|
+
AirGapInPlaceCommandType,
|
|
53
|
+
)
|
|
54
|
+
|
|
44
55
|
from .aspirate import (
|
|
45
56
|
Aspirate,
|
|
46
57
|
AspirateParams,
|
|
@@ -138,6 +149,15 @@ from .load_liquid import (
|
|
|
138
149
|
LoadLiquidImplementation,
|
|
139
150
|
)
|
|
140
151
|
|
|
152
|
+
from .load_liquid_class import (
|
|
153
|
+
LoadLiquidClass,
|
|
154
|
+
LoadLiquidClassParams,
|
|
155
|
+
LoadLiquidClassCreate,
|
|
156
|
+
LoadLiquidClassResult,
|
|
157
|
+
LoadLiquidClassCommandType,
|
|
158
|
+
LoadLiquidClassImplementation,
|
|
159
|
+
)
|
|
160
|
+
|
|
141
161
|
from .load_module import (
|
|
142
162
|
LoadModule,
|
|
143
163
|
LoadModuleParams,
|
|
@@ -154,6 +174,22 @@ from .load_pipette import (
|
|
|
154
174
|
LoadPipetteCommandType,
|
|
155
175
|
)
|
|
156
176
|
|
|
177
|
+
from .load_lid_stack import (
|
|
178
|
+
LoadLidStack,
|
|
179
|
+
LoadLidStackParams,
|
|
180
|
+
LoadLidStackCreate,
|
|
181
|
+
LoadLidStackResult,
|
|
182
|
+
LoadLidStackCommandType,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
from .load_lid import (
|
|
186
|
+
LoadLid,
|
|
187
|
+
LoadLidParams,
|
|
188
|
+
LoadLidCreate,
|
|
189
|
+
LoadLidResult,
|
|
190
|
+
LoadLidCommandType,
|
|
191
|
+
)
|
|
192
|
+
|
|
157
193
|
from .move_labware import (
|
|
158
194
|
MoveLabware,
|
|
159
195
|
MoveLabwareParams,
|
|
@@ -323,6 +359,14 @@ from .verify_tip_presence import (
|
|
|
323
359
|
VerifyTipPresenceCommandType,
|
|
324
360
|
)
|
|
325
361
|
|
|
362
|
+
from .get_next_tip import (
|
|
363
|
+
GetNextTip,
|
|
364
|
+
GetNextTipCreate,
|
|
365
|
+
GetNextTipParams,
|
|
366
|
+
GetNextTipResult,
|
|
367
|
+
GetNextTipCommandType,
|
|
368
|
+
)
|
|
369
|
+
|
|
326
370
|
from .liquid_probe import (
|
|
327
371
|
LiquidProbe,
|
|
328
372
|
LiquidProbeParams,
|
|
@@ -339,8 +383,10 @@ from .liquid_probe import (
|
|
|
339
383
|
__all__ = [
|
|
340
384
|
# command type unions
|
|
341
385
|
"Command",
|
|
386
|
+
"CommandAdapter",
|
|
342
387
|
"CommandParams",
|
|
343
388
|
"CommandCreate",
|
|
389
|
+
"CommandCreateAdapter",
|
|
344
390
|
"CommandResult",
|
|
345
391
|
"CommandType",
|
|
346
392
|
"CommandPrivateResult",
|
|
@@ -355,6 +401,12 @@ __all__ = [
|
|
|
355
401
|
"hash_protocol_command_params",
|
|
356
402
|
# command schema generation
|
|
357
403
|
"generate_command_schema",
|
|
404
|
+
# air gap command models
|
|
405
|
+
"AirGapInPlace",
|
|
406
|
+
"AirGapInPlaceCreate",
|
|
407
|
+
"AirGapInPlaceParams",
|
|
408
|
+
"AirGapInPlaceResult",
|
|
409
|
+
"AirGapInPlaceCommandType",
|
|
358
410
|
# aspirate command models
|
|
359
411
|
"Aspirate",
|
|
360
412
|
"AspirateCreate",
|
|
@@ -440,6 +492,20 @@ __all__ = [
|
|
|
440
492
|
"LoadPipetteResult",
|
|
441
493
|
"LoadPipetteCommandType",
|
|
442
494
|
"LoadPipettePrivateResult",
|
|
495
|
+
# load lid stack command models
|
|
496
|
+
"LoadLidStack",
|
|
497
|
+
"LoadLidStackCreate",
|
|
498
|
+
"LoadLidStackParams",
|
|
499
|
+
"LoadLidStackResult",
|
|
500
|
+
"LoadLidStackCommandType",
|
|
501
|
+
"LoadLidStackPrivateResult",
|
|
502
|
+
# load lid command models
|
|
503
|
+
"LoadLid",
|
|
504
|
+
"LoadLidCreate",
|
|
505
|
+
"LoadLidParams",
|
|
506
|
+
"LoadLidResult",
|
|
507
|
+
"LoadLidCommandType",
|
|
508
|
+
"LoadLidPrivateResult",
|
|
443
509
|
# move labware command models
|
|
444
510
|
"MoveLabware",
|
|
445
511
|
"MoveLabwareCreate",
|
|
@@ -538,6 +604,14 @@ __all__ = [
|
|
|
538
604
|
"LoadLiquidParams",
|
|
539
605
|
"LoadLiquidResult",
|
|
540
606
|
"LoadLiquidCommandType",
|
|
607
|
+
# load liquid class command models
|
|
608
|
+
"LoadLiquidClass",
|
|
609
|
+
"LoadLiquidClassParams",
|
|
610
|
+
"LoadLiquidClassCreate",
|
|
611
|
+
"LoadLiquidClassResult",
|
|
612
|
+
"LoadLiquidClassImplementation",
|
|
613
|
+
"LoadLiquidClassCommandType",
|
|
614
|
+
# hardware control command models
|
|
541
615
|
# hardware module command bundles
|
|
542
616
|
"absorbance_reader",
|
|
543
617
|
"heater_shaker",
|
|
@@ -548,6 +622,7 @@ __all__ = [
|
|
|
548
622
|
"calibration",
|
|
549
623
|
# unsafe command bundle
|
|
550
624
|
"unsafe",
|
|
625
|
+
"robot",
|
|
551
626
|
# configure pipette volume command bundle
|
|
552
627
|
"ConfigureForVolume",
|
|
553
628
|
"ConfigureForVolumeCreate",
|
|
@@ -578,6 +653,12 @@ __all__ = [
|
|
|
578
653
|
"VerifyTipPresenceParams",
|
|
579
654
|
"VerifyTipPresenceResult",
|
|
580
655
|
"VerifyTipPresenceCommandType",
|
|
656
|
+
# get next tip command bundle
|
|
657
|
+
"GetNextTip",
|
|
658
|
+
"GetNextTipCreate",
|
|
659
|
+
"GetNextTipParams",
|
|
660
|
+
"GetNextTipResult",
|
|
661
|
+
"GetNextTipCommandType",
|
|
581
662
|
# liquid probe command bundle
|
|
582
663
|
"LiquidProbe",
|
|
583
664
|
"LiquidProbeParams",
|
|
@@ -60,7 +60,6 @@ class CloseLidImpl(AbstractCommandImpl[CloseLidParams, SuccessData[CloseLidResul
|
|
|
60
60
|
hardware_lid_status = AbsorbanceReaderLidStatus.OFF
|
|
61
61
|
if not self._state_view.config.use_virtual_modules:
|
|
62
62
|
abs_reader = self._equipment.get_module_hardware_api(mod_substate.module_id)
|
|
63
|
-
|
|
64
63
|
if abs_reader is not None:
|
|
65
64
|
hardware_lid_status = await abs_reader.get_current_lid_status()
|
|
66
65
|
else:
|
|
@@ -95,7 +94,6 @@ class CloseLidImpl(AbstractCommandImpl[CloseLidParams, SuccessData[CloseLidResul
|
|
|
95
94
|
deck_slot=self._state_view.modules.get_location(
|
|
96
95
|
params.moduleId
|
|
97
96
|
).slotName,
|
|
98
|
-
deck_type=self._state_view.config.deck_type,
|
|
99
97
|
model=absorbance_model,
|
|
100
98
|
)
|
|
101
99
|
)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""Command models to initialize an Absorbance Reader."""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
-
from typing import List, Optional, Literal, TYPE_CHECKING
|
|
3
|
+
from typing import List, Optional, Literal, TYPE_CHECKING, Any
|
|
4
4
|
from typing_extensions import Type
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel, Field
|
|
7
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
7
8
|
|
|
8
9
|
from opentrons.drivers.types import ABSMeasurementMode
|
|
9
10
|
from opentrons.protocol_engine.types import ABSMeasureMode
|
|
@@ -11,6 +12,7 @@ from opentrons.protocol_engine.types import ABSMeasureMode
|
|
|
11
12
|
from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
12
13
|
from ...errors.error_occurrence import ErrorOccurrence
|
|
13
14
|
from ...errors import InvalidWavelengthError
|
|
15
|
+
from ...state import update_types
|
|
14
16
|
|
|
15
17
|
if TYPE_CHECKING:
|
|
16
18
|
from opentrons.protocol_engine.state.state import StateView
|
|
@@ -20,6 +22,10 @@ if TYPE_CHECKING:
|
|
|
20
22
|
InitializeCommandType = Literal["absorbanceReader/initialize"]
|
|
21
23
|
|
|
22
24
|
|
|
25
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
26
|
+
s.pop("default", None)
|
|
27
|
+
|
|
28
|
+
|
|
23
29
|
class InitializeParams(BaseModel):
|
|
24
30
|
"""Input parameters to initialize an absorbance reading."""
|
|
25
31
|
|
|
@@ -28,8 +34,10 @@ class InitializeParams(BaseModel):
|
|
|
28
34
|
..., description="Initialize single or multi measurement mode."
|
|
29
35
|
)
|
|
30
36
|
sampleWavelengths: List[int] = Field(..., description="Sample wavelengths in nm.")
|
|
31
|
-
referenceWavelength:
|
|
32
|
-
None,
|
|
37
|
+
referenceWavelength: int | SkipJsonSchema[None] = Field(
|
|
38
|
+
None,
|
|
39
|
+
description="Optional reference wavelength in nm.",
|
|
40
|
+
json_schema_extra=_remove_default,
|
|
33
41
|
)
|
|
34
42
|
|
|
35
43
|
|
|
@@ -53,6 +61,7 @@ class InitializeImpl(
|
|
|
53
61
|
|
|
54
62
|
async def execute(self, params: InitializeParams) -> SuccessData[InitializeResult]:
|
|
55
63
|
"""Initiate a single absorbance measurement."""
|
|
64
|
+
state_update = update_types.StateUpdate()
|
|
56
65
|
abs_reader_substate = self._state_view.modules.get_absorbance_reader_substate(
|
|
57
66
|
module_id=params.moduleId
|
|
58
67
|
)
|
|
@@ -113,10 +122,15 @@ class InitializeImpl(
|
|
|
113
122
|
reference_wavelength=params.referenceWavelength,
|
|
114
123
|
)
|
|
115
124
|
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
state_update.initialize_absorbance_reader(
|
|
126
|
+
abs_reader_substate.module_id,
|
|
127
|
+
params.measureMode,
|
|
128
|
+
params.sampleWavelengths,
|
|
129
|
+
params.referenceWavelength,
|
|
118
130
|
)
|
|
119
131
|
|
|
132
|
+
return SuccessData(public=InitializeResult(), state_update=state_update)
|
|
133
|
+
|
|
120
134
|
|
|
121
135
|
class Initialize(BaseCommand[InitializeParams, InitializeResult, ErrorOccurrence]):
|
|
122
136
|
"""A command to initialize an Absorbance Reader."""
|