opentrons 8.3.0a0__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/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 +4 -6
- opentrons/hardware_control/backends/ot3controller.py +177 -59
- opentrons/hardware_control/backends/ot3simulator.py +10 -8
- opentrons/hardware_control/backends/ot3utils.py +3 -13
- opentrons/hardware_control/dev_types.py +2 -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 +9 -21
- 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 +13 -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 +34 -22
- 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 +67 -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 +42 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +34 -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 +34 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +145 -43
- 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 +261 -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 +60 -25
- 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 +12 -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 +135 -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.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/METADATA +16 -15
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/RECORD +228 -201
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/WHEEL +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/LICENSE +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/top_level.txt +0 -0
|
@@ -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],
|
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
from typing import NamedTuple, Union,
|
|
1
|
+
from typing import NamedTuple, Union, Optional
|
|
2
2
|
|
|
3
|
-
from opentrons.types import
|
|
3
|
+
from opentrons.types import (
|
|
4
|
+
Mount,
|
|
5
|
+
DeckLocation,
|
|
6
|
+
Location,
|
|
7
|
+
Point,
|
|
8
|
+
AxisMapType,
|
|
9
|
+
AxisType,
|
|
10
|
+
StringAxisMap,
|
|
11
|
+
)
|
|
4
12
|
from opentrons.legacy_commands import publisher
|
|
5
|
-
from opentrons.hardware_control import SyncHardwareAPI
|
|
13
|
+
from opentrons.hardware_control import SyncHardwareAPI
|
|
14
|
+
from opentrons.protocols.api_support.util import requires_version
|
|
15
|
+
from opentrons.protocols.api_support.types import APIVersion
|
|
16
|
+
from opentrons_shared_data.pipette.types import PipetteNameType
|
|
6
17
|
|
|
7
|
-
from .
|
|
8
|
-
from .core.common import ProtocolCore
|
|
18
|
+
from . import validation
|
|
19
|
+
from .core.common import ProtocolCore, RobotCore
|
|
20
|
+
from .module_contexts import ModuleContext
|
|
21
|
+
from .labware import Labware
|
|
22
|
+
from ._types import PipetteActionTypes, PlungerPositionTypes
|
|
9
23
|
|
|
10
24
|
|
|
11
25
|
class HardwareManager(NamedTuple):
|
|
@@ -34,56 +48,214 @@ class RobotContext(publisher.CommandPublisher):
|
|
|
34
48
|
|
|
35
49
|
"""
|
|
36
50
|
|
|
37
|
-
def __init__(
|
|
38
|
-
self
|
|
51
|
+
def __init__(
|
|
52
|
+
self, core: RobotCore, protocol_core: ProtocolCore, api_version: APIVersion
|
|
53
|
+
) -> None:
|
|
54
|
+
self._hardware = HardwareManager(hardware=protocol_core.get_hardware())
|
|
55
|
+
self._core = core
|
|
56
|
+
self._protocol_core = protocol_core
|
|
57
|
+
self._api_version = api_version
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
@requires_version(2, 22)
|
|
61
|
+
def api_version(self) -> APIVersion:
|
|
62
|
+
return self._api_version
|
|
39
63
|
|
|
40
64
|
@property
|
|
41
65
|
def hardware(self) -> HardwareManager:
|
|
66
|
+
# TODO this hardware attribute should be deprecated
|
|
67
|
+
# in version 3.0+ as we will only support exposed robot
|
|
68
|
+
# context commands.
|
|
42
69
|
return self._hardware
|
|
43
70
|
|
|
71
|
+
@requires_version(2, 22)
|
|
44
72
|
def move_to(
|
|
45
73
|
self,
|
|
46
74
|
mount: Union[Mount, str],
|
|
47
|
-
destination:
|
|
48
|
-
|
|
75
|
+
destination: Location,
|
|
76
|
+
speed: Optional[float] = None,
|
|
49
77
|
) -> None:
|
|
50
|
-
|
|
78
|
+
"""
|
|
79
|
+
Move a specified mount to a destination location on the deck.
|
|
80
|
+
|
|
81
|
+
:param mount: The mount of the instrument you wish to move.
|
|
82
|
+
This can either be an instance of :py:class:`.types.Mount` or one
|
|
83
|
+
of the strings ``"left"``, ``"right"``, ``"extension"``, ``"gripper"``. Note
|
|
84
|
+
that the gripper mount can be referred to either as ``"extension"`` or ``"gripper"``.
|
|
85
|
+
:type mount: types.Mount or str
|
|
86
|
+
:param Location destination:
|
|
87
|
+
:param speed:
|
|
88
|
+
"""
|
|
89
|
+
mount = validation.ensure_instrument_mount(mount)
|
|
90
|
+
self._core.move_to(mount, destination.point, speed)
|
|
51
91
|
|
|
92
|
+
@requires_version(2, 22)
|
|
52
93
|
def move_axes_to(
|
|
53
94
|
self,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
95
|
+
axis_map: Union[AxisMapType, StringAxisMap],
|
|
96
|
+
critical_point: Optional[Union[AxisMapType, StringAxisMap]] = None,
|
|
97
|
+
speed: Optional[float] = None,
|
|
57
98
|
) -> None:
|
|
58
|
-
|
|
99
|
+
"""
|
|
100
|
+
Move a set of axes to an absolute position on the deck.
|
|
59
101
|
|
|
102
|
+
:param axis_map: A dictionary mapping axes to an absolute position on the deck in mm.
|
|
103
|
+
:param critical_point: The critical point to move the axes with. It should only
|
|
104
|
+
specify the gantry axes (i.e. `x`, `y`, `z`).
|
|
105
|
+
:param float speed: The maximum speed with which you want to move all the axes
|
|
106
|
+
in the axis map.
|
|
107
|
+
"""
|
|
108
|
+
instrument_on_left = self._core.get_pipette_type_from_engine(Mount.LEFT)
|
|
109
|
+
is_96_channel = instrument_on_left == PipetteNameType.P1000_96
|
|
110
|
+
axis_map = validation.ensure_axis_map_type(
|
|
111
|
+
axis_map, self._protocol_core.robot_type, is_96_channel
|
|
112
|
+
)
|
|
113
|
+
if critical_point:
|
|
114
|
+
critical_point = validation.ensure_axis_map_type(
|
|
115
|
+
critical_point, self._protocol_core.robot_type, is_96_channel
|
|
116
|
+
)
|
|
117
|
+
validation.ensure_only_gantry_axis_map_type(
|
|
118
|
+
critical_point, self._protocol_core.robot_type
|
|
119
|
+
)
|
|
120
|
+
else:
|
|
121
|
+
critical_point = None
|
|
122
|
+
self._core.move_axes_to(axis_map, critical_point, speed)
|
|
123
|
+
|
|
124
|
+
@requires_version(2, 22)
|
|
60
125
|
def move_axes_relative(
|
|
61
|
-
self,
|
|
126
|
+
self,
|
|
127
|
+
axis_map: Union[AxisMapType, StringAxisMap],
|
|
128
|
+
speed: Optional[float] = None,
|
|
62
129
|
) -> None:
|
|
63
|
-
|
|
130
|
+
"""
|
|
131
|
+
Move a set of axes to a relative position on the deck.
|
|
132
|
+
|
|
133
|
+
:param axis_map: A dictionary mapping axes to relative movements in mm.
|
|
134
|
+
:type mount: types.Mount or str
|
|
64
135
|
|
|
65
|
-
|
|
66
|
-
|
|
136
|
+
:param float speed: The maximum speed with which you want to move all the axes
|
|
137
|
+
in the axis map.
|
|
138
|
+
"""
|
|
139
|
+
instrument_on_left = self._core.get_pipette_type_from_engine(Mount.LEFT)
|
|
140
|
+
is_96_channel = instrument_on_left == PipetteNameType.P1000_96
|
|
141
|
+
|
|
142
|
+
axis_map = validation.ensure_axis_map_type(
|
|
143
|
+
axis_map, self._protocol_core.robot_type, is_96_channel
|
|
144
|
+
)
|
|
145
|
+
self._core.move_axes_relative(axis_map, speed)
|
|
146
|
+
|
|
147
|
+
def close_gripper_jaw(self, force: Optional[float] = None) -> None:
|
|
148
|
+
"""Command the gripper closed with some force."""
|
|
149
|
+
self._core.close_gripper(force)
|
|
67
150
|
|
|
68
151
|
def open_gripper_jaw(self) -> None:
|
|
69
|
-
|
|
152
|
+
"""Command the gripper open."""
|
|
153
|
+
self._core.release_grip()
|
|
70
154
|
|
|
71
155
|
def axis_coordinates_for(
|
|
72
|
-
self,
|
|
73
|
-
|
|
74
|
-
|
|
156
|
+
self,
|
|
157
|
+
mount: Union[Mount, str],
|
|
158
|
+
location: Union[Location, ModuleContext, DeckLocation],
|
|
159
|
+
) -> AxisMapType:
|
|
160
|
+
"""
|
|
161
|
+
Build a :py:class:`.types.AxisMapType` from a location to be compatible with
|
|
162
|
+
either :py:meth:`.RobotContext.move_axes_to` or :py:meth:`.RobotContext.move_axes_relative`.
|
|
163
|
+
You must provide only one of `location`, `slot`, or `module` to build
|
|
164
|
+
the axis map.
|
|
165
|
+
|
|
166
|
+
:param mount: The mount of the instrument you wish create an axis map for.
|
|
167
|
+
This can either be an instance of :py:class:`.types.Mount` or one
|
|
168
|
+
of the strings ``"left"``, ``"right"``, ``"extension"``, ``"gripper"``. Note
|
|
169
|
+
that the gripper mount can be referred to either as ``"extension"`` or ``"gripper"``.
|
|
170
|
+
:type mount: types.Mount or str
|
|
171
|
+
:param location: The location to format an axis map for.
|
|
172
|
+
:type location: `Well`, `ModuleContext`, `DeckLocation` or `OffDeckType`
|
|
173
|
+
"""
|
|
174
|
+
mount = validation.ensure_instrument_mount(mount)
|
|
175
|
+
|
|
176
|
+
mount_axis = AxisType.axis_for_mount(mount)
|
|
177
|
+
if location:
|
|
178
|
+
loc: Union[Point, Labware, None]
|
|
179
|
+
if isinstance(location, ModuleContext):
|
|
180
|
+
loc = location.labware
|
|
181
|
+
if not loc:
|
|
182
|
+
raise ValueError(f"There must be a labware on {location}")
|
|
183
|
+
top_of_labware = loc.wells()[0].top()
|
|
184
|
+
loc = top_of_labware.point
|
|
185
|
+
return {mount_axis: loc.z, AxisType.X: loc.x, AxisType.Y: loc.y}
|
|
186
|
+
elif location is DeckLocation and not isinstance(location, Location):
|
|
187
|
+
slot_name = validation.ensure_and_convert_deck_slot(
|
|
188
|
+
location,
|
|
189
|
+
api_version=self._api_version,
|
|
190
|
+
robot_type=self._protocol_core.robot_type,
|
|
191
|
+
)
|
|
192
|
+
loc = self._protocol_core.get_slot_center(slot_name)
|
|
193
|
+
return {mount_axis: loc.z, AxisType.X: loc.x, AxisType.Y: loc.y}
|
|
194
|
+
elif isinstance(location, Location):
|
|
195
|
+
assert isinstance(location, Location)
|
|
196
|
+
loc = location.point
|
|
197
|
+
return {mount_axis: loc.z, AxisType.X: loc.x, AxisType.Y: loc.y}
|
|
198
|
+
else:
|
|
199
|
+
raise ValueError(
|
|
200
|
+
"Location parameter must be a Module, Deck Location, or Location type."
|
|
201
|
+
)
|
|
202
|
+
else:
|
|
203
|
+
raise TypeError("You must specify a location to move to.")
|
|
75
204
|
|
|
76
205
|
def plunger_coordinates_for_volume(
|
|
77
|
-
self, mount: Union[Mount, str], volume: float
|
|
78
|
-
) ->
|
|
79
|
-
|
|
206
|
+
self, mount: Union[Mount, str], volume: float, action: PipetteActionTypes
|
|
207
|
+
) -> AxisMapType:
|
|
208
|
+
"""
|
|
209
|
+
Build a :py:class:`.types.AxisMapType` for a pipette plunger motor from volume.
|
|
210
|
+
|
|
211
|
+
"""
|
|
212
|
+
pipette_name = self._core.get_pipette_type_from_engine(mount)
|
|
213
|
+
if not pipette_name:
|
|
214
|
+
raise ValueError(
|
|
215
|
+
f"Expected a pipette to be attached to provided mount {mount}"
|
|
216
|
+
)
|
|
217
|
+
mount = validation.ensure_mount_for_pipette(mount, pipette_name)
|
|
218
|
+
pipette_axis = AxisType.plunger_axis_for_mount(mount)
|
|
219
|
+
|
|
220
|
+
pipette_position = self._core.get_plunger_position_from_volume(
|
|
221
|
+
mount, volume, action, self._protocol_core.robot_type
|
|
222
|
+
)
|
|
223
|
+
return {pipette_axis: pipette_position}
|
|
80
224
|
|
|
81
225
|
def plunger_coordinates_for_named_position(
|
|
82
|
-
self, mount: Union[Mount, str], position_name:
|
|
83
|
-
) ->
|
|
84
|
-
|
|
226
|
+
self, mount: Union[Mount, str], position_name: PlungerPositionTypes
|
|
227
|
+
) -> AxisMapType:
|
|
228
|
+
"""
|
|
229
|
+
Build a :py:class:`.types.AxisMapType` for a pipette plunger motor from position_name.
|
|
85
230
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
231
|
+
"""
|
|
232
|
+
pipette_name = self._core.get_pipette_type_from_engine(mount)
|
|
233
|
+
if not pipette_name:
|
|
234
|
+
raise ValueError(
|
|
235
|
+
f"Expected a pipette to be attached to provided mount {mount}"
|
|
236
|
+
)
|
|
237
|
+
mount = validation.ensure_mount_for_pipette(mount, pipette_name)
|
|
238
|
+
pipette_axis = AxisType.plunger_axis_for_mount(mount)
|
|
239
|
+
pipette_position = self._core.get_plunger_position_from_name(
|
|
240
|
+
mount, position_name
|
|
241
|
+
)
|
|
242
|
+
return {pipette_axis: pipette_position}
|
|
243
|
+
|
|
244
|
+
def build_axis_map(self, axis_map: StringAxisMap) -> AxisMapType:
|
|
245
|
+
"""Take in a :py:class:`.types.StringAxisMap` and output a :py:class:`.types.AxisMapType`.
|
|
246
|
+
A :py:class:`.types.StringAxisMap` is allowed to contain any of the following strings:
|
|
247
|
+
``"x"``, ``"y"``, "``z_l"``, "``z_r"``, "``z_g"``, ``"q"``.
|
|
248
|
+
|
|
249
|
+
An example of a valid axis map could be:
|
|
250
|
+
|
|
251
|
+
{"x": 1, "y": 2} or {"Z_L": 100}
|
|
252
|
+
|
|
253
|
+
Note that capitalization does not matter.
|
|
254
|
+
|
|
255
|
+
"""
|
|
256
|
+
instrument_on_left = self._core.get_pipette_type_from_engine(Mount.LEFT)
|
|
257
|
+
is_96_channel = instrument_on_left == PipetteNameType.P1000_96
|
|
258
|
+
|
|
259
|
+
return validation.ensure_axis_map_type(
|
|
260
|
+
axis_map, self._protocol_core.robot_type, is_96_channel
|
|
261
|
+
)
|