opentrons 8.2.0a4__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.
- 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/config/defaults_ot3.py +1 -0
- 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 +17 -7
- opentrons/hardware_control/backends/ot3controller.py +213 -63
- opentrons/hardware_control/backends/ot3simulator.py +18 -9
- opentrons/hardware_control/backends/ot3utils.py +43 -15
- opentrons/hardware_control/dev_types.py +4 -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 +15 -22
- 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 +23 -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 +60 -23
- 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 +82 -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 +46 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +37 -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 +37 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +158 -44
- 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 +262 -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 +67 -24
- 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 +26 -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 +144 -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.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/METADATA +16 -15
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/RECORD +229 -202
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/WHEEL +1 -1
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/LICENSE +0 -0
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/entry_points.txt +0 -0
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/top_level.txt +0 -0
|
@@ -131,7 +131,7 @@ class LabwareStore(HasState[LabwareState], HandlesActions):
|
|
|
131
131
|
for fixed_labware in deck_fixed_labware
|
|
132
132
|
}
|
|
133
133
|
labware_by_id = {
|
|
134
|
-
fixed_labware.labware_id: LoadedLabware.
|
|
134
|
+
fixed_labware.labware_id: LoadedLabware.model_construct(
|
|
135
135
|
id=fixed_labware.labware_id,
|
|
136
136
|
location=fixed_labware.location,
|
|
137
137
|
loadName=fixed_labware.definition.parameters.loadName,
|
|
@@ -156,10 +156,12 @@ class LabwareStore(HasState[LabwareState], HandlesActions):
|
|
|
156
156
|
"""Modify state in reaction to an action."""
|
|
157
157
|
for state_update in get_state_updates(action):
|
|
158
158
|
self._add_loaded_labware(state_update)
|
|
159
|
+
self._add_loaded_lid_stack(state_update)
|
|
159
160
|
self._set_labware_location(state_update)
|
|
161
|
+
self._set_labware_lid(state_update)
|
|
160
162
|
|
|
161
163
|
if isinstance(action, AddLabwareOffsetAction):
|
|
162
|
-
labware_offset = LabwareOffset.
|
|
164
|
+
labware_offset = LabwareOffset.model_construct(
|
|
163
165
|
id=action.labware_offset_id,
|
|
164
166
|
createdAt=action.created_at,
|
|
165
167
|
definitionUri=action.request.definitionUri,
|
|
@@ -212,7 +214,7 @@ class LabwareStore(HasState[LabwareState], HandlesActions):
|
|
|
212
214
|
|
|
213
215
|
self._state.labware_by_id[
|
|
214
216
|
loaded_labware_update.labware_id
|
|
215
|
-
] = LoadedLabware.
|
|
217
|
+
] = LoadedLabware.model_construct(
|
|
216
218
|
id=loaded_labware_update.labware_id,
|
|
217
219
|
location=location,
|
|
218
220
|
loadName=loaded_labware_update.definition.parameters.loadName,
|
|
@@ -221,6 +223,63 @@ class LabwareStore(HasState[LabwareState], HandlesActions):
|
|
|
221
223
|
displayName=display_name,
|
|
222
224
|
)
|
|
223
225
|
|
|
226
|
+
def _add_loaded_lid_stack(self, state_update: update_types.StateUpdate) -> None:
|
|
227
|
+
loaded_lid_stack_update = state_update.loaded_lid_stack
|
|
228
|
+
if loaded_lid_stack_update != update_types.NO_CHANGE:
|
|
229
|
+
# Add the stack object
|
|
230
|
+
stack_definition_uri = uri_from_details(
|
|
231
|
+
namespace=loaded_lid_stack_update.stack_object_definition.namespace,
|
|
232
|
+
load_name=loaded_lid_stack_update.stack_object_definition.parameters.loadName,
|
|
233
|
+
version=loaded_lid_stack_update.stack_object_definition.version,
|
|
234
|
+
)
|
|
235
|
+
self.state.definitions_by_uri[
|
|
236
|
+
stack_definition_uri
|
|
237
|
+
] = loaded_lid_stack_update.stack_object_definition
|
|
238
|
+
self._state.labware_by_id[
|
|
239
|
+
loaded_lid_stack_update.stack_id
|
|
240
|
+
] = LoadedLabware.construct(
|
|
241
|
+
id=loaded_lid_stack_update.stack_id,
|
|
242
|
+
location=loaded_lid_stack_update.stack_location,
|
|
243
|
+
loadName=loaded_lid_stack_update.stack_object_definition.parameters.loadName,
|
|
244
|
+
definitionUri=stack_definition_uri,
|
|
245
|
+
offsetId=None,
|
|
246
|
+
displayName=None,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# Add the Lids on top of the stack object
|
|
250
|
+
for i in range(len(loaded_lid_stack_update.labware_ids)):
|
|
251
|
+
definition_uri = uri_from_details(
|
|
252
|
+
namespace=loaded_lid_stack_update.definition.namespace,
|
|
253
|
+
load_name=loaded_lid_stack_update.definition.parameters.loadName,
|
|
254
|
+
version=loaded_lid_stack_update.definition.version,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
self._state.definitions_by_uri[
|
|
258
|
+
definition_uri
|
|
259
|
+
] = loaded_lid_stack_update.definition
|
|
260
|
+
|
|
261
|
+
location = loaded_lid_stack_update.new_locations_by_id[
|
|
262
|
+
loaded_lid_stack_update.labware_ids[i]
|
|
263
|
+
]
|
|
264
|
+
|
|
265
|
+
self._state.labware_by_id[
|
|
266
|
+
loaded_lid_stack_update.labware_ids[i]
|
|
267
|
+
] = LoadedLabware.construct(
|
|
268
|
+
id=loaded_lid_stack_update.labware_ids[i],
|
|
269
|
+
location=location,
|
|
270
|
+
loadName=loaded_lid_stack_update.definition.parameters.loadName,
|
|
271
|
+
definitionUri=definition_uri,
|
|
272
|
+
offsetId=None,
|
|
273
|
+
displayName=None,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
def _set_labware_lid(self, state_update: update_types.StateUpdate) -> None:
|
|
277
|
+
labware_lid_update = state_update.labware_lid
|
|
278
|
+
if labware_lid_update != update_types.NO_CHANGE:
|
|
279
|
+
parent_labware_id = labware_lid_update.parent_labware_id
|
|
280
|
+
lid_id = labware_lid_update.lid_id
|
|
281
|
+
self._state.labware_by_id[parent_labware_id].lid_id = lid_id
|
|
282
|
+
|
|
224
283
|
def _set_labware_location(self, state_update: update_types.StateUpdate) -> None:
|
|
225
284
|
labware_location_update = state_update.labware_location
|
|
226
285
|
if labware_location_update != update_types.NO_CHANGE:
|
|
@@ -244,7 +303,7 @@ class LabwareStore(HasState[LabwareState], HandlesActions):
|
|
|
244
303
|
self._state.labware_by_id[labware_id].location = new_location
|
|
245
304
|
|
|
246
305
|
|
|
247
|
-
class LabwareView
|
|
306
|
+
class LabwareView:
|
|
248
307
|
"""Read-only labware state view."""
|
|
249
308
|
|
|
250
309
|
_state: LabwareState
|
|
@@ -268,7 +327,7 @@ class LabwareView(HasState[LabwareState]):
|
|
|
268
327
|
|
|
269
328
|
def get_id_by_module(self, module_id: str) -> str:
|
|
270
329
|
"""Return the ID of the labware loaded on the given module."""
|
|
271
|
-
for labware_id, labware in self.
|
|
330
|
+
for labware_id, labware in self._state.labware_by_id.items():
|
|
272
331
|
if (
|
|
273
332
|
isinstance(labware.location, ModuleLocation)
|
|
274
333
|
and labware.location.moduleId == module_id
|
|
@@ -281,7 +340,7 @@ class LabwareView(HasState[LabwareState]):
|
|
|
281
340
|
|
|
282
341
|
def get_id_by_labware(self, labware_id: str) -> str:
|
|
283
342
|
"""Return the ID of the labware loaded on the given labware."""
|
|
284
|
-
for labware in self.
|
|
343
|
+
for labware in self._state.labware_by_id.values():
|
|
285
344
|
if (
|
|
286
345
|
isinstance(labware.location, OnLabwareLocation)
|
|
287
346
|
and labware.location.labwareId == labware_id
|
|
@@ -441,21 +500,7 @@ class LabwareView(HasState[LabwareState]):
|
|
|
441
500
|
|
|
442
501
|
If not defined within a labware, defaults to one.
|
|
443
502
|
"""
|
|
444
|
-
|
|
445
|
-
"stackingMaxFive": 5,
|
|
446
|
-
"stackingMaxFour": 4,
|
|
447
|
-
"stackingMaxThree": 3,
|
|
448
|
-
"stackingMaxTwo": 2,
|
|
449
|
-
"stackingMaxOne": 1,
|
|
450
|
-
"stackingMaxZero": 0,
|
|
451
|
-
}
|
|
452
|
-
for quirk in stacking_quirks.keys():
|
|
453
|
-
if (
|
|
454
|
-
labware.parameters.quirks is not None
|
|
455
|
-
and quirk in labware.parameters.quirks
|
|
456
|
-
):
|
|
457
|
-
return stacking_quirks[quirk]
|
|
458
|
-
return 1
|
|
503
|
+
return labware.stackLimit if labware.stackLimit is not None else 1
|
|
459
504
|
|
|
460
505
|
def get_should_center_pipette_on_target_well(self, labware_id: str) -> bool:
|
|
461
506
|
"""True if a pipette moving to a well of this labware should center its body on the target.
|
|
@@ -815,6 +860,11 @@ class LabwareView(HasState[LabwareState]):
|
|
|
815
860
|
return self.raise_if_labware_inaccessible_by_pipette(
|
|
816
861
|
labware_location.labwareId
|
|
817
862
|
)
|
|
863
|
+
elif labware.lid_id is not None:
|
|
864
|
+
raise errors.LocationNotAccessibleByPipetteError(
|
|
865
|
+
f"Cannot move pipette to {labware.loadName} "
|
|
866
|
+
"because labware is currently covered by a lid."
|
|
867
|
+
)
|
|
818
868
|
elif isinstance(labware_location, AddressableAreaLocation):
|
|
819
869
|
if fixture_validation.is_staging_slot(labware_location.addressableAreaName):
|
|
820
870
|
raise errors.LocationNotAccessibleByPipetteError(
|
|
@@ -998,11 +1048,15 @@ class LabwareView(HasState[LabwareState]):
|
|
|
998
1048
|
return None
|
|
999
1049
|
else:
|
|
1000
1050
|
return LabwareMovementOffsetData(
|
|
1001
|
-
pickUpOffset=
|
|
1002
|
-
|
|
1051
|
+
pickUpOffset=LabwareOffsetVector.model_construct(
|
|
1052
|
+
x=parsed_offsets[offset_key].pickUpOffset.x,
|
|
1053
|
+
y=parsed_offsets[offset_key].pickUpOffset.y,
|
|
1054
|
+
z=parsed_offsets[offset_key].pickUpOffset.z,
|
|
1003
1055
|
),
|
|
1004
|
-
dropOffset=
|
|
1005
|
-
|
|
1056
|
+
dropOffset=LabwareOffsetVector.model_construct(
|
|
1057
|
+
x=parsed_offsets[offset_key].dropOffset.x,
|
|
1058
|
+
y=parsed_offsets[offset_key].dropOffset.y,
|
|
1059
|
+
z=parsed_offsets[offset_key].dropOffset.z,
|
|
1006
1060
|
),
|
|
1007
1061
|
)
|
|
1008
1062
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""A data store of liquid classes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import dataclasses
|
|
6
|
+
from typing import Dict
|
|
7
|
+
from typing_extensions import Optional
|
|
8
|
+
|
|
9
|
+
from .. import errors
|
|
10
|
+
from ..actions import Action, get_state_updates
|
|
11
|
+
from ..types import LiquidClassRecord
|
|
12
|
+
from . import update_types
|
|
13
|
+
from ._abstract_store import HasState, HandlesActions
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclasses.dataclass
|
|
17
|
+
class LiquidClassState:
|
|
18
|
+
"""Our state is a bidirectional mapping between IDs <-> LiquidClassRecords."""
|
|
19
|
+
|
|
20
|
+
# We use the bidirectional map to see if we've already assigned an ID to a liquid class when the
|
|
21
|
+
# engine is asked to store a new liquid class.
|
|
22
|
+
liquid_class_record_by_id: Dict[str, LiquidClassRecord]
|
|
23
|
+
liquid_class_record_to_id: Dict[LiquidClassRecord, str]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LiquidClassStore(HasState[LiquidClassState], HandlesActions):
|
|
27
|
+
"""Container for LiquidClassState."""
|
|
28
|
+
|
|
29
|
+
_state: LiquidClassState
|
|
30
|
+
|
|
31
|
+
def __init__(self) -> None:
|
|
32
|
+
self._state = LiquidClassState(
|
|
33
|
+
liquid_class_record_by_id={},
|
|
34
|
+
liquid_class_record_to_id={},
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def handle_action(self, action: Action) -> None:
|
|
38
|
+
"""Update the state in response to the action."""
|
|
39
|
+
for state_update in get_state_updates(action):
|
|
40
|
+
if state_update.liquid_class_loaded != update_types.NO_CHANGE:
|
|
41
|
+
self._handle_liquid_class_loaded_update(
|
|
42
|
+
state_update.liquid_class_loaded
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def _handle_liquid_class_loaded_update(
|
|
46
|
+
self, state_update: update_types.LiquidClassLoadedUpdate
|
|
47
|
+
) -> None:
|
|
48
|
+
# We're just a data store. All the validation and ID generation happens in the command implementation.
|
|
49
|
+
self._state.liquid_class_record_by_id[
|
|
50
|
+
state_update.liquid_class_id
|
|
51
|
+
] = state_update.liquid_class_record
|
|
52
|
+
self._state.liquid_class_record_to_id[
|
|
53
|
+
state_update.liquid_class_record
|
|
54
|
+
] = state_update.liquid_class_id
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class LiquidClassView:
|
|
58
|
+
"""Read-only view of the LiquidClassState."""
|
|
59
|
+
|
|
60
|
+
_state: LiquidClassState
|
|
61
|
+
|
|
62
|
+
def __init__(self, state: LiquidClassState) -> None:
|
|
63
|
+
self._state = state
|
|
64
|
+
|
|
65
|
+
def get(self, liquid_class_id: str) -> LiquidClassRecord:
|
|
66
|
+
"""Get the LiquidClassRecord with the given identifier."""
|
|
67
|
+
try:
|
|
68
|
+
return self._state.liquid_class_record_by_id[liquid_class_id]
|
|
69
|
+
except KeyError as e:
|
|
70
|
+
raise errors.LiquidClassDoesNotExistError(
|
|
71
|
+
f"Liquid class ID {liquid_class_id} not found."
|
|
72
|
+
) from e
|
|
73
|
+
|
|
74
|
+
def get_id_for_liquid_class_record(
|
|
75
|
+
self, liquid_class_record: LiquidClassRecord
|
|
76
|
+
) -> Optional[str]:
|
|
77
|
+
"""See if the given LiquidClassRecord if already in the store, and if so, return its identifier."""
|
|
78
|
+
return self._state.liquid_class_record_to_id.get(liquid_class_record)
|
|
79
|
+
|
|
80
|
+
def get_all(self) -> Dict[str, LiquidClassRecord]:
|
|
81
|
+
"""Get all the LiquidClassRecords in the store."""
|
|
82
|
+
return self._state.liquid_class_record_by_id.copy()
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""Basic liquid data state and store."""
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
from typing import Dict, List
|
|
4
|
-
from opentrons.protocol_engine.types import Liquid
|
|
4
|
+
from opentrons.protocol_engine.types import Liquid, LiquidId
|
|
5
5
|
|
|
6
6
|
from ._abstract_store import HasState, HandlesActions
|
|
7
7
|
from ..actions import Action, AddLiquidAction
|
|
8
|
-
from ..errors import LiquidDoesNotExistError
|
|
8
|
+
from ..errors import LiquidDoesNotExistError, InvalidLiquidError
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@dataclass
|
|
@@ -34,7 +34,7 @@ class LiquidStore(HasState[LiquidState], HandlesActions):
|
|
|
34
34
|
self._state.liquids_by_id[action.liquid.id] = action.liquid
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
class LiquidView
|
|
37
|
+
class LiquidView:
|
|
38
38
|
"""Read-only liquid state view."""
|
|
39
39
|
|
|
40
40
|
_state: LiquidState
|
|
@@ -51,11 +51,23 @@ class LiquidView(HasState[LiquidState]):
|
|
|
51
51
|
"""Get all protocol liquids."""
|
|
52
52
|
return list(self._state.liquids_by_id.values())
|
|
53
53
|
|
|
54
|
-
def validate_liquid_id(self, liquid_id:
|
|
54
|
+
def validate_liquid_id(self, liquid_id: LiquidId) -> LiquidId:
|
|
55
55
|
"""Check if liquid_id exists in liquids."""
|
|
56
|
+
is_empty = liquid_id == "EMPTY"
|
|
57
|
+
if is_empty:
|
|
58
|
+
return liquid_id
|
|
56
59
|
has_liquid = liquid_id in self._state.liquids_by_id
|
|
57
60
|
if not has_liquid:
|
|
58
61
|
raise LiquidDoesNotExistError(
|
|
59
62
|
f"Supplied liquidId: {liquid_id} does not exist in the loaded liquids."
|
|
60
63
|
)
|
|
61
64
|
return liquid_id
|
|
65
|
+
|
|
66
|
+
def validate_liquid_allowed(self, liquid: Liquid) -> Liquid:
|
|
67
|
+
"""Validate that a liquid is legal to load."""
|
|
68
|
+
is_empty = liquid.id == "EMPTY"
|
|
69
|
+
if is_empty:
|
|
70
|
+
raise InvalidLiquidError(
|
|
71
|
+
message='Protocols may not define a liquid with the special id "EMPTY".'
|
|
72
|
+
)
|
|
73
|
+
return liquid
|
|
@@ -35,6 +35,7 @@ from opentrons.protocol_engine.state.module_substates.absorbance_reader_substate
|
|
|
35
35
|
AbsorbanceReaderMeasureMode,
|
|
36
36
|
)
|
|
37
37
|
from opentrons.types import DeckSlotName, MountType, StagingSlotName
|
|
38
|
+
from .update_types import AbsorbanceReaderStateUpdate
|
|
38
39
|
from ..errors import ModuleNotConnectedError
|
|
39
40
|
|
|
40
41
|
from ..types import (
|
|
@@ -63,7 +64,6 @@ from ..commands import (
|
|
|
63
64
|
heater_shaker,
|
|
64
65
|
temperature_module,
|
|
65
66
|
thermocycler,
|
|
66
|
-
absorbance_reader,
|
|
67
67
|
)
|
|
68
68
|
from ..actions import (
|
|
69
69
|
Action,
|
|
@@ -296,40 +296,10 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
296
296
|
):
|
|
297
297
|
self._handle_thermocycler_module_commands(command)
|
|
298
298
|
|
|
299
|
-
if isinstance(
|
|
300
|
-
command.result,
|
|
301
|
-
(
|
|
302
|
-
absorbance_reader.InitializeResult,
|
|
303
|
-
absorbance_reader.ReadAbsorbanceResult,
|
|
304
|
-
),
|
|
305
|
-
):
|
|
306
|
-
self._handle_absorbance_reader_commands(command)
|
|
307
|
-
|
|
308
299
|
def _handle_state_update(self, state_update: update_types.StateUpdate) -> None:
|
|
309
|
-
if state_update.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
# Get current values:
|
|
314
|
-
absorbance_reader_substate = self._state.substate_by_module_id[module_id]
|
|
315
|
-
assert isinstance(
|
|
316
|
-
absorbance_reader_substate, AbsorbanceReaderSubState
|
|
317
|
-
), f"{module_id} is not an absorbance plate reader."
|
|
318
|
-
configured = absorbance_reader_substate.configured
|
|
319
|
-
measure_mode = absorbance_reader_substate.measure_mode
|
|
320
|
-
configured_wavelengths = absorbance_reader_substate.configured_wavelengths
|
|
321
|
-
reference_wavelength = absorbance_reader_substate.reference_wavelength
|
|
322
|
-
data = absorbance_reader_substate.data
|
|
323
|
-
|
|
324
|
-
self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState(
|
|
325
|
-
module_id=AbsorbanceReaderId(module_id),
|
|
326
|
-
configured=configured,
|
|
327
|
-
measured=True,
|
|
328
|
-
is_lid_on=is_lid_on,
|
|
329
|
-
measure_mode=measure_mode,
|
|
330
|
-
configured_wavelengths=configured_wavelengths,
|
|
331
|
-
reference_wavelength=reference_wavelength,
|
|
332
|
-
data=data,
|
|
300
|
+
if state_update.absorbance_reader_state_update != update_types.NO_CHANGE:
|
|
301
|
+
self._handle_absorbance_reader_commands(
|
|
302
|
+
state_update.absorbance_reader_state_update
|
|
333
303
|
)
|
|
334
304
|
|
|
335
305
|
def _add_module_substate(
|
|
@@ -589,50 +559,61 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
589
559
|
)
|
|
590
560
|
|
|
591
561
|
def _handle_absorbance_reader_commands(
|
|
592
|
-
self,
|
|
593
|
-
command: Union[
|
|
594
|
-
absorbance_reader.Initialize,
|
|
595
|
-
absorbance_reader.ReadAbsorbance,
|
|
596
|
-
],
|
|
562
|
+
self, absorbance_reader_state_update: AbsorbanceReaderStateUpdate
|
|
597
563
|
) -> None:
|
|
598
|
-
|
|
564
|
+
# Get current values:
|
|
565
|
+
module_id = absorbance_reader_state_update.module_id
|
|
599
566
|
absorbance_reader_substate = self._state.substate_by_module_id[module_id]
|
|
600
567
|
assert isinstance(
|
|
601
568
|
absorbance_reader_substate, AbsorbanceReaderSubState
|
|
602
569
|
), f"{module_id} is not an absorbance plate reader."
|
|
603
|
-
|
|
604
|
-
|
|
570
|
+
is_lid_on = absorbance_reader_substate.is_lid_on
|
|
571
|
+
measured = True
|
|
605
572
|
configured = absorbance_reader_substate.configured
|
|
606
573
|
measure_mode = absorbance_reader_substate.measure_mode
|
|
607
574
|
configured_wavelengths = absorbance_reader_substate.configured_wavelengths
|
|
608
575
|
reference_wavelength = absorbance_reader_substate.reference_wavelength
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
576
|
+
data = absorbance_reader_substate.data
|
|
577
|
+
if (
|
|
578
|
+
absorbance_reader_state_update.absorbance_reader_lid
|
|
579
|
+
!= update_types.NO_CHANGE
|
|
580
|
+
):
|
|
581
|
+
is_lid_on = absorbance_reader_state_update.absorbance_reader_lid.is_lid_on
|
|
582
|
+
elif (
|
|
583
|
+
absorbance_reader_state_update.initialize_absorbance_reader_update
|
|
584
|
+
!= update_types.NO_CHANGE
|
|
585
|
+
):
|
|
586
|
+
configured = True
|
|
587
|
+
measured = False
|
|
588
|
+
is_lid_on = is_lid_on
|
|
589
|
+
measure_mode = AbsorbanceReaderMeasureMode(
|
|
590
|
+
absorbance_reader_state_update.initialize_absorbance_reader_update.measure_mode
|
|
621
591
|
)
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
is_lid_on=is_lid_on,
|
|
628
|
-
measure_mode=measure_mode,
|
|
629
|
-
configured_wavelengths=configured_wavelengths,
|
|
630
|
-
reference_wavelength=reference_wavelength,
|
|
631
|
-
data=command.result.data,
|
|
592
|
+
configured_wavelengths = (
|
|
593
|
+
absorbance_reader_state_update.initialize_absorbance_reader_update.sample_wave_lengths
|
|
594
|
+
)
|
|
595
|
+
reference_wavelength = (
|
|
596
|
+
absorbance_reader_state_update.initialize_absorbance_reader_update.reference_wave_length
|
|
632
597
|
)
|
|
598
|
+
data = None
|
|
599
|
+
elif (
|
|
600
|
+
absorbance_reader_state_update.absorbance_reader_data
|
|
601
|
+
!= update_types.NO_CHANGE
|
|
602
|
+
):
|
|
603
|
+
data = absorbance_reader_state_update.absorbance_reader_data.read_result
|
|
604
|
+
self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState(
|
|
605
|
+
module_id=AbsorbanceReaderId(module_id),
|
|
606
|
+
configured=configured,
|
|
607
|
+
measured=measured,
|
|
608
|
+
is_lid_on=is_lid_on,
|
|
609
|
+
measure_mode=measure_mode,
|
|
610
|
+
configured_wavelengths=configured_wavelengths,
|
|
611
|
+
reference_wavelength=reference_wavelength,
|
|
612
|
+
data=data,
|
|
613
|
+
)
|
|
633
614
|
|
|
634
615
|
|
|
635
|
-
class ModuleView
|
|
616
|
+
class ModuleView:
|
|
636
617
|
"""Read-only view of computed module state."""
|
|
637
618
|
|
|
638
619
|
_state: ModuleState
|
|
@@ -654,7 +635,7 @@ class ModuleView(HasState[ModuleState]):
|
|
|
654
635
|
DeckSlotLocation(slotName=slot_name) if slot_name is not None else None
|
|
655
636
|
)
|
|
656
637
|
|
|
657
|
-
return LoadedModule.
|
|
638
|
+
return LoadedModule.model_construct(
|
|
658
639
|
id=module_id,
|
|
659
640
|
location=location,
|
|
660
641
|
model=attached_module.definition.model,
|
|
@@ -860,8 +841,8 @@ class ModuleView(HasState[ModuleState]):
|
|
|
860
841
|
Labware Position Check offset.
|
|
861
842
|
"""
|
|
862
843
|
if (
|
|
863
|
-
self.
|
|
864
|
-
or self.
|
|
844
|
+
self._state.deck_type == DeckType.OT2_STANDARD
|
|
845
|
+
or self._state.deck_type == DeckType.OT2_SHORT_TRASH
|
|
865
846
|
):
|
|
866
847
|
definition = self.get_definition(module_id)
|
|
867
848
|
slot = self.get_location(module_id).slotName.id
|
|
@@ -908,7 +889,7 @@ class ModuleView(HasState[ModuleState]):
|
|
|
908
889
|
"Module location invalid for nominal module offset calculation."
|
|
909
890
|
)
|
|
910
891
|
module_addressable_area = self.ensure_and_convert_module_fixture_location(
|
|
911
|
-
location,
|
|
892
|
+
location, module.model
|
|
912
893
|
)
|
|
913
894
|
module_addressable_area_position = (
|
|
914
895
|
addressable_areas.get_addressable_area_offsets_from_cutout(
|
|
@@ -1281,13 +1262,14 @@ class ModuleView(HasState[ModuleState]):
|
|
|
1281
1262
|
def ensure_and_convert_module_fixture_location(
|
|
1282
1263
|
self,
|
|
1283
1264
|
deck_slot: DeckSlotName,
|
|
1284
|
-
deck_type: DeckType,
|
|
1285
1265
|
model: ModuleModel,
|
|
1286
1266
|
) -> str:
|
|
1287
1267
|
"""Ensure module fixture load location is valid.
|
|
1288
1268
|
|
|
1289
1269
|
Also, convert the deck slot to a valid module fixture addressable area.
|
|
1290
1270
|
"""
|
|
1271
|
+
deck_type = self._state.deck_type
|
|
1272
|
+
|
|
1291
1273
|
if deck_type == DeckType.OT2_STANDARD or deck_type == DeckType.OT2_SHORT_TRASH:
|
|
1292
1274
|
raise ValueError(
|
|
1293
1275
|
f"Invalid Deck Type: {deck_type.name} - Does not support modules as fixtures."
|
|
@@ -327,6 +327,7 @@ class MotionView:
|
|
|
327
327
|
labware_id: str,
|
|
328
328
|
well_name: str,
|
|
329
329
|
center_point: Point,
|
|
330
|
+
mm_from_edge: float = 0,
|
|
330
331
|
radius: float = 1.0,
|
|
331
332
|
) -> List[motion_planning.Waypoint]:
|
|
332
333
|
"""Get a list of touch points for a touch tip operation."""
|
|
@@ -346,7 +347,11 @@ class MotionView:
|
|
|
346
347
|
)
|
|
347
348
|
|
|
348
349
|
positions = _move_types.get_edge_point_list(
|
|
349
|
-
center_point,
|
|
350
|
+
center=center_point,
|
|
351
|
+
x_radius=x_offset,
|
|
352
|
+
y_radius=y_offset,
|
|
353
|
+
mm_from_edge=mm_from_edge,
|
|
354
|
+
edge_path_type=edge_path_type,
|
|
350
355
|
)
|
|
351
356
|
critical_point: Optional[CriticalPoint] = None
|
|
352
357
|
|