opentrons 8.3.1a1__py2.py3-none-any.whl → 8.4.0a0__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/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 +7 -2
- 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 +19 -3
- opentrons/legacy_commands/helpers.py +15 -0
- opentrons/legacy_commands/types.py +3 -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 +1233 -65
- 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/protocol.py +253 -11
- opentrons/protocol_api/core/engine/stringify.py +19 -8
- opentrons/protocol_api/core/engine/transfer_components_executor.py +853 -0
- opentrons/protocol_api/core/engine/well.py +60 -5
- opentrons/protocol_api/core/instrument.py +65 -19
- 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 +69 -21
- 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 +25 -1
- 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 +67 -21
- opentrons/protocol_api/core/module.py +43 -0
- opentrons/protocol_api/core/protocol.py +33 -0
- opentrons/protocol_api/core/well.py +21 -1
- opentrons/protocol_api/instrument_context.py +245 -123
- opentrons/protocol_api/labware.py +75 -11
- opentrons/protocol_api/module_contexts.py +140 -0
- opentrons/protocol_api/protocol_context.py +156 -16
- 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 +30 -0
- 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 +237 -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 +69 -0
- 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 +240 -0
- opentrons/protocol_engine/commands/drop_tip.py +23 -1
- opentrons/protocol_engine/commands/evotip_dispense.py +6 -7
- opentrons/protocol_engine/commands/evotip_seal_pipette.py +2 -9
- opentrons/protocol_engine/commands/evotip_unseal_pipette.py +1 -7
- 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 +288 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
- opentrons/protocol_engine/commands/labware_handling_common.py +24 -0
- opentrons/protocol_engine/commands/liquid_probe.py +21 -12
- 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/pick_up_tip.py +5 -2
- opentrons/protocol_engine/commands/pipetting_common.py +154 -7
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +3 -1
- opentrons/protocol_engine/commands/reload_labware.py +6 -19
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/equipment.py +123 -106
- opentrons/protocol_engine/execution/labware_movement.py +8 -6
- opentrons/protocol_engine/execution/pipetting.py +233 -26
- opentrons/protocol_engine/execution/tip_handler.py +14 -5
- opentrons/protocol_engine/labware_offset_standardization.py +173 -0
- opentrons/protocol_engine/protocol_engine.py +22 -13
- opentrons/protocol_engine/resources/deck_configuration_provider.py +94 -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 +26 -10
- opentrons/protocol_engine/state/geometry.py +683 -100
- 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 +178 -52
- 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 +54 -8
- opentrons/protocol_engine/types/__init__.py +292 -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 +110 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +108 -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 +137 -0
- opentrons/protocol_engine/types/location.py +193 -0
- opentrons/protocol_engine/types/module.py +269 -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 +107 -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 +5 -6
- opentrons/protocols/models/__init__.py +0 -21
- opentrons/simulate.py +4 -2
- opentrons/types.py +15 -6
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/METADATA +4 -4
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/RECORD +187 -147
- 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.1a1.dist-info → opentrons-8.4.0a0.dist-info}/LICENSE +0 -0
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/WHEEL +0 -0
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/top_level.txt +0 -0
|
@@ -19,23 +19,34 @@ from typing import (
|
|
|
19
19
|
List,
|
|
20
20
|
Dict,
|
|
21
21
|
Optional,
|
|
22
|
-
Union,
|
|
23
22
|
Tuple,
|
|
24
23
|
cast,
|
|
25
24
|
Sequence,
|
|
26
25
|
Mapping,
|
|
26
|
+
Union,
|
|
27
|
+
Literal,
|
|
27
28
|
)
|
|
28
29
|
|
|
29
|
-
from opentrons_shared_data.labware.types import
|
|
30
|
+
from opentrons_shared_data.labware.types import (
|
|
31
|
+
LabwareDefinition,
|
|
32
|
+
LabwareDefinition2,
|
|
33
|
+
LabwareParameters2,
|
|
34
|
+
LabwareParameters3,
|
|
35
|
+
)
|
|
30
36
|
|
|
31
|
-
from opentrons.types import
|
|
37
|
+
from opentrons.types import (
|
|
38
|
+
Location,
|
|
39
|
+
Point,
|
|
40
|
+
NozzleMapInterface,
|
|
41
|
+
MeniscusTrackingTarget,
|
|
42
|
+
)
|
|
32
43
|
from opentrons.protocols.api_support.types import APIVersion
|
|
33
44
|
from opentrons.protocols.api_support.util import (
|
|
34
45
|
requires_version,
|
|
35
46
|
APIVersionError,
|
|
36
47
|
UnsupportedAPIError,
|
|
37
48
|
)
|
|
38
|
-
|
|
49
|
+
from opentrons.protocol_engine.types.liquid_level_detection import LiquidTrackingType
|
|
39
50
|
|
|
40
51
|
# TODO(mc, 2022-09-02): re-exports provided for backwards compatibility
|
|
41
52
|
# remove when their usage is no longer needed
|
|
@@ -49,7 +60,10 @@ from . import validation
|
|
|
49
60
|
from ._liquid import Liquid
|
|
50
61
|
from ._types import OffDeckType
|
|
51
62
|
from .core import well_grid
|
|
52
|
-
from .core.engine import
|
|
63
|
+
from .core.engine import (
|
|
64
|
+
ENGINE_CORE_API_VERSION,
|
|
65
|
+
SET_OFFSET_RESTORED_API_VERSION,
|
|
66
|
+
)
|
|
53
67
|
from .core.labware import AbstractLabware
|
|
54
68
|
from .core.module import AbstractModuleCore
|
|
55
69
|
from .core.core_map import LoadedCoreMap
|
|
@@ -248,16 +262,21 @@ class Well:
|
|
|
248
262
|
return Location(self._core.get_center(), self)
|
|
249
263
|
|
|
250
264
|
@requires_version(2, 21)
|
|
251
|
-
def meniscus(
|
|
265
|
+
def meniscus(
|
|
266
|
+
self, target: Literal["start", "end", "dynamic"], z: float = 0.0
|
|
267
|
+
) -> Location:
|
|
252
268
|
"""
|
|
253
269
|
:param z: An offset on the z-axis, in mm. Positive offsets are higher and
|
|
254
270
|
negative offsets are lower.
|
|
271
|
+
:param target: The relative position inside the well to target when performing a liquid handling operation.
|
|
255
272
|
:return: A :py:class:`~opentrons.types.Location` that indicates location is meniscus and that holds the ``z`` offset in its point.z field.
|
|
256
273
|
|
|
257
274
|
:meta private:
|
|
258
275
|
"""
|
|
259
276
|
return Location(
|
|
260
|
-
point=Point(x=0, y=0, z=z),
|
|
277
|
+
point=Point(x=0, y=0, z=z),
|
|
278
|
+
labware=self,
|
|
279
|
+
_meniscus_tracking=MeniscusTrackingTarget(target),
|
|
261
280
|
)
|
|
262
281
|
|
|
263
282
|
@requires_version(2, 8)
|
|
@@ -316,6 +335,35 @@ class Well:
|
|
|
316
335
|
volume=volume,
|
|
317
336
|
)
|
|
318
337
|
|
|
338
|
+
@requires_version(2, 21)
|
|
339
|
+
def current_liquid_height(self) -> LiquidTrackingType:
|
|
340
|
+
"""Get the current liquid height in a well."""
|
|
341
|
+
return self._core.current_liquid_height()
|
|
342
|
+
|
|
343
|
+
@requires_version(2, 21)
|
|
344
|
+
def current_liquid_volume(self) -> LiquidTrackingType:
|
|
345
|
+
"""Get the current liquid volume in a well."""
|
|
346
|
+
return self._core.get_liquid_volume()
|
|
347
|
+
|
|
348
|
+
@requires_version(2, 21)
|
|
349
|
+
def estimate_liquid_height_after_pipetting(
|
|
350
|
+
self,
|
|
351
|
+
operation_volume: float,
|
|
352
|
+
) -> LiquidTrackingType:
|
|
353
|
+
"""Check the height of the liquid within a well.
|
|
354
|
+
|
|
355
|
+
:returns: The height, in mm, of the liquid from the deck.
|
|
356
|
+
|
|
357
|
+
:meta private:
|
|
358
|
+
|
|
359
|
+
This is intended for Opentrons internal use only and is not a guaranteed API.
|
|
360
|
+
"""
|
|
361
|
+
|
|
362
|
+
projected_final_height = self._core.estimate_liquid_height_after_pipetting(
|
|
363
|
+
operation_volume=operation_volume,
|
|
364
|
+
)
|
|
365
|
+
return projected_final_height
|
|
366
|
+
|
|
319
367
|
def _from_center_cartesian(self, x: float, y: float, z: float) -> Point:
|
|
320
368
|
"""
|
|
321
369
|
Private version of from_center_cartesian. Present only for backward
|
|
@@ -509,7 +557,7 @@ class Labware:
|
|
|
509
557
|
|
|
510
558
|
@property
|
|
511
559
|
@requires_version(2, 0)
|
|
512
|
-
def parameters(self) -> "
|
|
560
|
+
def parameters(self) -> "LabwareParameters2 | LabwareParameters3":
|
|
513
561
|
"""Internal properties of a labware including type and quirks."""
|
|
514
562
|
return self._core.get_parameters()
|
|
515
563
|
|
|
@@ -658,6 +706,8 @@ class Labware:
|
|
|
658
706
|
automatically.
|
|
659
707
|
|
|
660
708
|
:return: The initialized and loaded labware object representing the Lid Stack.
|
|
709
|
+
|
|
710
|
+
:meta private:
|
|
661
711
|
"""
|
|
662
712
|
if self._api_version < validation.LID_STACK_VERSION_GATE:
|
|
663
713
|
raise APIVersionError(
|
|
@@ -712,11 +762,15 @@ class Labware:
|
|
|
712
762
|
|
|
713
763
|
.. list-table::
|
|
714
764
|
:header-rows: 1
|
|
765
|
+
:widths: 1 5
|
|
715
766
|
|
|
716
767
|
* - API level
|
|
717
768
|
- Offset behavior
|
|
718
769
|
* - 2.12–2.13
|
|
719
770
|
- Offsets only apply to the exact :py:class:`.Labware` instance.
|
|
771
|
+
|
|
772
|
+
If your protocol has multiple instances of the same type of labware,
|
|
773
|
+
you must either use ``set_offset()`` on all of them or none of them.
|
|
720
774
|
* - 2.14–2.17
|
|
721
775
|
- ``set_offset()`` is not available, and the API raises an error.
|
|
722
776
|
* - 2.18 and newer
|
|
@@ -1417,7 +1471,7 @@ def next_available_tip(
|
|
|
1417
1471
|
# TODO(mc, 2022-11-09): implementation detail, move somewhere else
|
|
1418
1472
|
# only used in old calibration flows by robot-server
|
|
1419
1473
|
def load_from_definition(
|
|
1420
|
-
definition: "
|
|
1474
|
+
definition: "LabwareDefinition2",
|
|
1421
1475
|
parent: Location,
|
|
1422
1476
|
label: Optional[str] = None,
|
|
1423
1477
|
api_level: Optional[APIVersion] = None,
|
|
@@ -1461,8 +1515,8 @@ def load(
|
|
|
1461
1515
|
label: Optional[str] = None,
|
|
1462
1516
|
namespace: Optional[str] = None,
|
|
1463
1517
|
version: int = 1,
|
|
1464
|
-
bundled_defs: Optional[
|
|
1465
|
-
extra_defs: Optional[
|
|
1518
|
+
bundled_defs: Optional[Mapping[str, LabwareDefinition2]] = None,
|
|
1519
|
+
extra_defs: Optional[Mapping[str, LabwareDefinition2]] = None,
|
|
1466
1520
|
api_level: Optional[APIVersion] = None,
|
|
1467
1521
|
) -> Labware:
|
|
1468
1522
|
"""
|
|
@@ -1500,4 +1554,14 @@ def load(
|
|
|
1500
1554
|
extra_defs=extra_defs,
|
|
1501
1555
|
)
|
|
1502
1556
|
|
|
1557
|
+
# The legacy `load_from_definition()` function that we're calling only supports
|
|
1558
|
+
# schemaVersion==2 labware. Fortunately, when robot-server calls this function,
|
|
1559
|
+
# we only expect it to try to load schemaVersion==2 labware, so we never expect
|
|
1560
|
+
# this ValueError to be raised in practice.
|
|
1561
|
+
if definition["schemaVersion"] != 2:
|
|
1562
|
+
raise ValueError(
|
|
1563
|
+
f"{namespace}/{load_name}/{version} has schema {definition['schemaVersion']}."
|
|
1564
|
+
" Only schema 2 is supported."
|
|
1565
|
+
)
|
|
1566
|
+
|
|
1503
1567
|
return load_from_definition(definition, parent, label, api_level)
|
|
@@ -29,6 +29,7 @@ from .core.common import (
|
|
|
29
29
|
HeaterShakerCore,
|
|
30
30
|
MagneticBlockCore,
|
|
31
31
|
AbsorbanceReaderCore,
|
|
32
|
+
FlexStackerCore,
|
|
32
33
|
)
|
|
33
34
|
from .core.core_map import LoadedCoreMap
|
|
34
35
|
from .core.engine import ENGINE_CORE_API_VERSION
|
|
@@ -1098,3 +1099,142 @@ class AbsorbanceReaderContext(ModuleContext):
|
|
|
1098
1099
|
:returns: A dictionary of wavelengths to dictionary of values ordered by well name.
|
|
1099
1100
|
"""
|
|
1100
1101
|
return self._core.read(filename=export_filename)
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
class FlexStackerContext(ModuleContext):
|
|
1105
|
+
"""An object representing a connected Flex Stacker module.
|
|
1106
|
+
|
|
1107
|
+
It should not be instantiated directly; instead, it should be
|
|
1108
|
+
created through :py:meth:`.ProtocolContext.load_module`.
|
|
1109
|
+
|
|
1110
|
+
.. versionadded:: 2.23
|
|
1111
|
+
"""
|
|
1112
|
+
|
|
1113
|
+
_core: FlexStackerCore
|
|
1114
|
+
|
|
1115
|
+
@property
|
|
1116
|
+
@requires_version(2, 23)
|
|
1117
|
+
def serial_number(self) -> str:
|
|
1118
|
+
"""Get the module's unique hardware serial number."""
|
|
1119
|
+
return self._core.get_serial_number()
|
|
1120
|
+
|
|
1121
|
+
@requires_version(2, 23)
|
|
1122
|
+
def retrieve(self) -> Labware:
|
|
1123
|
+
"""Retrieve a labware from the Flex Stacker and place it on the shuttle.
|
|
1124
|
+
|
|
1125
|
+
:returns: The retrieved :py:class:`Labware` object. This will always be the main labware,
|
|
1126
|
+
even if the Flex Stacker contains labware on an adapter. To get the adapter object,
|
|
1127
|
+
call :py:class:`Labware.parent` on the returned labware.
|
|
1128
|
+
|
|
1129
|
+
"""
|
|
1130
|
+
self._core.retrieve()
|
|
1131
|
+
|
|
1132
|
+
labware_core = self._protocol_core.get_labware_on_module(self._core)
|
|
1133
|
+
if labware_core is not None and labware_core.is_adapter():
|
|
1134
|
+
adapter_core = labware_core
|
|
1135
|
+
adapter = Labware(
|
|
1136
|
+
core=adapter_core,
|
|
1137
|
+
api_version=self._api_version,
|
|
1138
|
+
protocol_core=self._protocol_core,
|
|
1139
|
+
core_map=self._core_map,
|
|
1140
|
+
)
|
|
1141
|
+
self._core_map.add(adapter_core, adapter)
|
|
1142
|
+
labware_core = self._protocol_core.get_labware_on_labware(adapter_core)
|
|
1143
|
+
|
|
1144
|
+
# the core retrieve command should have already raised the error
|
|
1145
|
+
# if labware_core is None, this is just to satisfy the type checker
|
|
1146
|
+
assert labware_core is not None, "Retrieve failed to return labware"
|
|
1147
|
+
# check core map first
|
|
1148
|
+
try:
|
|
1149
|
+
labware = self._core_map.get(labware_core)
|
|
1150
|
+
except KeyError:
|
|
1151
|
+
# If the labware is not already in the core map,
|
|
1152
|
+
# create a new Labware object
|
|
1153
|
+
labware = Labware(
|
|
1154
|
+
core=labware_core,
|
|
1155
|
+
api_version=self._api_version,
|
|
1156
|
+
protocol_core=self._protocol_core,
|
|
1157
|
+
core_map=self._core_map,
|
|
1158
|
+
)
|
|
1159
|
+
self._core_map.add(labware_core, labware)
|
|
1160
|
+
return labware
|
|
1161
|
+
|
|
1162
|
+
@requires_version(2, 23)
|
|
1163
|
+
def store(self) -> None:
|
|
1164
|
+
"""Move the labware currently on the Flex Stacker shuttle into the Flex Stacker."""
|
|
1165
|
+
self._core.store()
|
|
1166
|
+
|
|
1167
|
+
@requires_version(2, 23)
|
|
1168
|
+
def set_stored_labware(
|
|
1169
|
+
self,
|
|
1170
|
+
load_name: str,
|
|
1171
|
+
namespace: str | None = None,
|
|
1172
|
+
version: int | None = None,
|
|
1173
|
+
adapter: str | None = None,
|
|
1174
|
+
lid: str | None = None,
|
|
1175
|
+
count: int | None = None,
|
|
1176
|
+
) -> None:
|
|
1177
|
+
"""Configure what kind of labware the Flex Stacker will store.
|
|
1178
|
+
|
|
1179
|
+
:param str load_name: A string to use for looking up a labware definition.
|
|
1180
|
+
You can find the ``load_name`` for any Opentrons-verified labware on the
|
|
1181
|
+
`Labware Library <https://labware.opentrons.com>`__.
|
|
1182
|
+
:param str namespace: The namespace that the labware definition belongs to.
|
|
1183
|
+
If unspecified, the API will automatically search two namespaces:
|
|
1184
|
+
|
|
1185
|
+
- ``"opentrons"``, to load standard Opentrons labware definitions.
|
|
1186
|
+
- ``"custom_beta"``, to load custom labware definitions created with the
|
|
1187
|
+
`Custom Labware Creator <https://labware.opentrons.com/create>`__.
|
|
1188
|
+
|
|
1189
|
+
You might need to specify an explicit ``namespace`` if you have a custom
|
|
1190
|
+
definition whose ``load_name`` is the same as an Opentrons-verified
|
|
1191
|
+
definition, and you want to explicitly choose one or the other.
|
|
1192
|
+
:param version: The version of the labware definition. You should normally
|
|
1193
|
+
leave this unspecified to let ``load_labware()`` choose a version
|
|
1194
|
+
automatically.
|
|
1195
|
+
:param adapter: An adapter to load the labware on top of. Accepts the same
|
|
1196
|
+
values as the ``load_name`` parameter of :py:meth:`.load_adapter`. The
|
|
1197
|
+
adapter will use the same namespace as the labware, and the API will
|
|
1198
|
+
choose the adapter's version automatically.
|
|
1199
|
+
:param lid: A lid to load the on top of the main labware. Accepts the same
|
|
1200
|
+
values as the ``load_name`` parameter of :py:meth:`.load_lid_stack`. The
|
|
1201
|
+
lid will use the same namespace as the labware, and the API will
|
|
1202
|
+
choose the lid's version automatically.
|
|
1203
|
+
:param count: The number of labware that the Flex Stacker should start the protocol
|
|
1204
|
+
storing. If not specified, this will be the maximum amount of this kind of
|
|
1205
|
+
labware that the Flex Stacker is capable of storing.
|
|
1206
|
+
|
|
1207
|
+
"""
|
|
1208
|
+
self._core.set_stored_labware(
|
|
1209
|
+
main_load_name=load_name,
|
|
1210
|
+
main_namespace=namespace,
|
|
1211
|
+
main_version=version,
|
|
1212
|
+
lid_load_name=lid,
|
|
1213
|
+
lid_namespace=namespace,
|
|
1214
|
+
lid_version=version,
|
|
1215
|
+
adapter_load_name=adapter,
|
|
1216
|
+
adapter_namespace=namespace,
|
|
1217
|
+
adapter_version=version,
|
|
1218
|
+
count=count,
|
|
1219
|
+
)
|
|
1220
|
+
|
|
1221
|
+
@requires_version(2, 23)
|
|
1222
|
+
def fill(self, message: str, count: int | None = None) -> None:
|
|
1223
|
+
"""Pause the protocol to add more labware to the Flex Stacker.
|
|
1224
|
+
|
|
1225
|
+
:param message: A message to display in the Opentrons App to note what kind of labware to add.
|
|
1226
|
+
:param count: The amount of labware the Flex Stacker should hold after this command is executed.
|
|
1227
|
+
If not specified, the Flex Stacker should be full after this command is executed.
|
|
1228
|
+
"""
|
|
1229
|
+
self._core.fill(message, count)
|
|
1230
|
+
|
|
1231
|
+
@requires_version(2, 23)
|
|
1232
|
+
def empty(self, message: str) -> None:
|
|
1233
|
+
"""Pause the protocol to remove labware from the Flex Stacker.
|
|
1234
|
+
|
|
1235
|
+
:param message: A message to display in the Opentrons App to note what should be removed from
|
|
1236
|
+
the Flex Stacker.
|
|
1237
|
+
"""
|
|
1238
|
+
self._core.empty(
|
|
1239
|
+
message,
|
|
1240
|
+
)
|
|
@@ -14,17 +14,19 @@ from typing import (
|
|
|
14
14
|
|
|
15
15
|
from opentrons_shared_data.labware.types import LabwareDefinition
|
|
16
16
|
from opentrons_shared_data.pipette.types import PipetteNameType
|
|
17
|
-
from opentrons_shared_data.robot.types import RobotTypeEnum
|
|
18
17
|
|
|
19
18
|
from opentrons.types import Mount, Location, DeckLocation, DeckSlotName, StagingSlotName
|
|
20
|
-
from opentrons.config import feature_flags
|
|
21
19
|
from opentrons.legacy_broker import LegacyBroker
|
|
22
20
|
from opentrons.hardware_control.modules.types import (
|
|
23
21
|
MagneticBlockModel,
|
|
24
22
|
AbsorbanceReaderModel,
|
|
23
|
+
FlexStackerModuleModel,
|
|
25
24
|
)
|
|
26
25
|
from opentrons.legacy_commands import protocol_commands as cmds, types as cmd_types
|
|
27
|
-
from opentrons.legacy_commands.helpers import
|
|
26
|
+
from opentrons.legacy_commands.helpers import (
|
|
27
|
+
stringify_labware_movement_command,
|
|
28
|
+
stringify_lid_movement_command,
|
|
29
|
+
)
|
|
28
30
|
from opentrons.legacy_commands.publisher import (
|
|
29
31
|
CommandPublisher,
|
|
30
32
|
publish,
|
|
@@ -58,6 +60,7 @@ from .core.module import (
|
|
|
58
60
|
AbstractHeaterShakerCore,
|
|
59
61
|
AbstractMagneticBlockCore,
|
|
60
62
|
AbstractAbsorbanceReaderCore,
|
|
63
|
+
AbstractFlexStackerCore,
|
|
61
64
|
)
|
|
62
65
|
from .robot_context import RobotContext, HardwareManager
|
|
63
66
|
from .core.engine import ENGINE_CORE_API_VERSION
|
|
@@ -76,6 +79,7 @@ from .module_contexts import (
|
|
|
76
79
|
HeaterShakerContext,
|
|
77
80
|
MagneticBlockContext,
|
|
78
81
|
AbsorbanceReaderContext,
|
|
82
|
+
FlexStackerContext,
|
|
79
83
|
ModuleContext,
|
|
80
84
|
)
|
|
81
85
|
from ._parameters import Parameters
|
|
@@ -91,6 +95,7 @@ ModuleTypes = Union[
|
|
|
91
95
|
HeaterShakerContext,
|
|
92
96
|
MagneticBlockContext,
|
|
93
97
|
AbsorbanceReaderContext,
|
|
98
|
+
FlexStackerContext,
|
|
94
99
|
]
|
|
95
100
|
|
|
96
101
|
|
|
@@ -444,13 +449,16 @@ class ProtocolContext(CommandPublisher):
|
|
|
444
449
|
values as the ``load_name`` parameter of :py:meth:`.load_adapter`. The
|
|
445
450
|
adapter will use the same namespace as the labware, and the API will
|
|
446
451
|
choose the adapter's version automatically.
|
|
447
|
-
:param lid: A lid to load the on top of the main labware. Accepts the same
|
|
448
|
-
values as the ``load_name`` parameter of :py:meth:`.load_lid_stack`. The
|
|
449
|
-
lid will use the same namespace as the labware, and the API will
|
|
450
|
-
choose the lid's version automatically.
|
|
451
452
|
|
|
452
453
|
.. versionadded:: 2.15
|
|
453
454
|
"""
|
|
455
|
+
# TODO: re-include in docstring when 2.23 is ready
|
|
456
|
+
# :param lid: A lid to load the on top of the main labware. Accepts the same
|
|
457
|
+
# values as the ``load_name`` parameter of :py:meth:`.load_lid_stack`. The
|
|
458
|
+
# lid will use the same namespace as the labware, and the API will
|
|
459
|
+
# choose the lid's version automatically.
|
|
460
|
+
#
|
|
461
|
+
# .. versionadded:: 2.23
|
|
454
462
|
if isinstance(location, OffDeckType) and self._api_version < APIVersion(2, 15):
|
|
455
463
|
raise APIVersionError(
|
|
456
464
|
api_element="Loading a labware off-deck",
|
|
@@ -859,6 +867,10 @@ class ProtocolContext(CommandPublisher):
|
|
|
859
867
|
|
|
860
868
|
.. versionchanged:: 2.15
|
|
861
869
|
Added ``MagneticBlockContext`` return value.
|
|
870
|
+
|
|
871
|
+
.. TODO uncomment when 2.23 is ready
|
|
872
|
+
versionchanged:: 2.23
|
|
873
|
+
Added ``FlexStackerModuleContext`` return value.
|
|
862
874
|
"""
|
|
863
875
|
if configuration:
|
|
864
876
|
if self._api_version < APIVersion(2, 4):
|
|
@@ -887,7 +899,18 @@ class ProtocolContext(CommandPublisher):
|
|
|
887
899
|
requested_model, AbsorbanceReaderModel
|
|
888
900
|
) and self._api_version < APIVersion(2, 21):
|
|
889
901
|
raise APIVersionError(
|
|
890
|
-
f"Module of type {module_name}
|
|
902
|
+
api_element=f"Module of type {module_name}",
|
|
903
|
+
until_version="2.21",
|
|
904
|
+
current_version=f"{self._api_version}",
|
|
905
|
+
)
|
|
906
|
+
if (
|
|
907
|
+
isinstance(requested_model, FlexStackerModuleModel)
|
|
908
|
+
and self._api_version < validation.FLEX_STACKER_VERSION_GATE
|
|
909
|
+
):
|
|
910
|
+
raise APIVersionError(
|
|
911
|
+
api_element=f"Module of type {module_name}",
|
|
912
|
+
until_version=str(validation.FLEX_STACKER_VERSION_GATE),
|
|
913
|
+
current_version=f"{self._api_version}",
|
|
891
914
|
)
|
|
892
915
|
|
|
893
916
|
deck_slot = (
|
|
@@ -898,7 +921,11 @@ class ProtocolContext(CommandPublisher):
|
|
|
898
921
|
)
|
|
899
922
|
)
|
|
900
923
|
if isinstance(deck_slot, StagingSlotName):
|
|
901
|
-
|
|
924
|
+
# flex stacker modules can only be loaded into staging slot inside a protocol
|
|
925
|
+
if isinstance(requested_model, FlexStackerModuleModel):
|
|
926
|
+
deck_slot = validation.convert_flex_stacker_load_slot(deck_slot)
|
|
927
|
+
else:
|
|
928
|
+
raise ValueError(f"Cannot load {module_name} onto a staging slot.")
|
|
902
929
|
|
|
903
930
|
module_core = self._core.load_module(
|
|
904
931
|
model=requested_model,
|
|
@@ -1329,17 +1356,17 @@ class ProtocolContext(CommandPublisher):
|
|
|
1329
1356
|
display_color=display_color,
|
|
1330
1357
|
)
|
|
1331
1358
|
|
|
1359
|
+
@requires_version(2, 23)
|
|
1332
1360
|
def define_liquid_class(
|
|
1333
1361
|
self,
|
|
1334
1362
|
name: str,
|
|
1335
1363
|
) -> LiquidClass:
|
|
1336
|
-
"""
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
raise NotImplementedError("This method is not implemented.")
|
|
1364
|
+
"""
|
|
1365
|
+
Define a liquid class for use in the protocol.
|
|
1366
|
+
|
|
1367
|
+
:meta private:
|
|
1368
|
+
"""
|
|
1369
|
+
return self._core.define_liquid_class(name=name)
|
|
1343
1370
|
|
|
1344
1371
|
@property
|
|
1345
1372
|
@requires_version(2, 5)
|
|
@@ -1392,6 +1419,8 @@ class ProtocolContext(CommandPublisher):
|
|
|
1392
1419
|
automatically.
|
|
1393
1420
|
|
|
1394
1421
|
:return: The initialized and loaded labware object representing the Lid Stack.
|
|
1422
|
+
|
|
1423
|
+
:meta private:
|
|
1395
1424
|
"""
|
|
1396
1425
|
if self._api_version < validation.LID_STACK_VERSION_GATE:
|
|
1397
1426
|
raise APIVersionError(
|
|
@@ -1441,6 +1470,115 @@ class ProtocolContext(CommandPublisher):
|
|
|
1441
1470
|
)
|
|
1442
1471
|
return labware
|
|
1443
1472
|
|
|
1473
|
+
@requires_version(2, 23)
|
|
1474
|
+
def move_lid(
|
|
1475
|
+
self,
|
|
1476
|
+
source_location: Union[DeckLocation, Labware],
|
|
1477
|
+
new_location: Union[DeckLocation, Labware, OffDeckType, WasteChute, TrashBin],
|
|
1478
|
+
use_gripper: bool = False,
|
|
1479
|
+
pick_up_offset: Optional[Mapping[str, float]] = None,
|
|
1480
|
+
drop_offset: Optional[Mapping[str, float]] = None,
|
|
1481
|
+
) -> Labware | None:
|
|
1482
|
+
"""Move a lid from a valid source to a new location. Can return a Lid Stack if one is created.
|
|
1483
|
+
|
|
1484
|
+
:param source_location: Where to take the lid from. This is either:
|
|
1485
|
+
|
|
1486
|
+
* A deck slot like ``1``, ``"1"``, or ``"D1"``. See :ref:`deck-slots`.
|
|
1487
|
+
* A labware or adapter that's already been loaded on the deck
|
|
1488
|
+
with :py:meth:`load_labware` or :py:meth:`load_adapter`.
|
|
1489
|
+
* A lid stack that's already been loaded on the deck with
|
|
1490
|
+
with :py:meth:`load_lid_stack`.
|
|
1491
|
+
|
|
1492
|
+
:param new_location: Where to move the lid to. This is either:
|
|
1493
|
+
|
|
1494
|
+
* A deck slot like ``1``, ``"1"``, or ``"D1"``. See :ref:`deck-slots`.
|
|
1495
|
+
* A hardware module that's already been loaded on the deck
|
|
1496
|
+
with :py:meth:`load_module`.
|
|
1497
|
+
* A labware or adapter that's already been loaded on the deck
|
|
1498
|
+
with :py:meth:`load_labware` or :py:meth:`load_adapter`.
|
|
1499
|
+
* The special constant :py:obj:`OFF_DECK`.
|
|
1500
|
+
|
|
1501
|
+
:param use_gripper: Whether to use the Flex Gripper for this movement.
|
|
1502
|
+
|
|
1503
|
+
* If ``True``, use the gripper to perform an automatic
|
|
1504
|
+
movement. This will raise an error in an OT-2 protocol.
|
|
1505
|
+
* If ``False``, pause protocol execution until the user
|
|
1506
|
+
performs the movement. Protocol execution remains paused until
|
|
1507
|
+
the user presses **Confirm and resume**.
|
|
1508
|
+
|
|
1509
|
+
Gripper-only parameters:
|
|
1510
|
+
|
|
1511
|
+
:param pick_up_offset: Optional x, y, z vector offset to use when picking up a lid.
|
|
1512
|
+
:param drop_offset: Optional x, y, z vector offset to use when dropping off a lid.
|
|
1513
|
+
|
|
1514
|
+
Before moving a lid to or from a labware in a hardware module, make sure that the
|
|
1515
|
+
labware's current and new locations are accessible, i.e., open the Thermocycler lid
|
|
1516
|
+
or open the Heater-Shaker's labware latch.
|
|
1517
|
+
|
|
1518
|
+
:meta private:
|
|
1519
|
+
"""
|
|
1520
|
+
source: Union[LabwareCore, DeckSlotName, StagingSlotName]
|
|
1521
|
+
if isinstance(source_location, Labware):
|
|
1522
|
+
source = source_location._core
|
|
1523
|
+
else:
|
|
1524
|
+
source = validation.ensure_and_convert_deck_slot(
|
|
1525
|
+
source_location, self._api_version, self._core.robot_type
|
|
1526
|
+
)
|
|
1527
|
+
|
|
1528
|
+
destination: Union[
|
|
1529
|
+
ModuleCore,
|
|
1530
|
+
LabwareCore,
|
|
1531
|
+
WasteChute,
|
|
1532
|
+
OffDeckType,
|
|
1533
|
+
DeckSlotName,
|
|
1534
|
+
StagingSlotName,
|
|
1535
|
+
TrashBin,
|
|
1536
|
+
]
|
|
1537
|
+
if isinstance(new_location, Labware):
|
|
1538
|
+
destination = new_location._core
|
|
1539
|
+
elif isinstance(new_location, (OffDeckType, WasteChute, TrashBin)):
|
|
1540
|
+
destination = new_location
|
|
1541
|
+
else:
|
|
1542
|
+
destination = validation.ensure_and_convert_deck_slot(
|
|
1543
|
+
new_location, self._api_version, self._core.robot_type
|
|
1544
|
+
)
|
|
1545
|
+
|
|
1546
|
+
_pick_up_offset = (
|
|
1547
|
+
validation.ensure_valid_labware_offset_vector(pick_up_offset)
|
|
1548
|
+
if pick_up_offset
|
|
1549
|
+
else None
|
|
1550
|
+
)
|
|
1551
|
+
_drop_offset = (
|
|
1552
|
+
validation.ensure_valid_labware_offset_vector(drop_offset)
|
|
1553
|
+
if drop_offset
|
|
1554
|
+
else None
|
|
1555
|
+
)
|
|
1556
|
+
with publish_context(
|
|
1557
|
+
broker=self.broker,
|
|
1558
|
+
command=cmds.move_labware(
|
|
1559
|
+
# This needs to be called from protocol context and not the command for import loop reasons
|
|
1560
|
+
text=stringify_lid_movement_command(
|
|
1561
|
+
source_location, new_location, use_gripper
|
|
1562
|
+
)
|
|
1563
|
+
),
|
|
1564
|
+
):
|
|
1565
|
+
result = self._core.move_lid(
|
|
1566
|
+
source_location=source,
|
|
1567
|
+
new_location=destination,
|
|
1568
|
+
use_gripper=use_gripper,
|
|
1569
|
+
pause_for_manual_move=True,
|
|
1570
|
+
pick_up_offset=_pick_up_offset,
|
|
1571
|
+
drop_offset=_drop_offset,
|
|
1572
|
+
)
|
|
1573
|
+
if result is not None:
|
|
1574
|
+
return Labware(
|
|
1575
|
+
core=result,
|
|
1576
|
+
api_version=self._api_version,
|
|
1577
|
+
protocol_core=self._core,
|
|
1578
|
+
core_map=self._core_map,
|
|
1579
|
+
)
|
|
1580
|
+
return None
|
|
1581
|
+
|
|
1444
1582
|
|
|
1445
1583
|
def _create_module_context(
|
|
1446
1584
|
module_core: Union[ModuleCore, NonConnectedModuleCore],
|
|
@@ -1462,6 +1600,8 @@ def _create_module_context(
|
|
|
1462
1600
|
module_cls = MagneticBlockContext
|
|
1463
1601
|
elif isinstance(module_core, AbstractAbsorbanceReaderCore):
|
|
1464
1602
|
module_cls = AbsorbanceReaderContext
|
|
1603
|
+
elif isinstance(module_core, AbstractFlexStackerCore):
|
|
1604
|
+
module_cls = FlexStackerContext
|
|
1465
1605
|
else:
|
|
1466
1606
|
assert False, "Unsupported module type"
|
|
1467
1607
|
|