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,4 +1,5 @@
|
|
|
1
1
|
"""ProtocolEngine-based Protocol API core implementation."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
from typing import Dict, Optional, Type, Union, List, Tuple, TYPE_CHECKING
|
|
4
5
|
|
|
@@ -8,7 +9,9 @@ from opentrons.protocol_engine import commands as cmd
|
|
|
8
9
|
from opentrons.protocol_engine.commands import LoadModuleResult
|
|
9
10
|
|
|
10
11
|
from opentrons_shared_data.deck.types import DeckDefinitionV5, SlotDefV3
|
|
11
|
-
from opentrons_shared_data.labware.labware_definition import
|
|
12
|
+
from opentrons_shared_data.labware.labware_definition import (
|
|
13
|
+
labware_definition_type_adapter,
|
|
14
|
+
)
|
|
12
15
|
from opentrons_shared_data.labware.types import LabwareDefinition as LabwareDefDict
|
|
13
16
|
from opentrons_shared_data import liquid_classes
|
|
14
17
|
from opentrons_shared_data.liquid_classes.liquid_class_definition import (
|
|
@@ -47,7 +50,8 @@ from opentrons.protocol_engine import (
|
|
|
47
50
|
from opentrons.protocol_engine.types import (
|
|
48
51
|
ModuleModel as ProtocolEngineModuleModel,
|
|
49
52
|
OFF_DECK_LOCATION,
|
|
50
|
-
|
|
53
|
+
SYSTEM_LOCATION,
|
|
54
|
+
LoadableLabwareLocation,
|
|
51
55
|
NonStackedLocation,
|
|
52
56
|
)
|
|
53
57
|
from opentrons.protocol_engine.clients import SyncClient as ProtocolEngineClient
|
|
@@ -74,9 +78,11 @@ from .module_core import (
|
|
|
74
78
|
NonConnectedModuleCore,
|
|
75
79
|
MagneticBlockCore,
|
|
76
80
|
AbsorbanceReaderCore,
|
|
81
|
+
FlexStackerCore,
|
|
77
82
|
)
|
|
78
83
|
from .exceptions import InvalidModuleLocationError
|
|
79
84
|
from . import load_labware_params, deck_conflict, overlap_versions
|
|
85
|
+
from opentrons.protocol_engine.resources import labware_validation
|
|
80
86
|
|
|
81
87
|
if TYPE_CHECKING:
|
|
82
88
|
from ...labware import Labware
|
|
@@ -193,7 +199,7 @@ class ProtocolCore(
|
|
|
193
199
|
) -> LabwareLoadParams:
|
|
194
200
|
"""Add a labware definition to the set of loadable definitions."""
|
|
195
201
|
uri = self._engine_client.add_labware_definition(
|
|
196
|
-
|
|
202
|
+
labware_definition_type_adapter.validate_python(definition)
|
|
197
203
|
)
|
|
198
204
|
return LabwareLoadParams.from_uri(uri)
|
|
199
205
|
|
|
@@ -219,7 +225,7 @@ class ProtocolCore(
|
|
|
219
225
|
self._engine_client.state.labware.find_custom_labware_load_params()
|
|
220
226
|
)
|
|
221
227
|
namespace, version = load_labware_params.resolve(
|
|
222
|
-
load_name, namespace, version, custom_labware_params
|
|
228
|
+
load_name, namespace, version, custom_labware_params, self._api_version
|
|
223
229
|
)
|
|
224
230
|
|
|
225
231
|
load_result = self._engine_client.execute_command_without_recovery(
|
|
@@ -290,7 +296,7 @@ class ProtocolCore(
|
|
|
290
296
|
self._engine_client.state.labware.find_custom_labware_load_params()
|
|
291
297
|
)
|
|
292
298
|
namespace, version = load_labware_params.resolve(
|
|
293
|
-
load_name, namespace, version, custom_labware_params
|
|
299
|
+
load_name, namespace, version, custom_labware_params, self._api_version
|
|
294
300
|
)
|
|
295
301
|
load_result = self._engine_client.execute_command_without_recovery(
|
|
296
302
|
cmd.LoadLabwareParams(
|
|
@@ -338,7 +344,7 @@ class ProtocolCore(
|
|
|
338
344
|
self._engine_client.state.labware.find_custom_labware_load_params()
|
|
339
345
|
)
|
|
340
346
|
namespace, version = load_labware_params.resolve(
|
|
341
|
-
load_name, namespace, version, custom_labware_params
|
|
347
|
+
load_name, namespace, version, custom_labware_params, self._api_version
|
|
342
348
|
)
|
|
343
349
|
load_result = self._engine_client.execute_command_without_recovery(
|
|
344
350
|
cmd.LoadLidParams(
|
|
@@ -371,6 +377,34 @@ class ProtocolCore(
|
|
|
371
377
|
self._labware_cores_by_id[labware_core.labware_id] = labware_core
|
|
372
378
|
return labware_core
|
|
373
379
|
|
|
380
|
+
def load_labware_to_flex_stacker_hopper(
|
|
381
|
+
self,
|
|
382
|
+
module_core: Union[ModuleCore, NonConnectedModuleCore],
|
|
383
|
+
load_name: str,
|
|
384
|
+
quantity: int,
|
|
385
|
+
label: Optional[str],
|
|
386
|
+
namespace: Optional[str],
|
|
387
|
+
version: Optional[int],
|
|
388
|
+
lid: Optional[str],
|
|
389
|
+
) -> None:
|
|
390
|
+
"""Load one or more labware with or without a lid to the flex stacker hopper."""
|
|
391
|
+
assert isinstance(module_core, FlexStackerCore)
|
|
392
|
+
for _ in range(quantity):
|
|
393
|
+
labware_core = self.load_labware(
|
|
394
|
+
load_name=load_name,
|
|
395
|
+
location=module_core,
|
|
396
|
+
label=label,
|
|
397
|
+
namespace=namespace,
|
|
398
|
+
version=version,
|
|
399
|
+
)
|
|
400
|
+
if lid is not None:
|
|
401
|
+
self.load_lid(
|
|
402
|
+
load_name=lid,
|
|
403
|
+
location=labware_core,
|
|
404
|
+
namespace=namespace,
|
|
405
|
+
version=version,
|
|
406
|
+
)
|
|
407
|
+
|
|
374
408
|
def move_labware(
|
|
375
409
|
self,
|
|
376
410
|
labware_core: LabwareCore,
|
|
@@ -442,6 +476,203 @@ class ProtocolCore(
|
|
|
442
476
|
existing_module_ids=list(self._module_cores_by_id.keys()),
|
|
443
477
|
)
|
|
444
478
|
|
|
479
|
+
def move_lid( # noqa: C901
|
|
480
|
+
self,
|
|
481
|
+
source_location: Union[DeckSlotName, StagingSlotName, LabwareCore],
|
|
482
|
+
new_location: Union[
|
|
483
|
+
DeckSlotName,
|
|
484
|
+
StagingSlotName,
|
|
485
|
+
LabwareCore,
|
|
486
|
+
OffDeckType,
|
|
487
|
+
WasteChute,
|
|
488
|
+
TrashBin,
|
|
489
|
+
],
|
|
490
|
+
use_gripper: bool,
|
|
491
|
+
pause_for_manual_move: bool,
|
|
492
|
+
pick_up_offset: Optional[Tuple[float, float, float]],
|
|
493
|
+
drop_offset: Optional[Tuple[float, float, float]],
|
|
494
|
+
) -> LabwareCore | None:
|
|
495
|
+
"""Move the given lid to a new location."""
|
|
496
|
+
if use_gripper:
|
|
497
|
+
strategy = LabwareMovementStrategy.USING_GRIPPER
|
|
498
|
+
elif pause_for_manual_move:
|
|
499
|
+
strategy = LabwareMovementStrategy.MANUAL_MOVE_WITH_PAUSE
|
|
500
|
+
else:
|
|
501
|
+
strategy = LabwareMovementStrategy.MANUAL_MOVE_WITHOUT_PAUSE
|
|
502
|
+
|
|
503
|
+
if isinstance(source_location, DeckSlotName) or isinstance(
|
|
504
|
+
source_location, StagingSlotName
|
|
505
|
+
):
|
|
506
|
+
# Find the source labware at the provided deck slot
|
|
507
|
+
labware_in_slot = self._engine_client.state.labware.get_by_slot(
|
|
508
|
+
source_location
|
|
509
|
+
)
|
|
510
|
+
if labware_in_slot is None:
|
|
511
|
+
raise LabwareNotLoadedOnLabwareError(
|
|
512
|
+
"Lid cannot be loaded on non-labware position."
|
|
513
|
+
)
|
|
514
|
+
else:
|
|
515
|
+
labware = LabwareCore(labware_in_slot.id, self._engine_client)
|
|
516
|
+
else:
|
|
517
|
+
labware = source_location
|
|
518
|
+
|
|
519
|
+
# if this is a labware stack, we need to find the labware at the top of the stack
|
|
520
|
+
if labware_validation.is_lid_stack(labware.load_name):
|
|
521
|
+
lid_id = self._engine_client.state.labware.get_highest_child_labware(
|
|
522
|
+
labware.labware_id
|
|
523
|
+
)
|
|
524
|
+
# if this is a labware with a lid, we just need to find its lid_id
|
|
525
|
+
else:
|
|
526
|
+
lid = self._engine_client.state.labware.get_lid_by_labware_id(
|
|
527
|
+
labware.labware_id
|
|
528
|
+
)
|
|
529
|
+
if lid is not None:
|
|
530
|
+
lid_id = lid.id
|
|
531
|
+
else:
|
|
532
|
+
raise ValueError("Cannot move a lid off of a labware with no lid.")
|
|
533
|
+
|
|
534
|
+
_pick_up_offset = (
|
|
535
|
+
LabwareOffsetVector(
|
|
536
|
+
x=pick_up_offset[0], y=pick_up_offset[1], z=pick_up_offset[2]
|
|
537
|
+
)
|
|
538
|
+
if pick_up_offset
|
|
539
|
+
else None
|
|
540
|
+
)
|
|
541
|
+
_drop_offset = (
|
|
542
|
+
LabwareOffsetVector(x=drop_offset[0], y=drop_offset[1], z=drop_offset[2])
|
|
543
|
+
if drop_offset
|
|
544
|
+
else None
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
create_new_lid_stack = False
|
|
548
|
+
|
|
549
|
+
if isinstance(new_location, DeckSlotName) or isinstance(
|
|
550
|
+
new_location, StagingSlotName
|
|
551
|
+
):
|
|
552
|
+
# Find the destination labware at the provided deck slot
|
|
553
|
+
destination_labware_in_slot = self._engine_client.state.labware.get_by_slot(
|
|
554
|
+
new_location
|
|
555
|
+
)
|
|
556
|
+
if destination_labware_in_slot is None:
|
|
557
|
+
to_location = self._convert_labware_location(location=new_location)
|
|
558
|
+
# absolutely must make a new lid stack
|
|
559
|
+
create_new_lid_stack = True
|
|
560
|
+
else:
|
|
561
|
+
highest_child_location = (
|
|
562
|
+
self._engine_client.state.labware.get_highest_child_labware(
|
|
563
|
+
destination_labware_in_slot.id
|
|
564
|
+
)
|
|
565
|
+
)
|
|
566
|
+
if labware_validation.validate_definition_is_adapter(
|
|
567
|
+
self._engine_client.state.labware.get_definition(
|
|
568
|
+
highest_child_location
|
|
569
|
+
)
|
|
570
|
+
):
|
|
571
|
+
# absolutely must make a new lid stack
|
|
572
|
+
create_new_lid_stack = True
|
|
573
|
+
|
|
574
|
+
to_location = self._convert_labware_location(
|
|
575
|
+
location=LabwareCore(highest_child_location, self._engine_client)
|
|
576
|
+
)
|
|
577
|
+
elif isinstance(new_location, LabwareCore):
|
|
578
|
+
highest_child_location = (
|
|
579
|
+
self._engine_client.state.labware.get_highest_child_labware(
|
|
580
|
+
new_location.labware_id
|
|
581
|
+
)
|
|
582
|
+
)
|
|
583
|
+
if labware_validation.validate_definition_is_adapter(
|
|
584
|
+
self._engine_client.state.labware.get_definition(highest_child_location)
|
|
585
|
+
):
|
|
586
|
+
# absolutely must make a new lid stack
|
|
587
|
+
create_new_lid_stack = True
|
|
588
|
+
to_location = self._convert_labware_location(
|
|
589
|
+
location=LabwareCore(highest_child_location, self._engine_client)
|
|
590
|
+
)
|
|
591
|
+
else:
|
|
592
|
+
to_location = self._convert_labware_location(location=new_location)
|
|
593
|
+
|
|
594
|
+
output_result = None
|
|
595
|
+
if create_new_lid_stack:
|
|
596
|
+
# Make a new lid stack object that is empty
|
|
597
|
+
result = self._engine_client.execute_command_without_recovery(
|
|
598
|
+
cmd.LoadLidStackParams(
|
|
599
|
+
location=SYSTEM_LOCATION,
|
|
600
|
+
loadName="empty",
|
|
601
|
+
version=1,
|
|
602
|
+
namespace="empty",
|
|
603
|
+
quantity=0,
|
|
604
|
+
)
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
# Move the lid stack object from the SYSTEM_LOCATION space to the desired deck location
|
|
608
|
+
self._engine_client.execute_command(
|
|
609
|
+
cmd.MoveLabwareParams(
|
|
610
|
+
labwareId=result.stackLabwareId,
|
|
611
|
+
newLocation=to_location,
|
|
612
|
+
strategy=LabwareMovementStrategy.MANUAL_MOVE_WITHOUT_PAUSE,
|
|
613
|
+
pickUpOffset=None,
|
|
614
|
+
dropOffset=None,
|
|
615
|
+
)
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
output_result = LabwareCore(
|
|
619
|
+
labware_id=result.stackLabwareId, engine_client=self._engine_client
|
|
620
|
+
)
|
|
621
|
+
destination = self._convert_labware_location(location=output_result)
|
|
622
|
+
else:
|
|
623
|
+
destination = to_location
|
|
624
|
+
|
|
625
|
+
self._engine_client.execute_command(
|
|
626
|
+
cmd.MoveLabwareParams(
|
|
627
|
+
labwareId=lid_id,
|
|
628
|
+
newLocation=destination,
|
|
629
|
+
strategy=strategy,
|
|
630
|
+
pickUpOffset=_pick_up_offset,
|
|
631
|
+
dropOffset=_drop_offset,
|
|
632
|
+
)
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
# Handle leftover empty lid stack if there is one
|
|
636
|
+
if (
|
|
637
|
+
labware_validation.is_lid_stack(labware.load_name)
|
|
638
|
+
and self._engine_client.state.labware.get_highest_child_labware(
|
|
639
|
+
labware_id=labware.labware_id
|
|
640
|
+
)
|
|
641
|
+
== labware.labware_id
|
|
642
|
+
):
|
|
643
|
+
# The originating lid stack is now empty, so we need to move it to the SYSTEM_LOCATION
|
|
644
|
+
self._engine_client.execute_command(
|
|
645
|
+
cmd.MoveLabwareParams(
|
|
646
|
+
labwareId=labware.labware_id,
|
|
647
|
+
newLocation=SYSTEM_LOCATION,
|
|
648
|
+
strategy=LabwareMovementStrategy.MANUAL_MOVE_WITHOUT_PAUSE,
|
|
649
|
+
pickUpOffset=None,
|
|
650
|
+
dropOffset=None,
|
|
651
|
+
)
|
|
652
|
+
)
|
|
653
|
+
|
|
654
|
+
if strategy == LabwareMovementStrategy.USING_GRIPPER:
|
|
655
|
+
# Clear out last location since it is not relevant to pipetting
|
|
656
|
+
# and we only use last location for in-place pipetting commands
|
|
657
|
+
self.set_last_location(location=None, mount=Mount.EXTENSION)
|
|
658
|
+
|
|
659
|
+
# FIXME(jbl, 2024-01-04) deck conflict after execution logic issue, read notes in load_labware for more info:
|
|
660
|
+
deck_conflict.check(
|
|
661
|
+
engine_state=self._engine_client.state,
|
|
662
|
+
new_labware_id=lid_id,
|
|
663
|
+
existing_disposal_locations=self._disposal_locations,
|
|
664
|
+
# TODO: We can now fetch these IDs from engine too.
|
|
665
|
+
# See comment in self.load_labware().
|
|
666
|
+
existing_labware_ids=[
|
|
667
|
+
labware_id
|
|
668
|
+
for labware_id in self._labware_cores_by_id
|
|
669
|
+
if labware_id != labware_id
|
|
670
|
+
],
|
|
671
|
+
existing_module_ids=list(self._module_cores_by_id.keys()),
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
return output_result
|
|
675
|
+
|
|
445
676
|
def _resolve_module_hardware(
|
|
446
677
|
self, serial_number: str, model: ModuleModel
|
|
447
678
|
) -> AbstractModule:
|
|
@@ -527,6 +758,7 @@ class ProtocolCore(
|
|
|
527
758
|
ModuleType.THERMOCYCLER: ThermocyclerModuleCore,
|
|
528
759
|
ModuleType.HEATER_SHAKER: HeaterShakerModuleCore,
|
|
529
760
|
ModuleType.ABSORBANCE_READER: AbsorbanceReaderCore,
|
|
761
|
+
ModuleType.FLEX_STACKER: FlexStackerCore,
|
|
530
762
|
}
|
|
531
763
|
|
|
532
764
|
module_type = load_module_result.model.as_type()
|
|
@@ -557,6 +789,15 @@ class ProtocolCore(
|
|
|
557
789
|
load_module_result=load_module_result, model=model
|
|
558
790
|
)
|
|
559
791
|
|
|
792
|
+
def add_or_get_labware_core(self, labware_id: str) -> LabwareCore:
|
|
793
|
+
"""Create a LabwareCore and add it to the map or return one if it exists."""
|
|
794
|
+
if labware_id in self._labware_cores_by_id:
|
|
795
|
+
return self._labware_cores_by_id[labware_id]
|
|
796
|
+
else:
|
|
797
|
+
core = LabwareCore(labware_id, self._engine_client)
|
|
798
|
+
self._labware_cores_by_id[labware_id] = core
|
|
799
|
+
return core
|
|
800
|
+
|
|
560
801
|
def load_robot(self) -> RobotCore:
|
|
561
802
|
"""Load a robot core into the RobotContext."""
|
|
562
803
|
return RobotCore(
|
|
@@ -720,7 +961,7 @@ class ProtocolCore(
|
|
|
720
961
|
self._engine_client.state.labware.find_custom_labware_load_params()
|
|
721
962
|
)
|
|
722
963
|
namespace, version = load_labware_params.resolve(
|
|
723
|
-
load_name, namespace, version, custom_labware_params
|
|
964
|
+
load_name, namespace, version, custom_labware_params, self._api_version
|
|
724
965
|
)
|
|
725
966
|
|
|
726
967
|
load_result = self._engine_client.execute_command_without_recovery(
|
|
@@ -734,6 +975,7 @@ class ProtocolCore(
|
|
|
734
975
|
)
|
|
735
976
|
|
|
736
977
|
# FIXME(CHB, 2024-12-04) just like load labware and load adapter we have a validating after loading the object issue
|
|
978
|
+
assert load_result.definition is not None
|
|
737
979
|
validation.ensure_definition_is_lid(load_result.definition)
|
|
738
980
|
|
|
739
981
|
deck_conflict.check(
|
|
@@ -803,9 +1045,9 @@ class ProtocolCore(
|
|
|
803
1045
|
labware_id = self._engine_client.state.labware.get_id_by_module(
|
|
804
1046
|
module_core.module_id
|
|
805
1047
|
)
|
|
806
|
-
return self._labware_cores_by_id[labware_id]
|
|
807
1048
|
except LabwareNotLoadedOnModuleError:
|
|
808
1049
|
return None
|
|
1050
|
+
return self.add_or_get_labware_core(labware_id)
|
|
809
1051
|
|
|
810
1052
|
def get_labware_on_labware(
|
|
811
1053
|
self, labware_core: LabwareCore
|
|
@@ -815,9 +1057,9 @@ class ProtocolCore(
|
|
|
815
1057
|
labware_id = self._engine_client.state.labware.get_id_by_labware(
|
|
816
1058
|
labware_core.labware_id
|
|
817
1059
|
)
|
|
818
|
-
return self._labware_cores_by_id[labware_id]
|
|
819
1060
|
except LabwareNotLoadedOnLabwareError:
|
|
820
1061
|
return None
|
|
1062
|
+
return self.add_or_get_labware_core(labware_id)
|
|
821
1063
|
|
|
822
1064
|
def get_slot_center(self, slot_name: Union[DeckSlotName, StagingSlotName]) -> Point:
|
|
823
1065
|
"""Get the absolute coordinate of a slot's center."""
|
|
@@ -905,7 +1147,7 @@ class ProtocolCore(
|
|
|
905
1147
|
WasteChute,
|
|
906
1148
|
TrashBin,
|
|
907
1149
|
],
|
|
908
|
-
) ->
|
|
1150
|
+
) -> LoadableLabwareLocation:
|
|
909
1151
|
if isinstance(location, LabwareCore):
|
|
910
1152
|
return OnLabwareLocation(labwareId=location.labware_id)
|
|
911
1153
|
else:
|
|
@@ -921,7 +1163,7 @@ class ProtocolCore(
|
|
|
921
1163
|
OffDeckType,
|
|
922
1164
|
WasteChute,
|
|
923
1165
|
TrashBin,
|
|
924
|
-
]
|
|
1166
|
+
],
|
|
925
1167
|
) -> NonStackedLocation:
|
|
926
1168
|
if isinstance(location, (ModuleCore, NonConnectedModuleCore)):
|
|
927
1169
|
return ModuleLocation(moduleId=location.module_id)
|
|
@@ -5,6 +5,7 @@ from opentrons.protocol_engine.types import (
|
|
|
5
5
|
ModuleLocation,
|
|
6
6
|
OnLabwareLocation,
|
|
7
7
|
AddressableAreaLocation,
|
|
8
|
+
InStackerHopperLocation,
|
|
8
9
|
)
|
|
9
10
|
|
|
10
11
|
|
|
@@ -17,6 +18,15 @@ def well(engine_client: SyncClient, well_name: str, labware_id: str) -> str:
|
|
|
17
18
|
return f"{well_name} of {_labware_location_string(engine_client, labware_location)}"
|
|
18
19
|
|
|
19
20
|
|
|
21
|
+
def _module_in_location_string(module_id: str, engine_client: SyncClient) -> str:
|
|
22
|
+
module_name = engine_client.state.modules.get_definition(
|
|
23
|
+
module_id=module_id
|
|
24
|
+
).displayName
|
|
25
|
+
module_on = engine_client.state.modules.get_location(module_id=module_id)
|
|
26
|
+
module_on_string = _labware_location_string(engine_client, module_on)
|
|
27
|
+
return f"{module_name} on {module_on_string}"
|
|
28
|
+
|
|
29
|
+
|
|
20
30
|
def _labware_location_string(
|
|
21
31
|
engine_client: SyncClient, location: LabwareLocation
|
|
22
32
|
) -> str:
|
|
@@ -26,14 +36,7 @@ def _labware_location_string(
|
|
|
26
36
|
return f"slot {location.slotName.id}"
|
|
27
37
|
|
|
28
38
|
elif isinstance(location, ModuleLocation):
|
|
29
|
-
|
|
30
|
-
module_id=location.moduleId
|
|
31
|
-
).displayName
|
|
32
|
-
module_on = engine_client.state.modules.get_location(
|
|
33
|
-
module_id=location.moduleId
|
|
34
|
-
)
|
|
35
|
-
module_on_string = _labware_location_string(engine_client, module_on)
|
|
36
|
-
return f"{module_name} on {module_on_string}"
|
|
39
|
+
return _module_in_location_string(location.moduleId, engine_client)
|
|
37
40
|
|
|
38
41
|
elif isinstance(location, OnLabwareLocation):
|
|
39
42
|
labware_name = _labware_name(engine_client, location.labwareId)
|
|
@@ -50,6 +53,14 @@ def _labware_location_string(
|
|
|
50
53
|
elif location == "offDeck":
|
|
51
54
|
return "[off-deck]"
|
|
52
55
|
|
|
56
|
+
elif location == "systemLocation":
|
|
57
|
+
return "[systemLocation]"
|
|
58
|
+
|
|
59
|
+
elif isinstance(location, InStackerHopperLocation):
|
|
60
|
+
return (
|
|
61
|
+
f"stored in {_module_in_location_string(location.moduleId, engine_client)}"
|
|
62
|
+
)
|
|
63
|
+
|
|
53
64
|
|
|
54
65
|
def _labware_name(engine_client: SyncClient, labware_id: str) -> str:
|
|
55
66
|
"""Return the user-specified labware label, or fall back to the display name from the def."""
|