opentrons 8.3.2__py2.py3-none-any.whl → 8.4.0__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/ot2/mark_bad_calibration.py +2 -0
- opentrons/calibration_storage/ot2/tip_length.py +6 -6
- opentrons/config/advanced_settings.py +9 -11
- opentrons/config/feature_flags.py +0 -4
- opentrons/config/reset.py +7 -2
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/async_serial.py +4 -0
- opentrons/drivers/asyncio/communication/errors.py +41 -8
- opentrons/drivers/asyncio/communication/serial_connection.py +36 -10
- opentrons/drivers/flex_stacker/__init__.py +9 -3
- opentrons/drivers/flex_stacker/abstract.py +140 -15
- opentrons/drivers/flex_stacker/driver.py +593 -47
- opentrons/drivers/flex_stacker/errors.py +64 -0
- opentrons/drivers/flex_stacker/simulator.py +222 -24
- opentrons/drivers/flex_stacker/types.py +211 -15
- opentrons/drivers/flex_stacker/utils.py +19 -0
- opentrons/execute.py +4 -2
- opentrons/hardware_control/api.py +5 -0
- opentrons/hardware_control/backends/flex_protocol.py +4 -0
- opentrons/hardware_control/backends/ot3controller.py +12 -1
- opentrons/hardware_control/backends/ot3simulator.py +3 -0
- opentrons/hardware_control/backends/subsystem_manager.py +8 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +10 -6
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +59 -6
- opentrons/hardware_control/modules/__init__.py +12 -1
- opentrons/hardware_control/modules/absorbance_reader.py +11 -9
- opentrons/hardware_control/modules/flex_stacker.py +498 -0
- opentrons/hardware_control/modules/heater_shaker.py +12 -10
- opentrons/hardware_control/modules/magdeck.py +5 -1
- opentrons/hardware_control/modules/tempdeck.py +5 -1
- opentrons/hardware_control/modules/thermocycler.py +15 -14
- opentrons/hardware_control/modules/types.py +191 -1
- opentrons/hardware_control/modules/utils.py +3 -0
- opentrons/hardware_control/motion_utilities.py +20 -0
- opentrons/hardware_control/ot3api.py +145 -15
- opentrons/hardware_control/protocols/liquid_handler.py +47 -1
- opentrons/hardware_control/types.py +6 -0
- opentrons/legacy_commands/commands.py +102 -5
- opentrons/legacy_commands/helpers.py +74 -1
- opentrons/legacy_commands/types.py +33 -2
- opentrons/protocol_api/__init__.py +2 -0
- opentrons/protocol_api/_liquid.py +39 -8
- opentrons/protocol_api/_liquid_properties.py +20 -19
- opentrons/protocol_api/_transfer_liquid_validation.py +91 -0
- opentrons/protocol_api/core/common.py +3 -1
- opentrons/protocol_api/core/engine/deck_conflict.py +11 -1
- opentrons/protocol_api/core/engine/instrument.py +1356 -107
- opentrons/protocol_api/core/engine/labware.py +8 -4
- opentrons/protocol_api/core/engine/load_labware_params.py +68 -10
- opentrons/protocol_api/core/engine/module_core.py +118 -2
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +6 -14
- opentrons/protocol_api/core/engine/protocol.py +253 -11
- opentrons/protocol_api/core/engine/stringify.py +19 -8
- opentrons/protocol_api/core/engine/transfer_components_executor.py +858 -0
- opentrons/protocol_api/core/engine/well.py +73 -5
- opentrons/protocol_api/core/instrument.py +71 -21
- opentrons/protocol_api/core/labware.py +6 -2
- opentrons/protocol_api/core/legacy/labware_offset_provider.py +7 -3
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +76 -49
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +8 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +36 -0
- opentrons/protocol_api/core/legacy/legacy_well_core.py +27 -2
- opentrons/protocol_api/core/legacy/load_info.py +4 -12
- opentrons/protocol_api/core/legacy/module_geometry.py +6 -1
- opentrons/protocol_api/core/legacy/well_geometry.py +3 -3
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +73 -23
- opentrons/protocol_api/core/module.py +43 -0
- opentrons/protocol_api/core/protocol.py +33 -0
- opentrons/protocol_api/core/well.py +23 -2
- opentrons/protocol_api/instrument_context.py +454 -150
- opentrons/protocol_api/labware.py +98 -50
- opentrons/protocol_api/module_contexts.py +140 -0
- opentrons/protocol_api/protocol_context.py +163 -19
- opentrons/protocol_api/validation.py +51 -41
- opentrons/protocol_engine/__init__.py +21 -2
- opentrons/protocol_engine/actions/actions.py +5 -5
- opentrons/protocol_engine/clients/sync_client.py +6 -0
- opentrons/protocol_engine/commands/__init__.py +66 -36
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +0 -1
- opentrons/protocol_engine/commands/air_gap_in_place.py +3 -2
- opentrons/protocol_engine/commands/aspirate.py +6 -2
- opentrons/protocol_engine/commands/aspirate_in_place.py +3 -1
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +210 -0
- opentrons/protocol_engine/commands/blow_out.py +2 -0
- opentrons/protocol_engine/commands/blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/command_unions.py +102 -33
- opentrons/protocol_engine/commands/configure_for_volume.py +3 -0
- opentrons/protocol_engine/commands/dispense.py +3 -1
- opentrons/protocol_engine/commands/dispense_in_place.py +3 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
- opentrons/protocol_engine/commands/drop_tip.py +23 -1
- opentrons/protocol_engine/commands/flex_stacker/__init__.py +106 -0
- opentrons/protocol_engine/commands/flex_stacker/close_latch.py +72 -0
- opentrons/protocol_engine/commands/flex_stacker/common.py +15 -0
- opentrons/protocol_engine/commands/flex_stacker/empty.py +161 -0
- opentrons/protocol_engine/commands/flex_stacker/fill.py +164 -0
- opentrons/protocol_engine/commands/flex_stacker/open_latch.py +70 -0
- opentrons/protocol_engine/commands/flex_stacker/prepare_shuttle.py +112 -0
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +394 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +190 -0
- opentrons/protocol_engine/commands/flex_stacker/store.py +291 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
- opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
- opentrons/protocol_engine/commands/liquid_probe.py +27 -13
- opentrons/protocol_engine/commands/load_labware.py +42 -39
- opentrons/protocol_engine/commands/load_lid.py +21 -13
- opentrons/protocol_engine/commands/load_lid_stack.py +130 -47
- opentrons/protocol_engine/commands/load_module.py +18 -17
- opentrons/protocol_engine/commands/load_pipette.py +3 -0
- opentrons/protocol_engine/commands/move_labware.py +139 -20
- opentrons/protocol_engine/commands/move_to_well.py +5 -11
- opentrons/protocol_engine/commands/pick_up_tip.py +5 -2
- opentrons/protocol_engine/commands/pipetting_common.py +159 -8
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +15 -5
- opentrons/protocol_engine/commands/{evotip_dispense.py → pressure_dispense.py} +33 -34
- opentrons/protocol_engine/commands/reload_labware.py +6 -19
- opentrons/protocol_engine/commands/{evotip_seal_pipette.py → seal_pipette_to_tip.py} +97 -76
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +6 -1
- opentrons/protocol_engine/commands/{evotip_unseal_pipette.py → unseal_pipette_from_tip.py} +31 -40
- opentrons/protocol_engine/errors/__init__.py +10 -0
- opentrons/protocol_engine/errors/exceptions.py +62 -0
- opentrons/protocol_engine/execution/equipment.py +123 -106
- opentrons/protocol_engine/execution/labware_movement.py +8 -6
- opentrons/protocol_engine/execution/pipetting.py +235 -25
- opentrons/protocol_engine/execution/tip_handler.py +82 -32
- opentrons/protocol_engine/labware_offset_standardization.py +194 -0
- opentrons/protocol_engine/protocol_engine.py +22 -13
- opentrons/protocol_engine/resources/deck_configuration_provider.py +98 -2
- opentrons/protocol_engine/resources/deck_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_data_provider.py +32 -12
- opentrons/protocol_engine/resources/labware_validation.py +7 -5
- opentrons/protocol_engine/slot_standardization.py +11 -23
- opentrons/protocol_engine/state/addressable_areas.py +84 -46
- opentrons/protocol_engine/state/frustum_helpers.py +36 -14
- opentrons/protocol_engine/state/geometry.py +892 -227
- opentrons/protocol_engine/state/labware.py +252 -55
- opentrons/protocol_engine/state/module_substates/__init__.py +4 -0
- opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +68 -0
- opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +22 -0
- opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +13 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +20 -0
- opentrons/protocol_engine/state/modules.py +210 -67
- opentrons/protocol_engine/state/pipettes.py +54 -0
- opentrons/protocol_engine/state/state.py +1 -1
- opentrons/protocol_engine/state/tips.py +14 -0
- opentrons/protocol_engine/state/update_types.py +180 -25
- opentrons/protocol_engine/state/wells.py +55 -9
- opentrons/protocol_engine/types/__init__.py +300 -0
- opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
- opentrons/protocol_engine/types/command_annotations.py +53 -0
- opentrons/protocol_engine/types/deck_configuration.py +72 -0
- opentrons/protocol_engine/types/execution.py +96 -0
- opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
- opentrons/protocol_engine/types/instrument.py +47 -0
- opentrons/protocol_engine/types/instrument_sensors.py +47 -0
- opentrons/protocol_engine/types/labware.py +111 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +111 -0
- opentrons/protocol_engine/types/labware_offset_vector.py +33 -0
- opentrons/protocol_engine/types/liquid.py +40 -0
- opentrons/protocol_engine/types/liquid_class.py +59 -0
- opentrons/protocol_engine/types/liquid_handling.py +13 -0
- opentrons/protocol_engine/types/liquid_level_detection.py +131 -0
- opentrons/protocol_engine/types/location.py +194 -0
- opentrons/protocol_engine/types/module.py +301 -0
- opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
- opentrons/protocol_engine/types/run_time_parameters.py +133 -0
- opentrons/protocol_engine/types/tip.py +18 -0
- opentrons/protocol_engine/types/util.py +21 -0
- opentrons/protocol_engine/types/well_position.py +124 -0
- opentrons/protocol_reader/extract_labware_definitions.py +7 -3
- opentrons/protocol_reader/file_format_validator.py +5 -3
- opentrons/protocol_runner/json_translator.py +4 -2
- opentrons/protocol_runner/legacy_command_mapper.py +6 -2
- opentrons/protocol_runner/run_orchestrator.py +4 -1
- opentrons/protocols/advanced_control/transfers/common.py +48 -1
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +204 -0
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +16 -3
- opentrons/protocols/labware.py +27 -23
- opentrons/protocols/models/__init__.py +0 -21
- opentrons/simulate.py +4 -2
- opentrons/types.py +20 -7
- opentrons/util/logging_config.py +94 -25
- opentrons/util/logging_queue_handler.py +61 -0
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/METADATA +4 -4
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/RECORD +192 -151
- opentrons/calibration_storage/ot2/models/defaults.py +0 -0
- opentrons/calibration_storage/ot3/models/defaults.py +0 -0
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_engine/types.py +0 -1311
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/LICENSE +0 -0
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/WHEEL +0 -0
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import TYPE_CHECKING, List, Union, overload
|
|
2
|
+
from typing import TYPE_CHECKING, List, Sequence, Union, overload
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
from .helpers import
|
|
5
|
+
from .helpers import (
|
|
6
|
+
stringify_location,
|
|
7
|
+
stringify_disposal_location,
|
|
8
|
+
stringify_well_list,
|
|
9
|
+
listify,
|
|
10
|
+
)
|
|
6
11
|
from . import types as command_types
|
|
7
12
|
|
|
8
13
|
from opentrons.types import Location
|
|
9
14
|
from opentrons.protocol_api.disposal_locations import TrashBin, WasteChute
|
|
15
|
+
from opentrons.protocol_api._liquid import LiquidClass
|
|
10
16
|
|
|
11
17
|
if TYPE_CHECKING:
|
|
12
18
|
from opentrons.protocol_api import InstrumentContext
|
|
@@ -234,9 +240,25 @@ def touch_tip(instrument: InstrumentContext) -> command_types.TouchTipCommand:
|
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
|
|
237
|
-
def air_gap(
|
|
238
|
-
|
|
239
|
-
|
|
243
|
+
def air_gap(
|
|
244
|
+
instrument: InstrumentContext,
|
|
245
|
+
volume: float | None,
|
|
246
|
+
height: float | None,
|
|
247
|
+
) -> command_types.AirGapCommand:
|
|
248
|
+
text = (
|
|
249
|
+
"Air gap"
|
|
250
|
+
+ (f" of {volume} uL" if volume is not None else "")
|
|
251
|
+
+ (f" at height {height}" if height is not None else "")
|
|
252
|
+
)
|
|
253
|
+
return {
|
|
254
|
+
"name": command_types.AIR_GAP,
|
|
255
|
+
"payload": {
|
|
256
|
+
"instrument": instrument,
|
|
257
|
+
"volume": volume,
|
|
258
|
+
"height": height,
|
|
259
|
+
"text": text,
|
|
260
|
+
},
|
|
261
|
+
}
|
|
240
262
|
|
|
241
263
|
|
|
242
264
|
def return_tip() -> command_types.ReturnTipCommand:
|
|
@@ -301,6 +323,81 @@ def move_to_disposal_location(
|
|
|
301
323
|
}
|
|
302
324
|
|
|
303
325
|
|
|
326
|
+
def transfer_with_liquid_class(
|
|
327
|
+
instrument: InstrumentContext,
|
|
328
|
+
liquid_class: LiquidClass,
|
|
329
|
+
volume: float,
|
|
330
|
+
source: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
331
|
+
destination: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
332
|
+
) -> command_types.TransferWithLiquidClassCommand:
|
|
333
|
+
text = (
|
|
334
|
+
"Transferring "
|
|
335
|
+
+ f"{volume} uL of {liquid_class.display_name} liquid class from "
|
|
336
|
+
+ f"{stringify_well_list(source)} to {stringify_well_list(destination)}"
|
|
337
|
+
)
|
|
338
|
+
return {
|
|
339
|
+
"name": command_types.TRANSFER_WITH_LIQUID_CLASS,
|
|
340
|
+
"payload": {
|
|
341
|
+
"instrument": instrument,
|
|
342
|
+
"liquid_class": liquid_class,
|
|
343
|
+
"volume": volume,
|
|
344
|
+
"source": source,
|
|
345
|
+
"destination": destination,
|
|
346
|
+
"text": text,
|
|
347
|
+
},
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def distribute_with_liquid_class(
|
|
352
|
+
instrument: InstrumentContext,
|
|
353
|
+
liquid_class: LiquidClass,
|
|
354
|
+
volume: float,
|
|
355
|
+
source: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
356
|
+
destination: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
357
|
+
) -> command_types.DistributeWithLiquidClassCommand:
|
|
358
|
+
text = (
|
|
359
|
+
"Distributing "
|
|
360
|
+
+ f"{volume} uL of {liquid_class.display_name} liquid class from "
|
|
361
|
+
+ f"{stringify_well_list(source)} to {stringify_well_list(destination)}"
|
|
362
|
+
)
|
|
363
|
+
return {
|
|
364
|
+
"name": command_types.DISTRIBUTE_WITH_LIQUID_CLASS,
|
|
365
|
+
"payload": {
|
|
366
|
+
"instrument": instrument,
|
|
367
|
+
"liquid_class": liquid_class,
|
|
368
|
+
"volume": volume,
|
|
369
|
+
"source": source,
|
|
370
|
+
"destination": destination,
|
|
371
|
+
"text": text,
|
|
372
|
+
},
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def consolidate_with_liquid_class(
|
|
377
|
+
instrument: InstrumentContext,
|
|
378
|
+
liquid_class: LiquidClass,
|
|
379
|
+
volume: float,
|
|
380
|
+
source: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
381
|
+
destination: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
382
|
+
) -> command_types.ConsolidateWithLiquidClassCommand:
|
|
383
|
+
text = (
|
|
384
|
+
"Consolidating "
|
|
385
|
+
+ f"{volume} uL of {liquid_class.display_name} liquid class from "
|
|
386
|
+
+ f"{stringify_well_list(source)} to {stringify_well_list(destination)}"
|
|
387
|
+
)
|
|
388
|
+
return {
|
|
389
|
+
"name": command_types.CONSOLIDATE_WITH_LIQUID_CLASS,
|
|
390
|
+
"payload": {
|
|
391
|
+
"instrument": instrument,
|
|
392
|
+
"liquid_class": liquid_class,
|
|
393
|
+
"volume": volume,
|
|
394
|
+
"source": source,
|
|
395
|
+
"destination": destination,
|
|
396
|
+
"text": text,
|
|
397
|
+
},
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
|
|
304
401
|
def seal(
|
|
305
402
|
instrument: InstrumentContext,
|
|
306
403
|
location: Well,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, Union
|
|
1
|
+
from typing import List, Union, Sequence
|
|
2
2
|
|
|
3
3
|
from opentrons.protocol_api.labware import Well, Labware
|
|
4
4
|
from opentrons.protocol_api.module_contexts import ModuleContext
|
|
@@ -48,6 +48,64 @@ def stringify_disposal_location(location: Union[TrashBin, WasteChute]) -> str:
|
|
|
48
48
|
return "Waste Chute"
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
def _group_wells_by_labware(wells: List[Well]) -> List[List[Well]]:
|
|
52
|
+
wells_by_labware: List[List[Well]] = []
|
|
53
|
+
sub_list = []
|
|
54
|
+
active_parent_labware = None
|
|
55
|
+
for well in wells:
|
|
56
|
+
if well.parent == active_parent_labware:
|
|
57
|
+
sub_list.append(well)
|
|
58
|
+
else:
|
|
59
|
+
active_parent_labware = well.parent
|
|
60
|
+
if sub_list:
|
|
61
|
+
wells_by_labware.append(sub_list)
|
|
62
|
+
sub_list = [well]
|
|
63
|
+
if sub_list:
|
|
64
|
+
wells_by_labware.append(sub_list)
|
|
65
|
+
|
|
66
|
+
return wells_by_labware
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _stringify_multiple_wells_for_labware(wells: List[Well]) -> str:
|
|
70
|
+
if len(wells) == 0:
|
|
71
|
+
return ""
|
|
72
|
+
elif len(wells) == 1:
|
|
73
|
+
return str(wells[0])
|
|
74
|
+
# TODO(jbl 2025-04-10) this logic can be improved to more intelligently group wells
|
|
75
|
+
elif len(wells) < 9: # At most we'll print out a full column's worth of well
|
|
76
|
+
return ", ".join([well.well_name for well in wells[:-1]]) + f", {wells[-1]}"
|
|
77
|
+
else: # Otherwise print the first and last three
|
|
78
|
+
return (
|
|
79
|
+
", ".join([well.well_name for well in wells[:3]])
|
|
80
|
+
+ ", ... "
|
|
81
|
+
+ ", ".join([well.well_name for well in wells[-3:-1]])
|
|
82
|
+
+ f", {wells[-1]}"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def stringify_well_list(
|
|
87
|
+
wells: Union[Well, Sequence[Well], Sequence[Sequence[Well]]]
|
|
88
|
+
) -> str:
|
|
89
|
+
"""Takes an arbitrary sequence of wells and returns a string representation of each well, associated by labware."""
|
|
90
|
+
if isinstance(wells, Well):
|
|
91
|
+
well_list = [wells]
|
|
92
|
+
elif len(wells) == 0:
|
|
93
|
+
well_list = []
|
|
94
|
+
elif isinstance(wells, list) and isinstance(wells[0], list):
|
|
95
|
+
well_list = [well for sub_well_list in wells for well in sub_well_list]
|
|
96
|
+
elif isinstance(wells, list):
|
|
97
|
+
well_list = wells
|
|
98
|
+
else:
|
|
99
|
+
return ""
|
|
100
|
+
|
|
101
|
+
return "; ".join(
|
|
102
|
+
[
|
|
103
|
+
_stringify_multiple_wells_for_labware(wells_by_labware)
|
|
104
|
+
for wells_by_labware in _group_wells_by_labware(well_list)
|
|
105
|
+
]
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
51
109
|
def _stringify_labware_movement_location(
|
|
52
110
|
location: Union[
|
|
53
111
|
DeckLocation, OffDeckType, Labware, ModuleContext, WasteChute, TrashBin
|
|
@@ -78,3 +136,18 @@ def stringify_labware_movement_command(
|
|
|
78
136
|
destination_text = _stringify_labware_movement_location(destination)
|
|
79
137
|
gripper_text = " with gripper" if use_gripper else ""
|
|
80
138
|
return f"Moving {source_labware_text} to {destination_text}{gripper_text}"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def stringify_lid_movement_command(
|
|
142
|
+
source: Union[
|
|
143
|
+
DeckLocation, OffDeckType, Labware, ModuleContext, WasteChute, TrashBin
|
|
144
|
+
],
|
|
145
|
+
destination: Union[
|
|
146
|
+
DeckLocation, OffDeckType, Labware, ModuleContext, WasteChute, TrashBin
|
|
147
|
+
],
|
|
148
|
+
use_gripper: bool,
|
|
149
|
+
) -> str:
|
|
150
|
+
source_labware_text = _stringify_labware_movement_location(source)
|
|
151
|
+
destination_text = _stringify_labware_movement_location(destination)
|
|
152
|
+
gripper_text = " with gripper" if use_gripper else ""
|
|
153
|
+
return f"Moving lid from {source_labware_text} to {destination_text}{gripper_text}"
|
|
@@ -8,6 +8,7 @@ if TYPE_CHECKING:
|
|
|
8
8
|
from opentrons.protocol_api import InstrumentContext
|
|
9
9
|
from opentrons.protocol_api.labware import Well
|
|
10
10
|
from opentrons.protocol_api.disposal_locations import TrashBin, WasteChute
|
|
11
|
+
from opentrons.protocol_api._liquid import LiquidClass
|
|
11
12
|
|
|
12
13
|
from opentrons.types import Location
|
|
13
14
|
|
|
@@ -43,6 +44,9 @@ TOUCH_TIP: Final = "command.TOUCH_TIP"
|
|
|
43
44
|
RETURN_TIP: Final = "command.RETURN_TIP"
|
|
44
45
|
MOVE_TO: Final = "command.MOVE_TO"
|
|
45
46
|
MOVE_TO_DISPOSAL_LOCATION: Final = "command.MOVE_TO_DISPOSAL_LOCATION"
|
|
47
|
+
TRANSFER_WITH_LIQUID_CLASS: Final = "command.TRANSFER_WITH_LIQUID_CLASS"
|
|
48
|
+
DISTRIBUTE_WITH_LIQUID_CLASS: Final = "command.DISTRIBUTE_WITH_LIQUID_CLASS"
|
|
49
|
+
CONSOLIDATE_WITH_LIQUID_CLASS: Final = "command.CONSOLIDATE_WITH_LIQUID_CLASS"
|
|
46
50
|
SEAL: Final = "command.SEAL"
|
|
47
51
|
UNSEAL: Final = "command.UNSEAL"
|
|
48
52
|
PRESSURIZE: Final = "command.PRESSURIZE"
|
|
@@ -472,8 +476,9 @@ class TouchTipCommand(TypedDict):
|
|
|
472
476
|
payload: TouchTipCommandPayload
|
|
473
477
|
|
|
474
478
|
|
|
475
|
-
class AirGapCommandPayload(TextOnlyPayload):
|
|
476
|
-
|
|
479
|
+
class AirGapCommandPayload(TextOnlyPayload, SingleInstrumentPayload):
|
|
480
|
+
volume: Union[float, None]
|
|
481
|
+
height: Union[float, None]
|
|
477
482
|
|
|
478
483
|
|
|
479
484
|
class AirGapCommand(TypedDict):
|
|
@@ -539,6 +544,28 @@ class MoveLabwareCommandPayload(TextOnlyPayload):
|
|
|
539
544
|
pass
|
|
540
545
|
|
|
541
546
|
|
|
547
|
+
class LiquidClassCommandPayload(TextOnlyPayload, SingleInstrumentPayload):
|
|
548
|
+
liquid_class: LiquidClass
|
|
549
|
+
volume: float
|
|
550
|
+
source: Union[Well, Sequence[Well], Sequence[Sequence[Well]]]
|
|
551
|
+
destination: Union[Well, Sequence[Well], Sequence[Sequence[Well]]]
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
class TransferWithLiquidClassCommand(TypedDict):
|
|
555
|
+
name: Literal["command.TRANSFER_WITH_LIQUID_CLASS"]
|
|
556
|
+
payload: LiquidClassCommandPayload
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
class DistributeWithLiquidClassCommand(TypedDict):
|
|
560
|
+
name: Literal["command.DISTRIBUTE_WITH_LIQUID_CLASS"]
|
|
561
|
+
payload: LiquidClassCommandPayload
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
class ConsolidateWithLiquidClassCommand(TypedDict):
|
|
565
|
+
name: Literal["command.CONSOLIDATE_WITH_LIQUID_CLASS"]
|
|
566
|
+
payload: LiquidClassCommandPayload
|
|
567
|
+
|
|
568
|
+
|
|
542
569
|
class SealCommandPayload(TextOnlyPayload):
|
|
543
570
|
instrument: InstrumentContext
|
|
544
571
|
location: Union[None, Location, Well]
|
|
@@ -621,6 +648,9 @@ Command = Union[
|
|
|
621
648
|
MoveToCommand,
|
|
622
649
|
MoveToDisposalLocationCommand,
|
|
623
650
|
MoveLabwareCommand,
|
|
651
|
+
TransferWithLiquidClassCommand,
|
|
652
|
+
DistributeWithLiquidClassCommand,
|
|
653
|
+
ConsolidateWithLiquidClassCommand,
|
|
624
654
|
SealCommand,
|
|
625
655
|
UnsealCommand,
|
|
626
656
|
PressurizeCommand,
|
|
@@ -673,6 +703,7 @@ CommandPayload = Union[
|
|
|
673
703
|
MoveToCommandPayload,
|
|
674
704
|
MoveToDisposalLocationCommandPayload,
|
|
675
705
|
MoveLabwareCommandPayload,
|
|
706
|
+
LiquidClassCommandPayload,
|
|
676
707
|
SealCommandPayload,
|
|
677
708
|
UnsealCommandPayload,
|
|
678
709
|
PressurizeCommandPayload,
|
|
@@ -27,6 +27,7 @@ from .module_contexts import (
|
|
|
27
27
|
HeaterShakerContext,
|
|
28
28
|
MagneticBlockContext,
|
|
29
29
|
AbsorbanceReaderContext,
|
|
30
|
+
FlexStackerContext,
|
|
30
31
|
)
|
|
31
32
|
from .disposal_locations import TrashBin, WasteChute
|
|
32
33
|
from ._liquid import Liquid, LiquidClass
|
|
@@ -70,6 +71,7 @@ __all__ = [
|
|
|
70
71
|
"HeaterShakerContext",
|
|
71
72
|
"MagneticBlockContext",
|
|
72
73
|
"AbsorbanceReaderContext",
|
|
74
|
+
"FlexStackerContext",
|
|
73
75
|
"ParameterContext",
|
|
74
76
|
"Labware",
|
|
75
77
|
"TrashBin",
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Optional, Dict
|
|
4
|
+
from typing import Optional, Dict, Union, TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from opentrons_shared_data.liquid_classes.liquid_class_definition import (
|
|
7
7
|
LiquidClassSchemaV1,
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
+
from opentrons.protocols.advanced_control.transfers.common import (
|
|
11
|
+
NoLiquidClassPropertyError,
|
|
12
|
+
)
|
|
13
|
+
|
|
10
14
|
from ._liquid_properties import (
|
|
11
15
|
TransferProperties,
|
|
12
16
|
build_transfer_properties,
|
|
13
17
|
)
|
|
14
18
|
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from . import InstrumentContext, Labware
|
|
21
|
+
|
|
15
22
|
|
|
16
23
|
@dataclass(frozen=True)
|
|
17
24
|
class Liquid:
|
|
@@ -64,18 +71,42 @@ class LiquidClass:
|
|
|
64
71
|
def display_name(self) -> str:
|
|
65
72
|
return self._display_name
|
|
66
73
|
|
|
67
|
-
def get_for(
|
|
74
|
+
def get_for(
|
|
75
|
+
self, pipette: Union[str, InstrumentContext], tip_rack: Union[str, Labware]
|
|
76
|
+
) -> TransferProperties:
|
|
68
77
|
"""Get liquid class transfer properties for the specified pipette and tip."""
|
|
78
|
+
from . import InstrumentContext, Labware
|
|
79
|
+
|
|
80
|
+
if isinstance(pipette, InstrumentContext):
|
|
81
|
+
pipette_name = pipette.name
|
|
82
|
+
elif isinstance(pipette, str):
|
|
83
|
+
pipette_name = pipette
|
|
84
|
+
else:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
f"{pipette} should either be an InstrumentContext object"
|
|
87
|
+
f" or a pipette name string."
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if isinstance(tip_rack, Labware):
|
|
91
|
+
tiprack_uri = tip_rack.uri
|
|
92
|
+
elif isinstance(tip_rack, str):
|
|
93
|
+
tiprack_uri = tip_rack
|
|
94
|
+
else:
|
|
95
|
+
raise ValueError(
|
|
96
|
+
f"{tip_rack} should either be a tiprack Labware object"
|
|
97
|
+
f" or a tiprack URI string."
|
|
98
|
+
)
|
|
99
|
+
|
|
69
100
|
try:
|
|
70
|
-
settings_for_pipette = self._by_pipette_setting[
|
|
101
|
+
settings_for_pipette = self._by_pipette_setting[pipette_name]
|
|
71
102
|
except KeyError:
|
|
72
|
-
raise
|
|
73
|
-
f"No properties found for {
|
|
103
|
+
raise NoLiquidClassPropertyError(
|
|
104
|
+
f"No properties found for {pipette_name} in {self._name} liquid class"
|
|
74
105
|
)
|
|
75
106
|
try:
|
|
76
|
-
transfer_properties = settings_for_pipette[
|
|
107
|
+
transfer_properties = settings_for_pipette[tiprack_uri]
|
|
77
108
|
except KeyError:
|
|
78
|
-
raise
|
|
79
|
-
f"No properties found for {
|
|
109
|
+
raise NoLiquidClassPropertyError(
|
|
110
|
+
f"No properties found for {tiprack_uri} for {pipette_name} in {self._name} liquid class"
|
|
80
111
|
)
|
|
81
112
|
return transfer_properties
|
|
@@ -83,7 +83,10 @@ class LiquidHandlingPropertyByVolume:
|
|
|
83
83
|
)
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
# We use slots for this dataclass (and the rest of liquid properties) to prevent dynamic creation of attributes
|
|
87
|
+
# not defined in the class, not for any performance reasons. This is so that mistyping properties when overriding
|
|
88
|
+
# values will cause the protocol to fail analysis, rather than silently passing.
|
|
89
|
+
@dataclass(slots=True)
|
|
87
90
|
class DelayProperties:
|
|
88
91
|
|
|
89
92
|
_enabled: bool
|
|
@@ -118,7 +121,7 @@ class DelayProperties:
|
|
|
118
121
|
)
|
|
119
122
|
|
|
120
123
|
|
|
121
|
-
@dataclass
|
|
124
|
+
@dataclass(slots=True)
|
|
122
125
|
class TouchTipProperties:
|
|
123
126
|
|
|
124
127
|
_enabled: bool
|
|
@@ -157,7 +160,7 @@ class TouchTipProperties:
|
|
|
157
160
|
@mm_to_edge.setter
|
|
158
161
|
def mm_to_edge(self, new_mm: float) -> None:
|
|
159
162
|
validated_mm = validation.ensure_float(new_mm)
|
|
160
|
-
self.
|
|
163
|
+
self._mm_to_edge = validated_mm
|
|
161
164
|
|
|
162
165
|
@property
|
|
163
166
|
def speed(self) -> Optional[float]:
|
|
@@ -165,7 +168,7 @@ class TouchTipProperties:
|
|
|
165
168
|
|
|
166
169
|
@speed.setter
|
|
167
170
|
def speed(self, new_speed: float) -> None:
|
|
168
|
-
validated_speed = validation.
|
|
171
|
+
validated_speed = validation.ensure_greater_than_zero_float(new_speed)
|
|
169
172
|
self._speed = validated_speed
|
|
170
173
|
|
|
171
174
|
def _get_shared_data_params(self) -> Optional[SharedDataTouchTipParams]:
|
|
@@ -190,7 +193,7 @@ class TouchTipProperties:
|
|
|
190
193
|
)
|
|
191
194
|
|
|
192
195
|
|
|
193
|
-
@dataclass
|
|
196
|
+
@dataclass(slots=True)
|
|
194
197
|
class MixProperties:
|
|
195
198
|
|
|
196
199
|
_enabled: bool
|
|
@@ -223,7 +226,7 @@ class MixProperties:
|
|
|
223
226
|
|
|
224
227
|
@volume.setter
|
|
225
228
|
def volume(self, new_volume: float) -> None:
|
|
226
|
-
validated_volume = validation.
|
|
229
|
+
validated_volume = validation.ensure_greater_than_zero_float(new_volume)
|
|
227
230
|
self._volume = validated_volume
|
|
228
231
|
|
|
229
232
|
def _get_shared_data_params(self) -> Optional[SharedDataMixParams]:
|
|
@@ -243,7 +246,7 @@ class MixProperties:
|
|
|
243
246
|
)
|
|
244
247
|
|
|
245
248
|
|
|
246
|
-
@dataclass
|
|
249
|
+
@dataclass(slots=True)
|
|
247
250
|
class BlowoutProperties:
|
|
248
251
|
|
|
249
252
|
_enabled: bool
|
|
@@ -277,7 +280,7 @@ class BlowoutProperties:
|
|
|
277
280
|
|
|
278
281
|
@flow_rate.setter
|
|
279
282
|
def flow_rate(self, new_flow_rate: float) -> None:
|
|
280
|
-
validated_flow_rate = validation.
|
|
283
|
+
validated_flow_rate = validation.ensure_greater_than_zero_float(new_flow_rate)
|
|
281
284
|
self._flow_rate = validated_flow_rate
|
|
282
285
|
|
|
283
286
|
def _get_shared_data_params(self) -> Optional[SharedDataBlowoutParams]:
|
|
@@ -297,7 +300,7 @@ class BlowoutProperties:
|
|
|
297
300
|
)
|
|
298
301
|
|
|
299
302
|
|
|
300
|
-
@dataclass
|
|
303
|
+
@dataclass(slots=True)
|
|
301
304
|
class SubmergeRetractCommon:
|
|
302
305
|
|
|
303
306
|
_position_reference: PositionReference
|
|
@@ -336,10 +339,8 @@ class SubmergeRetractCommon:
|
|
|
336
339
|
return self._delay
|
|
337
340
|
|
|
338
341
|
|
|
339
|
-
@dataclass
|
|
342
|
+
@dataclass(slots=True)
|
|
340
343
|
class Submerge(SubmergeRetractCommon):
|
|
341
|
-
...
|
|
342
|
-
|
|
343
344
|
def as_shared_data_model(self) -> SharedDataSubmerge:
|
|
344
345
|
return SharedDataSubmerge(
|
|
345
346
|
positionReference=self._position_reference,
|
|
@@ -349,7 +350,7 @@ class Submerge(SubmergeRetractCommon):
|
|
|
349
350
|
)
|
|
350
351
|
|
|
351
352
|
|
|
352
|
-
@dataclass
|
|
353
|
+
@dataclass(slots=True)
|
|
353
354
|
class RetractAspirate(SubmergeRetractCommon):
|
|
354
355
|
|
|
355
356
|
_air_gap_by_volume: LiquidHandlingPropertyByVolume
|
|
@@ -374,7 +375,7 @@ class RetractAspirate(SubmergeRetractCommon):
|
|
|
374
375
|
)
|
|
375
376
|
|
|
376
377
|
|
|
377
|
-
@dataclass
|
|
378
|
+
@dataclass(slots=True)
|
|
378
379
|
class RetractDispense(SubmergeRetractCommon):
|
|
379
380
|
|
|
380
381
|
_air_gap_by_volume: LiquidHandlingPropertyByVolume
|
|
@@ -405,7 +406,7 @@ class RetractDispense(SubmergeRetractCommon):
|
|
|
405
406
|
)
|
|
406
407
|
|
|
407
408
|
|
|
408
|
-
@dataclass
|
|
409
|
+
@dataclass(slots=True)
|
|
409
410
|
class BaseLiquidHandlingProperties:
|
|
410
411
|
|
|
411
412
|
_submerge: Submerge
|
|
@@ -449,7 +450,7 @@ class BaseLiquidHandlingProperties:
|
|
|
449
450
|
return self._delay
|
|
450
451
|
|
|
451
452
|
|
|
452
|
-
@dataclass
|
|
453
|
+
@dataclass(slots=True)
|
|
453
454
|
class AspirateProperties(BaseLiquidHandlingProperties):
|
|
454
455
|
|
|
455
456
|
_retract: RetractAspirate
|
|
@@ -487,7 +488,7 @@ class AspirateProperties(BaseLiquidHandlingProperties):
|
|
|
487
488
|
)
|
|
488
489
|
|
|
489
490
|
|
|
490
|
-
@dataclass
|
|
491
|
+
@dataclass(slots=True)
|
|
491
492
|
class SingleDispenseProperties(BaseLiquidHandlingProperties):
|
|
492
493
|
|
|
493
494
|
_retract: RetractDispense
|
|
@@ -520,7 +521,7 @@ class SingleDispenseProperties(BaseLiquidHandlingProperties):
|
|
|
520
521
|
)
|
|
521
522
|
|
|
522
523
|
|
|
523
|
-
@dataclass
|
|
524
|
+
@dataclass(slots=True)
|
|
524
525
|
class MultiDispenseProperties(BaseLiquidHandlingProperties):
|
|
525
526
|
|
|
526
527
|
_retract: RetractDispense
|
|
@@ -553,7 +554,7 @@ class MultiDispenseProperties(BaseLiquidHandlingProperties):
|
|
|
553
554
|
)
|
|
554
555
|
|
|
555
556
|
|
|
556
|
-
@dataclass
|
|
557
|
+
@dataclass(slots=True)
|
|
557
558
|
class TransferProperties:
|
|
558
559
|
_aspirate: AspirateProperties
|
|
559
560
|
_dispense: SingleDispenseProperties
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import List, Union, Sequence, Optional
|
|
3
|
+
|
|
4
|
+
from opentrons.types import Location, NozzleMapInterface
|
|
5
|
+
from opentrons.protocols.api_support import instrument
|
|
6
|
+
from opentrons.protocols.advanced_control.transfers import (
|
|
7
|
+
transfer_liquid_utils as tx_liquid_utils,
|
|
8
|
+
)
|
|
9
|
+
from opentrons.protocols.advanced_control.transfers.common import (
|
|
10
|
+
TransferTipPolicyV2,
|
|
11
|
+
TransferTipPolicyV2Type,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from .disposal_locations import TrashBin, WasteChute
|
|
15
|
+
from .labware import Labware, Well
|
|
16
|
+
from . import validation
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class TransferInfo:
|
|
21
|
+
|
|
22
|
+
sources_list: List[Well]
|
|
23
|
+
destinations_list: List[Well]
|
|
24
|
+
tip_policy: TransferTipPolicyV2
|
|
25
|
+
tip_racks: List[Labware]
|
|
26
|
+
trash_location: Union[Location, TrashBin, WasteChute]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def verify_and_normalize_transfer_args(
|
|
30
|
+
source: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
31
|
+
dest: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
32
|
+
tip_policy: TransferTipPolicyV2Type,
|
|
33
|
+
last_tip_picked_up_from: Optional[Well],
|
|
34
|
+
tip_racks: List[Labware],
|
|
35
|
+
nozzle_map: NozzleMapInterface,
|
|
36
|
+
target_all_wells: bool,
|
|
37
|
+
current_volume: float,
|
|
38
|
+
trash_location: Union[Location, Well, Labware, TrashBin, WasteChute],
|
|
39
|
+
) -> TransferInfo:
|
|
40
|
+
flat_sources_list = validation.ensure_valid_flat_wells_list_for_transfer_v2(source)
|
|
41
|
+
flat_dests_list = validation.ensure_valid_flat_wells_list_for_transfer_v2(dest)
|
|
42
|
+
if not target_all_wells and nozzle_map.tip_count > 1:
|
|
43
|
+
flat_sources_list = tx_liquid_utils.group_wells_for_multi_channel_transfer(
|
|
44
|
+
flat_sources_list, nozzle_map
|
|
45
|
+
)
|
|
46
|
+
flat_dests_list = tx_liquid_utils.group_wells_for_multi_channel_transfer(
|
|
47
|
+
flat_dests_list, nozzle_map
|
|
48
|
+
)
|
|
49
|
+
for well in flat_sources_list + flat_dests_list:
|
|
50
|
+
instrument.validate_takes_liquid(
|
|
51
|
+
location=well.top(),
|
|
52
|
+
reject_module=True,
|
|
53
|
+
reject_adapter=True,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
valid_new_tip = validation.ensure_new_tip_policy(tip_policy)
|
|
57
|
+
if valid_new_tip == TransferTipPolicyV2.NEVER:
|
|
58
|
+
if last_tip_picked_up_from is None:
|
|
59
|
+
raise RuntimeError(
|
|
60
|
+
"Pipette has no tip attached to perform transfer."
|
|
61
|
+
" Either do a pick_up_tip beforehand or specify a new_tip parameter"
|
|
62
|
+
" of 'once' or 'always'."
|
|
63
|
+
)
|
|
64
|
+
else:
|
|
65
|
+
valid_tip_racks = [last_tip_picked_up_from.parent]
|
|
66
|
+
else:
|
|
67
|
+
valid_tip_racks = tip_racks
|
|
68
|
+
if current_volume != 0:
|
|
69
|
+
raise RuntimeError(
|
|
70
|
+
"A transfer on a liquid class cannot start with liquid already in the tip."
|
|
71
|
+
" Ensure that all previously aspirated liquid is dispensed before starting"
|
|
72
|
+
" a new transfer."
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
_trash_location: Union[Location, Well, TrashBin, WasteChute]
|
|
76
|
+
if isinstance(trash_location, Labware):
|
|
77
|
+
_trash_location = trash_location.wells()[0]
|
|
78
|
+
else:
|
|
79
|
+
_trash_location = trash_location
|
|
80
|
+
|
|
81
|
+
valid_trash_location = validation.ensure_valid_trash_location_for_transfer_v2(
|
|
82
|
+
trash_location=_trash_location
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
return TransferInfo(
|
|
86
|
+
sources_list=flat_sources_list,
|
|
87
|
+
destinations_list=flat_dests_list,
|
|
88
|
+
tip_policy=valid_new_tip,
|
|
89
|
+
tip_racks=valid_tip_racks,
|
|
90
|
+
trash_location=valid_trash_location,
|
|
91
|
+
)
|
|
@@ -11,6 +11,7 @@ from .module import (
|
|
|
11
11
|
AbstractHeaterShakerCore,
|
|
12
12
|
AbstractMagneticBlockCore,
|
|
13
13
|
AbstractAbsorbanceReaderCore,
|
|
14
|
+
AbstractFlexStackerCore,
|
|
14
15
|
)
|
|
15
16
|
from .protocol import AbstractProtocol
|
|
16
17
|
from .well import AbstractWellCore
|
|
@@ -19,7 +20,7 @@ from .robot import AbstractRobot
|
|
|
19
20
|
|
|
20
21
|
WellCore = AbstractWellCore
|
|
21
22
|
LabwareCore = AbstractLabware[WellCore]
|
|
22
|
-
InstrumentCore = AbstractInstrument[WellCore]
|
|
23
|
+
InstrumentCore = AbstractInstrument[WellCore, LabwareCore]
|
|
23
24
|
ModuleCore = AbstractModuleCore
|
|
24
25
|
TemperatureModuleCore = AbstractTemperatureModuleCore
|
|
25
26
|
MagneticModuleCore = AbstractMagneticModuleCore
|
|
@@ -27,5 +28,6 @@ ThermocyclerCore = AbstractThermocyclerCore
|
|
|
27
28
|
HeaterShakerCore = AbstractHeaterShakerCore
|
|
28
29
|
MagneticBlockCore = AbstractMagneticBlockCore
|
|
29
30
|
AbsorbanceReaderCore = AbstractAbsorbanceReaderCore
|
|
31
|
+
FlexStackerCore = AbstractFlexStackerCore
|
|
30
32
|
RobotCore = AbstractRobot
|
|
31
33
|
ProtocolCore = AbstractProtocol[InstrumentCore, LabwareCore, ModuleCore]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""A Protocol-Engine-friendly wrapper for opentrons.motion_planning.deck_conflict."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
import itertools
|
|
4
5
|
import logging
|
|
@@ -24,7 +25,9 @@ from opentrons.protocol_engine import (
|
|
|
24
25
|
ModuleLocation,
|
|
25
26
|
OnLabwareLocation,
|
|
26
27
|
AddressableAreaLocation,
|
|
28
|
+
InStackerHopperLocation,
|
|
27
29
|
OFF_DECK_LOCATION,
|
|
30
|
+
SYSTEM_LOCATION,
|
|
28
31
|
)
|
|
29
32
|
from opentrons.protocol_engine.errors.exceptions import LabwareNotLoadedOnModuleError
|
|
30
33
|
from opentrons.types import DeckSlotName, StagingSlotName, Point
|
|
@@ -245,7 +248,11 @@ def _map_labware(
|
|
|
245
248
|
# TODO(jbl 2023-06-08) check if we need to do any logic here or if this is correct
|
|
246
249
|
return None
|
|
247
250
|
|
|
248
|
-
elif
|
|
251
|
+
elif (
|
|
252
|
+
location_from_engine == OFF_DECK_LOCATION
|
|
253
|
+
or location_from_engine == SYSTEM_LOCATION
|
|
254
|
+
or isinstance(location_from_engine, InStackerHopperLocation)
|
|
255
|
+
):
|
|
249
256
|
# This labware is off-deck. Exclude it from conflict checking.
|
|
250
257
|
# todo(mm, 2023-02-23): Move this logic into wrapped_deck_conflict.
|
|
251
258
|
return None
|
|
@@ -296,6 +303,9 @@ def _map_module(
|
|
|
296
303
|
is_semi_configuration=False,
|
|
297
304
|
),
|
|
298
305
|
)
|
|
306
|
+
elif module_type == ModuleType.FLEX_STACKER:
|
|
307
|
+
# TODO: This is a placeholder. We need to implement this.
|
|
308
|
+
return None
|
|
299
309
|
else:
|
|
300
310
|
return (
|
|
301
311
|
mapped_location,
|