opentrons 8.2.0a4__py2.py3-none-any.whl → 8.3.0a1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opentrons/calibration_storage/deck_configuration.py +3 -3
- opentrons/calibration_storage/file_operators.py +3 -3
- opentrons/calibration_storage/helpers.py +3 -1
- opentrons/calibration_storage/ot2/models/v1.py +16 -29
- opentrons/calibration_storage/ot2/tip_length.py +7 -4
- opentrons/calibration_storage/ot3/models/v1.py +14 -23
- opentrons/cli/analyze.py +18 -6
- opentrons/config/defaults_ot3.py +1 -0
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/errors.py +16 -3
- opentrons/drivers/asyncio/communication/serial_connection.py +24 -9
- opentrons/drivers/command_builder.py +2 -2
- opentrons/drivers/flex_stacker/__init__.py +9 -0
- opentrons/drivers/flex_stacker/abstract.py +89 -0
- opentrons/drivers/flex_stacker/driver.py +260 -0
- opentrons/drivers/flex_stacker/simulator.py +109 -0
- opentrons/drivers/flex_stacker/types.py +138 -0
- opentrons/drivers/heater_shaker/driver.py +18 -3
- opentrons/drivers/temp_deck/driver.py +13 -3
- opentrons/drivers/thermocycler/driver.py +17 -3
- opentrons/execute.py +3 -1
- opentrons/hardware_control/__init__.py +1 -2
- opentrons/hardware_control/api.py +28 -20
- opentrons/hardware_control/backends/flex_protocol.py +17 -7
- opentrons/hardware_control/backends/ot3controller.py +213 -63
- opentrons/hardware_control/backends/ot3simulator.py +18 -9
- opentrons/hardware_control/backends/ot3utils.py +43 -15
- opentrons/hardware_control/dev_types.py +4 -0
- opentrons/hardware_control/emulation/heater_shaker.py +4 -0
- opentrons/hardware_control/emulation/module_server/client.py +1 -1
- opentrons/hardware_control/emulation/module_server/server.py +5 -3
- opentrons/hardware_control/emulation/settings.py +3 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +2 -1
- opentrons/hardware_control/instruments/ot2/pipette.py +15 -22
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +8 -1
- opentrons/hardware_control/instruments/ot3/gripper.py +2 -2
- opentrons/hardware_control/instruments/ot3/pipette.py +23 -22
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -1
- opentrons/hardware_control/modules/mod_abc.py +2 -2
- opentrons/hardware_control/motion_utilities.py +68 -0
- opentrons/hardware_control/nozzle_manager.py +39 -41
- opentrons/hardware_control/ot3_calibration.py +1 -1
- opentrons/hardware_control/ot3api.py +60 -23
- opentrons/hardware_control/protocols/gripper_controller.py +3 -0
- opentrons/hardware_control/protocols/hardware_manager.py +5 -1
- opentrons/hardware_control/protocols/liquid_handler.py +18 -0
- opentrons/hardware_control/protocols/motion_controller.py +6 -0
- opentrons/hardware_control/robot_calibration.py +1 -1
- opentrons/hardware_control/types.py +61 -0
- opentrons/protocol_api/__init__.py +20 -1
- opentrons/protocol_api/_liquid.py +24 -49
- opentrons/protocol_api/_liquid_properties.py +754 -0
- opentrons/protocol_api/_types.py +24 -0
- opentrons/protocol_api/core/common.py +2 -0
- opentrons/protocol_api/core/engine/instrument.py +82 -10
- opentrons/protocol_api/core/engine/labware.py +29 -7
- opentrons/protocol_api/core/engine/protocol.py +130 -5
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/well.py +4 -1
- opentrons/protocol_api/core/instrument.py +46 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +37 -3
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +32 -1
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +37 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +158 -44
- opentrons/protocol_api/labware.py +231 -7
- opentrons/protocol_api/module_contexts.py +21 -17
- opentrons/protocol_api/protocol_context.py +125 -4
- opentrons/protocol_api/robot_context.py +204 -32
- opentrons/protocol_api/validation.py +262 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/actions.py +2 -3
- opentrons/protocol_engine/clients/sync_client.py +18 -0
- opentrons/protocol_engine/commands/__init__.py +81 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +0 -2
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +19 -5
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +0 -1
- opentrons/protocol_engine/commands/absorbance_reader/read.py +32 -9
- opentrons/protocol_engine/commands/air_gap_in_place.py +160 -0
- opentrons/protocol_engine/commands/aspirate.py +103 -53
- opentrons/protocol_engine/commands/aspirate_in_place.py +55 -51
- opentrons/protocol_engine/commands/blow_out.py +44 -39
- opentrons/protocol_engine/commands/blow_out_in_place.py +21 -32
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +13 -6
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +1 -1
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +3 -3
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +1 -1
- opentrons/protocol_engine/commands/command.py +73 -66
- opentrons/protocol_engine/commands/command_unions.py +101 -1
- opentrons/protocol_engine/commands/comment.py +1 -1
- opentrons/protocol_engine/commands/configure_for_volume.py +10 -3
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +6 -4
- opentrons/protocol_engine/commands/custom.py +6 -12
- opentrons/protocol_engine/commands/dispense.py +82 -48
- opentrons/protocol_engine/commands/dispense_in_place.py +71 -51
- opentrons/protocol_engine/commands/drop_tip.py +52 -31
- opentrons/protocol_engine/commands/drop_tip_in_place.py +13 -3
- opentrons/protocol_engine/commands/generate_command_schema.py +4 -11
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/home.py +13 -4
- opentrons/protocol_engine/commands/liquid_probe.py +67 -24
- opentrons/protocol_engine/commands/load_labware.py +29 -7
- opentrons/protocol_engine/commands/load_lid.py +146 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +189 -0
- opentrons/protocol_engine/commands/load_liquid.py +12 -4
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +31 -10
- opentrons/protocol_engine/commands/load_pipette.py +19 -8
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +1 -1
- opentrons/protocol_engine/commands/magnetic_module/engage.py +1 -1
- opentrons/protocol_engine/commands/move_labware.py +19 -6
- opentrons/protocol_engine/commands/move_relative.py +35 -25
- opentrons/protocol_engine/commands/move_to_addressable_area.py +40 -27
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +53 -32
- opentrons/protocol_engine/commands/move_to_coordinates.py +36 -22
- opentrons/protocol_engine/commands/move_to_well.py +40 -24
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +49 -27
- opentrons/protocol_engine/commands/pipetting_common.py +169 -87
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +24 -33
- opentrons/protocol_engine/commands/reload_labware.py +1 -1
- opentrons/protocol_engine/commands/retract_axis.py +1 -1
- opentrons/protocol_engine/commands/robot/__init__.py +69 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +77 -0
- opentrons/protocol_engine/commands/save_position.py +14 -5
- opentrons/protocol_engine/commands/set_rail_lights.py +1 -1
- opentrons/protocol_engine/commands/set_status_bar.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +8 -2
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +9 -3
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +11 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/touch_tip.py +65 -16
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +1 -4
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -4
- opentrons/protocol_engine/commands/verify_tip_presence.py +11 -4
- opentrons/protocol_engine/commands/wait_for_duration.py +10 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +10 -3
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/error_occurrence.py +19 -20
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +73 -5
- opentrons/protocol_engine/execution/gantry_mover.py +364 -8
- opentrons/protocol_engine/execution/movement.py +27 -0
- opentrons/protocol_engine/execution/pipetting.py +5 -1
- opentrons/protocol_engine/execution/tip_handler.py +4 -6
- opentrons/protocol_engine/notes/notes.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +7 -6
- opentrons/protocol_engine/resources/labware_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_validation.py +5 -0
- opentrons/protocol_engine/resources/module_data_provider.py +1 -1
- opentrons/protocol_engine/resources/pipette_data_provider.py +26 -0
- opentrons/protocol_engine/slot_standardization.py +9 -9
- opentrons/protocol_engine/state/_move_types.py +9 -5
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +25 -61
- opentrons/protocol_engine/state/command_history.py +12 -0
- opentrons/protocol_engine/state/commands.py +17 -13
- opentrons/protocol_engine/state/files.py +10 -12
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/frustum_helpers.py +57 -32
- opentrons/protocol_engine/state/geometry.py +47 -1
- opentrons/protocol_engine/state/labware.py +79 -25
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +16 -4
- opentrons/protocol_engine/state/modules.py +52 -70
- opentrons/protocol_engine/state/motion.py +6 -1
- opentrons/protocol_engine/state/pipettes.py +144 -58
- opentrons/protocol_engine/state/state.py +21 -2
- opentrons/protocol_engine/state/state_summary.py +4 -2
- opentrons/protocol_engine/state/tips.py +11 -44
- opentrons/protocol_engine/state/update_types.py +343 -48
- opentrons/protocol_engine/state/wells.py +19 -11
- opentrons/protocol_engine/types.py +176 -28
- opentrons/protocol_reader/extract_labware_definitions.py +5 -2
- opentrons/protocol_reader/file_format_validator.py +5 -5
- opentrons/protocol_runner/json_file_reader.py +9 -3
- opentrons/protocol_runner/json_translator.py +51 -25
- opentrons/protocol_runner/legacy_command_mapper.py +66 -64
- opentrons/protocol_runner/protocol_runner.py +35 -4
- opentrons/protocol_runner/python_protocol_wrappers.py +1 -1
- opentrons/protocol_runner/run_orchestrator.py +13 -3
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +1 -1
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +56 -0
- opentrons/protocols/advanced_control/{transfers.py → transfers/transfer.py} +10 -85
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +1 -1
- opentrons/protocols/api_support/util.py +10 -0
- opentrons/protocols/labware.py +39 -6
- opentrons/protocols/models/json_protocol.py +5 -9
- opentrons/simulate.py +3 -1
- opentrons/types.py +162 -2
- opentrons/util/logging_config.py +1 -1
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/METADATA +16 -15
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/RECORD +229 -202
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/WHEEL +1 -1
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/LICENSE +0 -0
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/entry_points.txt +0 -0
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""opentrons.protocol_api.labware: classes and functions for labware handling
|
|
2
2
|
|
|
3
3
|
This module provides things like :py:class:`Labware`, and :py:class:`Well`
|
|
4
4
|
to encapsulate labware instances used in protocols
|
|
@@ -13,18 +13,29 @@ from __future__ import annotations
|
|
|
13
13
|
import logging
|
|
14
14
|
|
|
15
15
|
from itertools import dropwhile
|
|
16
|
-
from typing import
|
|
16
|
+
from typing import (
|
|
17
|
+
TYPE_CHECKING,
|
|
18
|
+
Any,
|
|
19
|
+
List,
|
|
20
|
+
Dict,
|
|
21
|
+
Optional,
|
|
22
|
+
Union,
|
|
23
|
+
Tuple,
|
|
24
|
+
cast,
|
|
25
|
+
Sequence,
|
|
26
|
+
Mapping,
|
|
27
|
+
)
|
|
17
28
|
|
|
18
29
|
from opentrons_shared_data.labware.types import LabwareDefinition, LabwareParameters
|
|
19
30
|
|
|
20
|
-
from opentrons.types import Location, Point
|
|
31
|
+
from opentrons.types import Location, Point, NozzleMapInterface
|
|
21
32
|
from opentrons.protocols.api_support.types import APIVersion
|
|
22
33
|
from opentrons.protocols.api_support.util import (
|
|
23
34
|
requires_version,
|
|
24
35
|
APIVersionError,
|
|
25
36
|
UnsupportedAPIError,
|
|
26
37
|
)
|
|
27
|
-
|
|
38
|
+
|
|
28
39
|
|
|
29
40
|
# TODO(mc, 2022-09-02): re-exports provided for backwards compatibility
|
|
30
41
|
# remove when their usage is no longer needed
|
|
@@ -280,6 +291,10 @@ class Well:
|
|
|
280
291
|
|
|
281
292
|
:param Liquid liquid: The liquid to load into the well.
|
|
282
293
|
:param float volume: The volume of liquid to load, in µL.
|
|
294
|
+
|
|
295
|
+
.. TODO: flag as deprecated in 2.22 docs
|
|
296
|
+
In API version 2.22 and later, use :py:meth:`~Labware.load_liquid`, :py:meth:`~Labware.load_liquid_by_well`,
|
|
297
|
+
or :py:meth:`~Labware.load_empty` to load liquid into a well.
|
|
283
298
|
"""
|
|
284
299
|
self._core.load_liquid(
|
|
285
300
|
liquid=liquid,
|
|
@@ -529,6 +544,7 @@ class Labware:
|
|
|
529
544
|
self,
|
|
530
545
|
name: str,
|
|
531
546
|
label: Optional[str] = None,
|
|
547
|
+
lid: Optional[str] = None,
|
|
532
548
|
namespace: Optional[str] = None,
|
|
533
549
|
version: Optional[int] = None,
|
|
534
550
|
) -> Labware:
|
|
@@ -558,6 +574,20 @@ class Labware:
|
|
|
558
574
|
|
|
559
575
|
self._core_map.add(labware_core, labware)
|
|
560
576
|
|
|
577
|
+
if lid is not None:
|
|
578
|
+
if self._api_version < validation.LID_STACK_VERSION_GATE:
|
|
579
|
+
raise APIVersionError(
|
|
580
|
+
api_element="Loading a Lid on a Labware",
|
|
581
|
+
until_version="2.23",
|
|
582
|
+
current_version=f"{self._api_version}",
|
|
583
|
+
)
|
|
584
|
+
self._protocol_core.load_lid(
|
|
585
|
+
load_name=lid,
|
|
586
|
+
location=labware_core,
|
|
587
|
+
namespace=namespace,
|
|
588
|
+
version=version,
|
|
589
|
+
)
|
|
590
|
+
|
|
561
591
|
return labware
|
|
562
592
|
|
|
563
593
|
@requires_version(2, 15)
|
|
@@ -582,6 +612,65 @@ class Labware:
|
|
|
582
612
|
label=label,
|
|
583
613
|
)
|
|
584
614
|
|
|
615
|
+
@requires_version(2, 23)
|
|
616
|
+
def load_lid_stack(
|
|
617
|
+
self,
|
|
618
|
+
load_name: str,
|
|
619
|
+
quantity: int,
|
|
620
|
+
namespace: Optional[str] = None,
|
|
621
|
+
version: Optional[int] = None,
|
|
622
|
+
) -> Labware:
|
|
623
|
+
"""
|
|
624
|
+
Load a stack of Lids onto a valid Deck Location or Adapter.
|
|
625
|
+
|
|
626
|
+
:param str load_name: A string to use for looking up a lid definition.
|
|
627
|
+
You can find the ``load_name`` for any standard lid on the Opentrons
|
|
628
|
+
`Labware Library <https://labware.opentrons.com>`_.
|
|
629
|
+
:param int quantity: The quantity of lids to be loaded in the stack.
|
|
630
|
+
:param str namespace: The namespace that the lid labware definition belongs to.
|
|
631
|
+
If unspecified, the API will automatically search two namespaces:
|
|
632
|
+
|
|
633
|
+
- ``"opentrons"``, to load standard Opentrons labware definitions.
|
|
634
|
+
- ``"custom_beta"``, to load custom labware definitions created with the
|
|
635
|
+
`Custom Labware Creator <https://labware.opentrons.com/create>`__.
|
|
636
|
+
|
|
637
|
+
You might need to specify an explicit ``namespace`` if you have a custom
|
|
638
|
+
definition whose ``load_name`` is the same as an Opentrons-verified
|
|
639
|
+
definition, and you want to explicitly choose one or the other.
|
|
640
|
+
|
|
641
|
+
:param version: The version of the labware definition. You should normally
|
|
642
|
+
leave this unspecified to let ``load_lid_stack()`` choose a version
|
|
643
|
+
automatically.
|
|
644
|
+
|
|
645
|
+
:return: The initialized and loaded labware object representing the Lid Stack.
|
|
646
|
+
"""
|
|
647
|
+
if self._api_version < validation.LID_STACK_VERSION_GATE:
|
|
648
|
+
raise APIVersionError(
|
|
649
|
+
api_element="Loading a Lid Stack",
|
|
650
|
+
until_version="2.23",
|
|
651
|
+
current_version=f"{self._api_version}",
|
|
652
|
+
)
|
|
653
|
+
|
|
654
|
+
load_location = self._core
|
|
655
|
+
|
|
656
|
+
load_name = validation.ensure_lowercase_name(load_name)
|
|
657
|
+
|
|
658
|
+
result = self._protocol_core.load_lid_stack(
|
|
659
|
+
load_name=load_name,
|
|
660
|
+
location=load_location,
|
|
661
|
+
quantity=quantity,
|
|
662
|
+
namespace=namespace,
|
|
663
|
+
version=version,
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
labware = Labware(
|
|
667
|
+
core=result,
|
|
668
|
+
api_version=self._api_version,
|
|
669
|
+
protocol_core=self._protocol_core,
|
|
670
|
+
core_map=self._core_map,
|
|
671
|
+
)
|
|
672
|
+
return labware
|
|
673
|
+
|
|
585
674
|
def set_calibration(self, delta: Point) -> None:
|
|
586
675
|
"""
|
|
587
676
|
An internal, deprecated method used for updating the labware offset.
|
|
@@ -932,7 +1021,7 @@ class Labware:
|
|
|
932
1021
|
num_tips: int = 1,
|
|
933
1022
|
starting_tip: Optional[Well] = None,
|
|
934
1023
|
*,
|
|
935
|
-
nozzle_map: Optional[
|
|
1024
|
+
nozzle_map: Optional[NozzleMapInterface] = None,
|
|
936
1025
|
) -> Optional[Well]:
|
|
937
1026
|
"""
|
|
938
1027
|
Find the next valid well for pick-up.
|
|
@@ -1105,6 +1194,141 @@ class Labware:
|
|
|
1105
1194
|
"""
|
|
1106
1195
|
self._core.reset_tips()
|
|
1107
1196
|
|
|
1197
|
+
@requires_version(2, 22)
|
|
1198
|
+
def load_liquid(
|
|
1199
|
+
self, wells: Sequence[Union[str, Well]], volume: float, liquid: Liquid
|
|
1200
|
+
) -> None:
|
|
1201
|
+
"""Mark several wells as containing the same amount of liquid.
|
|
1202
|
+
|
|
1203
|
+
This method should be called at the beginning of a protocol, soon after loading the labware and before
|
|
1204
|
+
liquid handling operations begin. It is a base of information for liquid tracking functionality. If a well in a labware
|
|
1205
|
+
has not been named in a call to :py:meth:`~Labware.load_empty`, :py:meth:`~Labware.load_liquid`, or
|
|
1206
|
+
:py:meth:`~Labware.load_liquid_by_well`, the volume it contains is unknown and the well's liquid will not be tracked.
|
|
1207
|
+
|
|
1208
|
+
For example, to load 10µL of a liquid named ``water`` (defined with :py:meth:`~ProtocolContext.define_liquid`)
|
|
1209
|
+
into all the wells of a labware, you could call ``labware.load_liquid(labware.wells(), 10, water)``.
|
|
1210
|
+
|
|
1211
|
+
If you want to load different volumes of liquid into different wells, use :py:meth:`~Labware.load_liquid_by_well`.
|
|
1212
|
+
|
|
1213
|
+
If you want to mark the well as containing no liquid, use :py:meth:`~Labware.load_empty`.
|
|
1214
|
+
|
|
1215
|
+
:param wells: The wells to load the liquid into.
|
|
1216
|
+
:type wells: List of well names or list of Well objects, for instance from :py:meth:`~Labware.wells`.
|
|
1217
|
+
|
|
1218
|
+
:param volume: The volume of liquid to load into each well, in 10µL.
|
|
1219
|
+
:type volume: float
|
|
1220
|
+
|
|
1221
|
+
:param liquid: The liquid to load into each well, previously defined by :py:meth:`~ProtocolContext.define_liquid`
|
|
1222
|
+
:type liquid: Liquid
|
|
1223
|
+
"""
|
|
1224
|
+
well_names: List[str] = []
|
|
1225
|
+
for well in wells:
|
|
1226
|
+
if isinstance(well, str):
|
|
1227
|
+
if well not in self.wells_by_name():
|
|
1228
|
+
raise KeyError(
|
|
1229
|
+
f"{well} is not a well in labware {self.name}. The elements of wells should name wells in this labware."
|
|
1230
|
+
)
|
|
1231
|
+
well_names.append(well)
|
|
1232
|
+
elif isinstance(well, Well):
|
|
1233
|
+
if well.parent is not self:
|
|
1234
|
+
raise KeyError(
|
|
1235
|
+
f"{well.well_name} is not a well in labware {self.name}. The elements of wells should be wells of this labware."
|
|
1236
|
+
)
|
|
1237
|
+
well_names.append(well.well_name)
|
|
1238
|
+
else:
|
|
1239
|
+
raise TypeError(
|
|
1240
|
+
f"Unexpected type for element {repr(well)}. The elements of wells should be Well instances or well names."
|
|
1241
|
+
)
|
|
1242
|
+
if not isinstance(volume, (float, int)):
|
|
1243
|
+
raise TypeError(
|
|
1244
|
+
f"Unexpected type for volume {repr(volume)}. Volume should be a number in microliters."
|
|
1245
|
+
)
|
|
1246
|
+
self._core.load_liquid({well_name: volume for well_name in well_names}, liquid)
|
|
1247
|
+
|
|
1248
|
+
@requires_version(2, 22)
|
|
1249
|
+
def load_liquid_by_well(
|
|
1250
|
+
self, volumes: Mapping[Union[str, Well], float], liquid: Liquid
|
|
1251
|
+
) -> None:
|
|
1252
|
+
"""Mark several wells as containing unique volumes of liquid.
|
|
1253
|
+
|
|
1254
|
+
This method should be called at the beginning of a protocol, soon after loading the labware and before
|
|
1255
|
+
liquid handling operations begin. It is a base of information for liquid tracking functionality. If a well in a labware
|
|
1256
|
+
has not been named in a call to :py:meth:`~Labware.load_empty`, :py:meth:`~Labware.load_liquid`, or
|
|
1257
|
+
:py:meth:`~Labware.load_liquid_by_well`, the volume it contains is unknown and the well's liquid will not be tracked.
|
|
1258
|
+
|
|
1259
|
+
For example, to load a decreasing amount of of a liquid named ``water`` (defined with :py:meth:`~ProtocolContext.define_liquid`)
|
|
1260
|
+
into each successive well of a row, you could call
|
|
1261
|
+
``labware.load_liquid_by_well({'A1': 1000, 'A2': 950, 'A3': 900, ..., 'A12': 600}, water)``
|
|
1262
|
+
|
|
1263
|
+
If you want to load the same volume of a liquid into multiple wells, it is often easier to use :py:meth:`~Labware.load_liquid`.
|
|
1264
|
+
|
|
1265
|
+
If you want to mark the well as containing no liquid, use :py:meth:`~Labware.load_empty`.
|
|
1266
|
+
|
|
1267
|
+
:param volumes: A dictionary of well names (or :py:class:`Well` objects, for instance from ``labware['A1']``)
|
|
1268
|
+
:type wells: Dict[Union[str, Well], float]
|
|
1269
|
+
|
|
1270
|
+
:param liquid: The liquid to load into each well, previously defined by :py:meth:`~ProtocolContext.define_liquid`
|
|
1271
|
+
:type liquid: Liquid
|
|
1272
|
+
"""
|
|
1273
|
+
verified_volumes: Dict[str, float] = {}
|
|
1274
|
+
for well, volume in volumes.items():
|
|
1275
|
+
if isinstance(well, str):
|
|
1276
|
+
if well not in self.wells_by_name():
|
|
1277
|
+
raise KeyError(
|
|
1278
|
+
f"{well} is not a well in {self.name}. The keys of volumes should name wells in this labware"
|
|
1279
|
+
)
|
|
1280
|
+
verified_volumes[well] = volume
|
|
1281
|
+
elif isinstance(well, Well):
|
|
1282
|
+
if well.parent is not self:
|
|
1283
|
+
raise KeyError(
|
|
1284
|
+
f"{well.well_name} is not a well in {self.name}. The keys of volumes should be wells of this labware"
|
|
1285
|
+
)
|
|
1286
|
+
verified_volumes[well.well_name] = volume
|
|
1287
|
+
else:
|
|
1288
|
+
raise TypeError(
|
|
1289
|
+
f"Unexpected type for well name {repr(well)}. The keys of volumes should be Well instances or well names."
|
|
1290
|
+
)
|
|
1291
|
+
if not isinstance(volume, (float, int)):
|
|
1292
|
+
raise TypeError(
|
|
1293
|
+
f"Unexpected type for volume {repr(volume)}. The values of volumes should be numbers in microliters."
|
|
1294
|
+
)
|
|
1295
|
+
self._core.load_liquid(verified_volumes, liquid)
|
|
1296
|
+
|
|
1297
|
+
@requires_version(2, 22)
|
|
1298
|
+
def load_empty(self, wells: Sequence[Union[Well, str]]) -> None:
|
|
1299
|
+
"""Mark several wells as empty.
|
|
1300
|
+
|
|
1301
|
+
This method should be called at the beginning of a protocol, soon after loading the labware and before liquid handling
|
|
1302
|
+
operations begin. It is a base of information for liquid tracking functionality. If a well in a labware has not been named
|
|
1303
|
+
in a call to :py:meth:`Labware.load_empty`, :py:meth:`Labware.load_liquid`, or :py:meth:`Labware.load_liquid_by_well`, the
|
|
1304
|
+
volume it contains is unknown and the well's liquid will not be tracked.
|
|
1305
|
+
|
|
1306
|
+
For instance, to mark all wells in the labware as empty, you can call ``labware.load_empty(labware.wells())``.
|
|
1307
|
+
|
|
1308
|
+
:param wells: The list of wells to mark empty. To mark all wells as empty, pass ``labware.wells()``. You can also specify
|
|
1309
|
+
wells by their names (for instance, ``labware.load_empty(['A1', 'A2'])``).
|
|
1310
|
+
:type wells: Union[List[Well], List[str]]
|
|
1311
|
+
"""
|
|
1312
|
+
well_names: List[str] = []
|
|
1313
|
+
for well in wells:
|
|
1314
|
+
if isinstance(well, str):
|
|
1315
|
+
if well not in self.wells_by_name():
|
|
1316
|
+
raise KeyError(
|
|
1317
|
+
f"{well} is not a well in {self.name}. The elements of wells should name wells in this labware."
|
|
1318
|
+
)
|
|
1319
|
+
well_names.append(well)
|
|
1320
|
+
elif isinstance(well, Well):
|
|
1321
|
+
if well.parent is not self:
|
|
1322
|
+
raise KeyError(
|
|
1323
|
+
f"{well.well_name} is not a well in {self.name}. The elements of wells should be wells of this labware."
|
|
1324
|
+
)
|
|
1325
|
+
well_names.append(well.well_name)
|
|
1326
|
+
else:
|
|
1327
|
+
raise TypeError(
|
|
1328
|
+
f"Unexpected type for well name {repr(well)}. The elements of wells should be Well instances or well names."
|
|
1329
|
+
)
|
|
1330
|
+
self._core.load_empty(well_names)
|
|
1331
|
+
|
|
1108
1332
|
|
|
1109
1333
|
# TODO(mc, 2022-11-09): implementation detail, move to core
|
|
1110
1334
|
def split_tipracks(tip_racks: List[Labware]) -> Tuple[Labware, List[Labware]]:
|
|
@@ -1121,7 +1345,7 @@ def select_tiprack_from_list(
|
|
|
1121
1345
|
num_channels: int,
|
|
1122
1346
|
starting_point: Optional[Well] = None,
|
|
1123
1347
|
*,
|
|
1124
|
-
nozzle_map: Optional[
|
|
1348
|
+
nozzle_map: Optional[NozzleMapInterface] = None,
|
|
1125
1349
|
) -> Tuple[Labware, Well]:
|
|
1126
1350
|
try:
|
|
1127
1351
|
first, rest = split_tipracks(tip_racks)
|
|
@@ -1159,7 +1383,7 @@ def next_available_tip(
|
|
|
1159
1383
|
tip_racks: List[Labware],
|
|
1160
1384
|
channels: int,
|
|
1161
1385
|
*,
|
|
1162
|
-
nozzle_map: Optional[
|
|
1386
|
+
nozzle_map: Optional[NozzleMapInterface] = None,
|
|
1163
1387
|
) -> Tuple[Labware, Well]:
|
|
1164
1388
|
start = starting_tip
|
|
1165
1389
|
if start is None:
|
|
@@ -125,6 +125,7 @@ class ModuleContext(CommandPublisher):
|
|
|
125
125
|
namespace: Optional[str] = None,
|
|
126
126
|
version: Optional[int] = None,
|
|
127
127
|
adapter: Optional[str] = None,
|
|
128
|
+
lid: Optional[str] = None,
|
|
128
129
|
) -> Labware:
|
|
129
130
|
"""Load a labware onto the module using its load parameters.
|
|
130
131
|
|
|
@@ -180,6 +181,19 @@ class ModuleContext(CommandPublisher):
|
|
|
180
181
|
version=version,
|
|
181
182
|
location=load_location,
|
|
182
183
|
)
|
|
184
|
+
if lid is not None:
|
|
185
|
+
if self._api_version < validation.LID_STACK_VERSION_GATE:
|
|
186
|
+
raise APIVersionError(
|
|
187
|
+
api_element="Loading a lid on a Labware",
|
|
188
|
+
until_version="2.23",
|
|
189
|
+
current_version=f"{self._api_version}",
|
|
190
|
+
)
|
|
191
|
+
self._protocol_core.load_lid(
|
|
192
|
+
load_name=lid,
|
|
193
|
+
location=labware_core,
|
|
194
|
+
namespace=namespace,
|
|
195
|
+
version=version,
|
|
196
|
+
)
|
|
183
197
|
|
|
184
198
|
if isinstance(self._core, LegacyModuleCore):
|
|
185
199
|
labware = self._core.add_labware_core(cast(LegacyLabwareCore, labware_core))
|
|
@@ -608,7 +622,7 @@ class ThermocyclerContext(ModuleContext):
|
|
|
608
622
|
.. note::
|
|
609
623
|
|
|
610
624
|
The Thermocycler will proceed to the next command immediately after
|
|
611
|
-
``temperature``
|
|
625
|
+
``temperature`` is reached.
|
|
612
626
|
|
|
613
627
|
"""
|
|
614
628
|
self._core.set_target_lid_temperature(celsius=temperature)
|
|
@@ -625,28 +639,18 @@ class ThermocyclerContext(ModuleContext):
|
|
|
625
639
|
"""Execute a Thermocycler profile, defined as a cycle of
|
|
626
640
|
``steps``, for a given number of ``repetitions``.
|
|
627
641
|
|
|
628
|
-
:param steps: List of
|
|
629
|
-
Each list item should be a dictionary that maps to
|
|
630
|
-
|
|
631
|
-
|
|
642
|
+
:param steps: List of steps that make up a single cycle.
|
|
643
|
+
Each list item should be a dictionary that maps to the parameters
|
|
644
|
+
of the :py:meth:`set_block_temperature` method. The dictionary's
|
|
645
|
+
keys must be ``temperature`` and one or both of
|
|
632
646
|
``hold_time_seconds`` and ``hold_time_minutes``.
|
|
633
647
|
:param repetitions: The number of times to repeat the cycled steps.
|
|
634
648
|
:param block_max_volume: The greatest volume of liquid contained in any
|
|
635
649
|
individual well of the loaded labware, in µL.
|
|
636
650
|
If not specified, the default is 25 µL.
|
|
637
651
|
|
|
638
|
-
..
|
|
639
|
-
|
|
640
|
-
Unlike with :py:meth:`set_block_temperature`, either or both of
|
|
641
|
-
``hold_time_minutes`` and ``hold_time_seconds`` must be defined
|
|
642
|
-
and for each step.
|
|
643
|
-
|
|
644
|
-
.. note::
|
|
645
|
-
|
|
646
|
-
Before API Version 2.21, Thermocycler profiles run with this command
|
|
647
|
-
would be listed in the app as having a number of repetitions equal to
|
|
648
|
-
their step count. At or above API Version 2.21, the structure of the
|
|
649
|
-
Thermocycler cycles is preserved.
|
|
652
|
+
.. versionchanged:: 2.21
|
|
653
|
+
Fixed run log listing number of steps instead of number of repetitions.
|
|
650
654
|
|
|
651
655
|
"""
|
|
652
656
|
repetitions = validation.ensure_thermocycler_repetition_count(repetitions)
|
|
@@ -186,7 +186,14 @@ class ProtocolContext(CommandPublisher):
|
|
|
186
186
|
self._commands: List[str] = []
|
|
187
187
|
self._params: Parameters = Parameters()
|
|
188
188
|
self._unsubscribe_commands: Optional[Callable[[], None]] = None
|
|
189
|
-
|
|
189
|
+
try:
|
|
190
|
+
self._robot: Optional[RobotContext] = RobotContext(
|
|
191
|
+
core=self._core.load_robot(),
|
|
192
|
+
protocol_core=self._core,
|
|
193
|
+
api_version=self._api_version,
|
|
194
|
+
)
|
|
195
|
+
except APIVersionError:
|
|
196
|
+
self._robot = None
|
|
190
197
|
self.clear_commands()
|
|
191
198
|
|
|
192
199
|
@property
|
|
@@ -212,12 +219,14 @@ class ProtocolContext(CommandPublisher):
|
|
|
212
219
|
return self._api_version
|
|
213
220
|
|
|
214
221
|
@property
|
|
215
|
-
@requires_version(2,
|
|
222
|
+
@requires_version(2, 22)
|
|
216
223
|
def robot(self) -> RobotContext:
|
|
217
224
|
"""The :py:class:`.RobotContext` for the protocol.
|
|
218
225
|
|
|
219
226
|
:meta private:
|
|
220
227
|
"""
|
|
228
|
+
if self._core.robot_type != "OT-3 Standard" or not self._robot:
|
|
229
|
+
raise RobotTypeError("The RobotContext is only available on Flex robots.")
|
|
221
230
|
return self._robot
|
|
222
231
|
|
|
223
232
|
@property
|
|
@@ -229,7 +238,9 @@ class ProtocolContext(CommandPublisher):
|
|
|
229
238
|
"This function will be deprecated in later versions."
|
|
230
239
|
"Please use with caution."
|
|
231
240
|
)
|
|
232
|
-
|
|
241
|
+
if self._robot:
|
|
242
|
+
return self._robot.hardware
|
|
243
|
+
return HardwareManager(hardware=self._core.get_hardware())
|
|
233
244
|
|
|
234
245
|
@property
|
|
235
246
|
@requires_version(2, 0)
|
|
@@ -388,6 +399,7 @@ class ProtocolContext(CommandPublisher):
|
|
|
388
399
|
namespace: Optional[str] = None,
|
|
389
400
|
version: Optional[int] = None,
|
|
390
401
|
adapter: Optional[str] = None,
|
|
402
|
+
lid: Optional[str] = None,
|
|
391
403
|
) -> Labware:
|
|
392
404
|
"""Load a labware onto a location.
|
|
393
405
|
|
|
@@ -432,6 +444,10 @@ class ProtocolContext(CommandPublisher):
|
|
|
432
444
|
values as the ``load_name`` parameter of :py:meth:`.load_adapter`. The
|
|
433
445
|
adapter will use the same namespace as the labware, and the API will
|
|
434
446
|
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.
|
|
435
451
|
|
|
436
452
|
.. versionadded:: 2.15
|
|
437
453
|
"""
|
|
@@ -472,6 +488,20 @@ class ProtocolContext(CommandPublisher):
|
|
|
472
488
|
version=version,
|
|
473
489
|
)
|
|
474
490
|
|
|
491
|
+
if lid is not None:
|
|
492
|
+
if self._api_version < validation.LID_STACK_VERSION_GATE:
|
|
493
|
+
raise APIVersionError(
|
|
494
|
+
api_element="Loading a Lid on a Labware",
|
|
495
|
+
until_version="2.23",
|
|
496
|
+
current_version=f"{self._api_version}",
|
|
497
|
+
)
|
|
498
|
+
self._core.load_lid(
|
|
499
|
+
load_name=lid,
|
|
500
|
+
location=labware_core,
|
|
501
|
+
namespace=namespace,
|
|
502
|
+
version=version,
|
|
503
|
+
)
|
|
504
|
+
|
|
475
505
|
labware = Labware(
|
|
476
506
|
core=labware_core,
|
|
477
507
|
api_version=self._api_version,
|
|
@@ -956,7 +986,10 @@ class ProtocolContext(CommandPublisher):
|
|
|
956
986
|
mount, checked_instrument_name
|
|
957
987
|
)
|
|
958
988
|
|
|
959
|
-
is_96_channel = checked_instrument_name
|
|
989
|
+
is_96_channel = checked_instrument_name in [
|
|
990
|
+
PipetteNameType.P1000_96,
|
|
991
|
+
PipetteNameType.P200_96,
|
|
992
|
+
]
|
|
960
993
|
|
|
961
994
|
tip_racks = tip_racks or []
|
|
962
995
|
|
|
@@ -1320,6 +1353,94 @@ class ProtocolContext(CommandPublisher):
|
|
|
1320
1353
|
"""Returns ``True`` if the front door of the robot is closed."""
|
|
1321
1354
|
return self._core.door_closed()
|
|
1322
1355
|
|
|
1356
|
+
@requires_version(2, 23)
|
|
1357
|
+
def load_lid_stack(
|
|
1358
|
+
self,
|
|
1359
|
+
load_name: str,
|
|
1360
|
+
location: Union[DeckLocation, Labware],
|
|
1361
|
+
quantity: int,
|
|
1362
|
+
adapter: Optional[str] = None,
|
|
1363
|
+
namespace: Optional[str] = None,
|
|
1364
|
+
version: Optional[int] = None,
|
|
1365
|
+
) -> Labware:
|
|
1366
|
+
"""
|
|
1367
|
+
Load a stack of Lids onto a valid Deck Location or Adapter.
|
|
1368
|
+
|
|
1369
|
+
:param str load_name: A string to use for looking up a lid definition.
|
|
1370
|
+
You can find the ``load_name`` for any standard lid on the Opentrons
|
|
1371
|
+
`Labware Library <https://labware.opentrons.com>`_.
|
|
1372
|
+
:param location: Either a :ref:`deck slot <deck-slots>`,
|
|
1373
|
+
like ``1``, ``"1"``, or ``"D1"``, or the a valid Opentrons Adapter.
|
|
1374
|
+
:param int quantity: The quantity of lids to be loaded in the stack.
|
|
1375
|
+
:param adapter: An adapter to load the lid stack on top of. Accepts the same
|
|
1376
|
+
values as the ``load_name`` parameter of :py:meth:`.load_adapter`. The
|
|
1377
|
+
adapter will use the same namespace as the lid labware, and the API will
|
|
1378
|
+
choose the adapter's version automatically.
|
|
1379
|
+
:param str namespace: The namespace that the lid labware definition belongs to.
|
|
1380
|
+
If unspecified, the API will automatically search two namespaces:
|
|
1381
|
+
|
|
1382
|
+
- ``"opentrons"``, to load standard Opentrons labware definitions.
|
|
1383
|
+
- ``"custom_beta"``, to load custom labware definitions created with the
|
|
1384
|
+
`Custom Labware Creator <https://labware.opentrons.com/create>`__.
|
|
1385
|
+
|
|
1386
|
+
You might need to specify an explicit ``namespace`` if you have a custom
|
|
1387
|
+
definition whose ``load_name`` is the same as an Opentrons-verified
|
|
1388
|
+
definition, and you want to explicitly choose one or the other.
|
|
1389
|
+
|
|
1390
|
+
:param version: The version of the labware definition. You should normally
|
|
1391
|
+
leave this unspecified to let ``load_lid_stack()`` choose a version
|
|
1392
|
+
automatically.
|
|
1393
|
+
|
|
1394
|
+
:return: The initialized and loaded labware object representing the Lid Stack.
|
|
1395
|
+
"""
|
|
1396
|
+
if self._api_version < validation.LID_STACK_VERSION_GATE:
|
|
1397
|
+
raise APIVersionError(
|
|
1398
|
+
api_element="Loading a Lid Stack",
|
|
1399
|
+
until_version="2.23",
|
|
1400
|
+
current_version=f"{self._api_version}",
|
|
1401
|
+
)
|
|
1402
|
+
|
|
1403
|
+
load_location: Union[DeckSlotName, StagingSlotName, LabwareCore]
|
|
1404
|
+
if isinstance(location, Labware):
|
|
1405
|
+
load_location = location._core
|
|
1406
|
+
else:
|
|
1407
|
+
load_location = validation.ensure_and_convert_deck_slot(
|
|
1408
|
+
location, self._api_version, self._core.robot_type
|
|
1409
|
+
)
|
|
1410
|
+
|
|
1411
|
+
if adapter is not None:
|
|
1412
|
+
if isinstance(load_location, DeckSlotName) or isinstance(
|
|
1413
|
+
load_location, StagingSlotName
|
|
1414
|
+
):
|
|
1415
|
+
loaded_adapter = self.load_adapter(
|
|
1416
|
+
load_name=adapter,
|
|
1417
|
+
location=load_location.value,
|
|
1418
|
+
namespace=namespace,
|
|
1419
|
+
)
|
|
1420
|
+
load_location = loaded_adapter._core
|
|
1421
|
+
else:
|
|
1422
|
+
raise ValueError(
|
|
1423
|
+
"Location cannot be a Labware or Adapter when the 'adapter' field is not None."
|
|
1424
|
+
)
|
|
1425
|
+
|
|
1426
|
+
load_name = validation.ensure_lowercase_name(load_name)
|
|
1427
|
+
|
|
1428
|
+
result = self._core.load_lid_stack(
|
|
1429
|
+
load_name=load_name,
|
|
1430
|
+
location=load_location,
|
|
1431
|
+
quantity=quantity,
|
|
1432
|
+
namespace=namespace,
|
|
1433
|
+
version=version,
|
|
1434
|
+
)
|
|
1435
|
+
|
|
1436
|
+
labware = Labware(
|
|
1437
|
+
core=result,
|
|
1438
|
+
api_version=self._api_version,
|
|
1439
|
+
protocol_core=self._core,
|
|
1440
|
+
core_map=self._core_map,
|
|
1441
|
+
)
|
|
1442
|
+
return labware
|
|
1443
|
+
|
|
1323
1444
|
|
|
1324
1445
|
def _create_module_context(
|
|
1325
1446
|
module_core: Union[ModuleCore, NonConnectedModuleCore],
|