opentrons 8.1.0a0__py2.py3-none-any.whl → 8.2.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opentrons/cli/analyze.py +71 -7
- opentrons/config/__init__.py +9 -0
- opentrons/config/advanced_settings.py +22 -0
- opentrons/config/defaults_ot3.py +14 -36
- opentrons/config/feature_flags.py +4 -0
- opentrons/config/types.py +6 -17
- opentrons/drivers/absorbance_reader/abstract.py +27 -3
- opentrons/drivers/absorbance_reader/async_byonoy.py +208 -154
- opentrons/drivers/absorbance_reader/driver.py +24 -15
- opentrons/drivers/absorbance_reader/hid_protocol.py +79 -50
- opentrons/drivers/absorbance_reader/simulator.py +32 -6
- opentrons/drivers/types.py +23 -1
- opentrons/execute.py +2 -2
- opentrons/hardware_control/api.py +18 -10
- opentrons/hardware_control/backends/controller.py +3 -2
- opentrons/hardware_control/backends/flex_protocol.py +11 -5
- opentrons/hardware_control/backends/ot3controller.py +18 -50
- opentrons/hardware_control/backends/ot3simulator.py +7 -6
- opentrons/hardware_control/backends/ot3utils.py +1 -0
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +22 -82
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -2
- opentrons/hardware_control/module_control.py +43 -2
- opentrons/hardware_control/modules/__init__.py +7 -1
- opentrons/hardware_control/modules/absorbance_reader.py +232 -83
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/heater_shaker.py +8 -3
- opentrons/hardware_control/modules/magdeck.py +12 -3
- opentrons/hardware_control/modules/mod_abc.py +27 -2
- opentrons/hardware_control/modules/tempdeck.py +15 -7
- opentrons/hardware_control/modules/thermocycler.py +69 -3
- opentrons/hardware_control/modules/types.py +11 -5
- opentrons/hardware_control/modules/update.py +11 -5
- opentrons/hardware_control/modules/utils.py +3 -1
- opentrons/hardware_control/ot3_calibration.py +6 -6
- opentrons/hardware_control/ot3api.py +131 -94
- opentrons/hardware_control/poller.py +15 -11
- opentrons/hardware_control/protocols/__init__.py +1 -7
- opentrons/hardware_control/protocols/instrument_configurer.py +14 -2
- opentrons/hardware_control/protocols/liquid_handler.py +5 -0
- opentrons/hardware_control/protocols/position_estimator.py +3 -1
- opentrons/hardware_control/types.py +2 -0
- opentrons/legacy_commands/helpers.py +8 -2
- opentrons/motion_planning/__init__.py +2 -0
- opentrons/motion_planning/waypoints.py +32 -0
- opentrons/protocol_api/__init__.py +2 -1
- opentrons/protocol_api/_liquid.py +87 -1
- opentrons/protocol_api/_parameter_context.py +10 -1
- opentrons/protocol_api/core/engine/deck_conflict.py +0 -297
- opentrons/protocol_api/core/engine/instrument.py +29 -25
- opentrons/protocol_api/core/engine/labware.py +20 -4
- opentrons/protocol_api/core/engine/module_core.py +166 -17
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +362 -0
- opentrons/protocol_api/core/engine/protocol.py +30 -2
- opentrons/protocol_api/core/instrument.py +2 -0
- opentrons/protocol_api/core/labware.py +4 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +5 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +6 -2
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/module.py +22 -4
- opentrons/protocol_api/core/protocol.py +6 -2
- opentrons/protocol_api/instrument_context.py +52 -20
- opentrons/protocol_api/labware.py +13 -1
- opentrons/protocol_api/module_contexts.py +115 -17
- opentrons/protocol_api/protocol_context.py +49 -5
- opentrons/protocol_api/validation.py +5 -3
- opentrons/protocol_engine/__init__.py +10 -9
- opentrons/protocol_engine/actions/__init__.py +3 -0
- opentrons/protocol_engine/actions/actions.py +30 -25
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/sync_client.py +1 -1
- opentrons/protocol_engine/clients/transports.py +1 -1
- opentrons/protocol_engine/commands/__init__.py +0 -4
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +41 -11
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +148 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +65 -9
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +148 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +200 -0
- opentrons/protocol_engine/commands/aspirate.py +29 -16
- opentrons/protocol_engine/commands/aspirate_in_place.py +33 -16
- opentrons/protocol_engine/commands/blow_out.py +63 -14
- opentrons/protocol_engine/commands/blow_out_in_place.py +55 -13
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +2 -5
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +3 -4
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +2 -5
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +6 -4
- opentrons/protocol_engine/commands/command.py +31 -18
- opentrons/protocol_engine/commands/command_unions.py +37 -24
- opentrons/protocol_engine/commands/comment.py +5 -3
- opentrons/protocol_engine/commands/configure_for_volume.py +11 -14
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +9 -15
- opentrons/protocol_engine/commands/custom.py +5 -3
- opentrons/protocol_engine/commands/dispense.py +42 -20
- opentrons/protocol_engine/commands/dispense_in_place.py +32 -14
- opentrons/protocol_engine/commands/drop_tip.py +70 -16
- opentrons/protocol_engine/commands/drop_tip_in_place.py +59 -13
- opentrons/protocol_engine/commands/get_tip_presence.py +5 -3
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +8 -6
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +8 -4
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +6 -4
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/home.py +11 -5
- opentrons/protocol_engine/commands/liquid_probe.py +146 -88
- opentrons/protocol_engine/commands/load_labware.py +28 -5
- opentrons/protocol_engine/commands/load_liquid.py +18 -7
- opentrons/protocol_engine/commands/load_module.py +4 -6
- opentrons/protocol_engine/commands/load_pipette.py +18 -17
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +6 -6
- opentrons/protocol_engine/commands/magnetic_module/engage.py +6 -4
- opentrons/protocol_engine/commands/move_labware.py +155 -23
- opentrons/protocol_engine/commands/move_relative.py +15 -3
- opentrons/protocol_engine/commands/move_to_addressable_area.py +29 -4
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +13 -4
- opentrons/protocol_engine/commands/move_to_coordinates.py +11 -5
- opentrons/protocol_engine/commands/move_to_well.py +37 -10
- opentrons/protocol_engine/commands/pick_up_tip.py +51 -30
- opentrons/protocol_engine/commands/pipetting_common.py +47 -16
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +62 -15
- opentrons/protocol_engine/commands/reload_labware.py +13 -4
- opentrons/protocol_engine/commands/retract_axis.py +6 -3
- opentrons/protocol_engine/commands/save_position.py +2 -3
- opentrons/protocol_engine/commands/set_rail_lights.py +5 -3
- opentrons/protocol_engine/commands/set_status_bar.py +5 -3
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +6 -4
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +3 -4
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/__init__.py +19 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +8 -8
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +8 -4
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +165 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +6 -4
- opentrons/protocol_engine/commands/touch_tip.py +19 -7
- opentrons/protocol_engine/commands/unsafe/__init__.py +30 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +6 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +5 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +10 -4
- opentrons/protocol_engine/commands/verify_tip_presence.py +5 -5
- opentrons/protocol_engine/commands/wait_for_duration.py +5 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +5 -3
- opentrons/protocol_engine/create_protocol_engine.py +60 -10
- opentrons/protocol_engine/engine_support.py +2 -1
- opentrons/protocol_engine/error_recovery_policy.py +14 -3
- opentrons/protocol_engine/errors/__init__.py +20 -0
- opentrons/protocol_engine/errors/error_occurrence.py +8 -3
- opentrons/protocol_engine/errors/exceptions.py +127 -2
- opentrons/protocol_engine/execution/__init__.py +2 -0
- opentrons/protocol_engine/execution/command_executor.py +22 -13
- opentrons/protocol_engine/execution/create_queue_worker.py +5 -1
- opentrons/protocol_engine/execution/door_watcher.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +2 -1
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +4 -2
- opentrons/protocol_engine/execution/hardware_stopper.py +3 -3
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +1 -4
- opentrons/protocol_engine/execution/labware_movement.py +73 -22
- opentrons/protocol_engine/execution/movement.py +17 -7
- opentrons/protocol_engine/execution/pipetting.py +7 -4
- opentrons/protocol_engine/execution/queue_worker.py +6 -2
- opentrons/protocol_engine/execution/run_control.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +2 -1
- opentrons/protocol_engine/execution/tip_handler.py +77 -43
- opentrons/protocol_engine/notes/__init__.py +14 -2
- opentrons/protocol_engine/notes/notes.py +18 -1
- opentrons/protocol_engine/plugins.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +47 -31
- opentrons/protocol_engine/resources/__init__.py +2 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +19 -5
- opentrons/protocol_engine/resources/file_provider.py +161 -0
- opentrons/protocol_engine/resources/fixture_validation.py +11 -1
- opentrons/protocol_engine/resources/labware_validation.py +10 -0
- opentrons/protocol_engine/state/__init__.py +0 -70
- opentrons/protocol_engine/state/addressable_areas.py +1 -1
- opentrons/protocol_engine/state/command_history.py +21 -2
- opentrons/protocol_engine/state/commands.py +110 -31
- opentrons/protocol_engine/state/files.py +59 -0
- opentrons/protocol_engine/state/frustum_helpers.py +440 -0
- opentrons/protocol_engine/state/geometry.py +445 -59
- opentrons/protocol_engine/state/labware.py +264 -84
- opentrons/protocol_engine/state/liquids.py +1 -1
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +21 -3
- opentrons/protocol_engine/state/modules.py +145 -90
- opentrons/protocol_engine/state/motion.py +33 -14
- opentrons/protocol_engine/state/pipettes.py +157 -317
- opentrons/protocol_engine/state/state.py +30 -1
- opentrons/protocol_engine/state/state_summary.py +3 -0
- opentrons/protocol_engine/state/tips.py +69 -114
- opentrons/protocol_engine/state/update_types.py +424 -0
- opentrons/protocol_engine/state/wells.py +236 -0
- opentrons/protocol_engine/types.py +90 -0
- opentrons/protocol_reader/file_format_validator.py +83 -15
- opentrons/protocol_runner/json_translator.py +21 -5
- opentrons/protocol_runner/legacy_command_mapper.py +27 -6
- opentrons/protocol_runner/legacy_context_plugin.py +27 -71
- opentrons/protocol_runner/protocol_runner.py +6 -3
- opentrons/protocol_runner/run_orchestrator.py +41 -6
- opentrons/protocols/advanced_control/mix.py +3 -5
- opentrons/protocols/advanced_control/transfers.py +125 -56
- opentrons/protocols/api_support/constants.py +1 -1
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/labware_like.py +4 -4
- opentrons/protocols/api_support/tip_tracker.py +2 -2
- opentrons/protocols/api_support/types.py +15 -2
- opentrons/protocols/api_support/util.py +30 -42
- opentrons/protocols/duration/errors.py +1 -1
- opentrons/protocols/duration/estimator.py +50 -29
- opentrons/protocols/execution/dev_types.py +2 -2
- opentrons/protocols/execution/execute_json_v4.py +15 -10
- opentrons/protocols/execution/execute_python.py +8 -3
- opentrons/protocols/geometry/planning.py +12 -12
- opentrons/protocols/labware.py +17 -33
- opentrons/protocols/parameters/csv_parameter_interface.py +3 -1
- opentrons/simulate.py +3 -3
- opentrons/types.py +30 -3
- opentrons/util/logging_config.py +34 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/METADATA +5 -4
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/RECORD +235 -223
- opentrons/protocol_engine/commands/absorbance_reader/measure.py +0 -94
- opentrons/protocol_engine/commands/configuring_common.py +0 -26
- opentrons/protocol_runner/thread_async_queue.py +0 -174
- /opentrons/protocol_engine/state/{abstract_store.py → _abstract_store.py} +0 -0
- /opentrons/protocol_engine/state/{move_types.py → _move_types.py} +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/LICENSE +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/WHEEL +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/top_level.txt +0 -0
|
@@ -9,7 +9,11 @@ from typing import (
|
|
|
9
9
|
Callable,
|
|
10
10
|
Generator,
|
|
11
11
|
Iterator,
|
|
12
|
+
Iterable,
|
|
13
|
+
Sequence,
|
|
12
14
|
Tuple,
|
|
15
|
+
TypedDict,
|
|
16
|
+
TypeAlias,
|
|
13
17
|
TYPE_CHECKING,
|
|
14
18
|
TypeVar,
|
|
15
19
|
)
|
|
@@ -19,9 +23,22 @@ from opentrons.protocols.api_support.types import APIVersion
|
|
|
19
23
|
from opentrons.hardware_control.nozzle_manager import NozzleConfigurationType
|
|
20
24
|
|
|
21
25
|
|
|
26
|
+
AdvancedLiquidHandling = Union[
|
|
27
|
+
Well,
|
|
28
|
+
types.Location,
|
|
29
|
+
Sequence[Union[Well, types.Location]],
|
|
30
|
+
Sequence[Sequence[Well]],
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TransferStep(TypedDict):
|
|
35
|
+
method: str
|
|
36
|
+
args: Optional[List[Any]]
|
|
37
|
+
kwargs: Optional[Dict[Any, Any]]
|
|
38
|
+
|
|
39
|
+
|
|
22
40
|
if TYPE_CHECKING:
|
|
23
41
|
from opentrons.protocol_api import InstrumentContext
|
|
24
|
-
from opentrons.protocols.execution.dev_types import Dictable
|
|
25
42
|
|
|
26
43
|
_PARTIAL_TIP_SUPPORT_ADDED = APIVersion(2, 18)
|
|
27
44
|
"""The version after which partial tip support and nozzle maps were made available."""
|
|
@@ -335,6 +352,11 @@ class TransferOptions(NamedTuple):
|
|
|
335
352
|
dispense: DispenseOpts = DispenseOpts()
|
|
336
353
|
|
|
337
354
|
|
|
355
|
+
FormatDictArgs: TypeAlias = Union[
|
|
356
|
+
PickUpTipOpts, MixOpts, BlowOutOpts, TouchTipOpts, AspirateOpts, DispenseOpts
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
|
|
338
360
|
TransferOptions.transfer.__doc__ = """
|
|
339
361
|
Options pertaining to behavior of the transfer.
|
|
340
362
|
|
|
@@ -386,9 +408,9 @@ class TransferPlan:
|
|
|
386
408
|
|
|
387
409
|
def __init__(
|
|
388
410
|
self,
|
|
389
|
-
volume,
|
|
390
|
-
|
|
391
|
-
|
|
411
|
+
volume: Union[float, Sequence[float]],
|
|
412
|
+
srcs: AdvancedLiquidHandling,
|
|
413
|
+
dsts: AdvancedLiquidHandling,
|
|
392
414
|
# todo(mm, 2021-03-10):
|
|
393
415
|
# Refactor to not need an InstrumentContext, so we can more
|
|
394
416
|
# easily test this class's logic on its own.
|
|
@@ -414,6 +436,8 @@ class TransferPlan:
|
|
|
414
436
|
# ii. if using single channel pipettes, flatten a multi-dimensional
|
|
415
437
|
# list of Wells into a 1 dimensional list of Wells
|
|
416
438
|
pipette_configuration_type = NozzleConfigurationType.FULL
|
|
439
|
+
normalized_sources: List[Union[Well, types.Location]]
|
|
440
|
+
normalized_dests: List[Union[Well, types.Location]]
|
|
417
441
|
if self._api_version >= _PARTIAL_TIP_SUPPORT_ADDED:
|
|
418
442
|
pipette_configuration_type = (
|
|
419
443
|
self._instr._core.get_nozzle_map().configuration
|
|
@@ -422,24 +446,36 @@ class TransferPlan:
|
|
|
422
446
|
self._instr.channels > 1
|
|
423
447
|
and pipette_configuration_type == NozzleConfigurationType.FULL
|
|
424
448
|
):
|
|
425
|
-
|
|
449
|
+
normalized_sources, normalized_dests = self._multichannel_transfer(
|
|
450
|
+
srcs, dsts
|
|
451
|
+
)
|
|
426
452
|
else:
|
|
427
|
-
if isinstance(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
elif isinstance(
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
453
|
+
if isinstance(srcs, List):
|
|
454
|
+
if isinstance(srcs[0], List):
|
|
455
|
+
# Source is a List[List[Well]]
|
|
456
|
+
normalized_sources = [
|
|
457
|
+
well for well_list in srcs for well in well_list
|
|
458
|
+
]
|
|
459
|
+
else:
|
|
460
|
+
normalized_sources = srcs
|
|
461
|
+
elif isinstance(srcs, Well) or isinstance(srcs, types.Location):
|
|
462
|
+
normalized_sources = [srcs]
|
|
463
|
+
if isinstance(dsts, List):
|
|
464
|
+
if isinstance(dsts[0], List):
|
|
465
|
+
# Dest is a List[List[Well]]
|
|
466
|
+
normalized_dests = [
|
|
467
|
+
well for well_list in dsts for well in well_list
|
|
468
|
+
]
|
|
469
|
+
else:
|
|
470
|
+
normalized_dests = dsts
|
|
471
|
+
elif isinstance(dsts, Well) or isinstance(dsts, types.Location):
|
|
472
|
+
normalized_dests = [dsts]
|
|
473
|
+
|
|
474
|
+
total_xfers = max(len(normalized_sources), len(normalized_dests))
|
|
439
475
|
|
|
440
476
|
self._volumes = self._create_volume_list(volume, total_xfers)
|
|
441
|
-
self._sources =
|
|
442
|
-
self._dests =
|
|
477
|
+
self._sources = normalized_sources
|
|
478
|
+
self._dests = normalized_dests
|
|
443
479
|
self._options = options or TransferOptions()
|
|
444
480
|
self._strategy = self._options.transfer
|
|
445
481
|
self._tip_opts = self._options.pick_up_tip
|
|
@@ -451,7 +487,7 @@ class TransferPlan:
|
|
|
451
487
|
|
|
452
488
|
self._mode = TransferMode[mode.upper()]
|
|
453
489
|
|
|
454
|
-
def __iter__(self):
|
|
490
|
+
def __iter__(self) -> Iterator[TransferStep]:
|
|
455
491
|
if self._strategy.new_tip == types.TransferTipPolicy.ONCE:
|
|
456
492
|
yield self._format_dict("pick_up_tip", kwargs=self._tip_opts)
|
|
457
493
|
yield from {
|
|
@@ -465,7 +501,7 @@ class TransferPlan:
|
|
|
465
501
|
else:
|
|
466
502
|
yield self._format_dict("drop_tip")
|
|
467
503
|
|
|
468
|
-
def _plan_transfer(self):
|
|
504
|
+
def _plan_transfer(self) -> Generator[TransferStep, None, None]:
|
|
469
505
|
"""
|
|
470
506
|
* **Source/ Dest:** Multiple sources to multiple destinations.
|
|
471
507
|
Src & dest should be equal length
|
|
@@ -532,7 +568,7 @@ class TransferPlan:
|
|
|
532
568
|
def _extend_source_target_lists(
|
|
533
569
|
sources: List[Union[Well, types.Location]],
|
|
534
570
|
targets: List[Union[Well, types.Location]],
|
|
535
|
-
):
|
|
571
|
+
) -> Tuple[List[Union[Well, types.Location]], List[Union[Well, types.Location]]]:
|
|
536
572
|
"""Extend source or target list to match the length of the other"""
|
|
537
573
|
if len(sources) < len(targets):
|
|
538
574
|
if len(targets) % len(sources) != 0:
|
|
@@ -552,7 +588,7 @@ class TransferPlan:
|
|
|
552
588
|
]
|
|
553
589
|
return sources, targets
|
|
554
590
|
|
|
555
|
-
def _plan_distribute(self):
|
|
591
|
+
def _plan_distribute(self) -> Generator[TransferStep, None, None]:
|
|
556
592
|
"""
|
|
557
593
|
* **Source/ Dest:** One source to many destinations
|
|
558
594
|
* **Volume:** Single volume or List of volumes is acceptable. This list
|
|
@@ -617,7 +653,7 @@ class TransferPlan:
|
|
|
617
653
|
if self._strategy.new_tip == types.TransferTipPolicy.ALWAYS:
|
|
618
654
|
yield self._format_dict("pick_up_tip", kwargs=self._tip_opts)
|
|
619
655
|
while not done:
|
|
620
|
-
asp_grouped: List[Tuple[float, Well]] = []
|
|
656
|
+
asp_grouped: List[Tuple[float, Well | types.Location]] = []
|
|
621
657
|
try:
|
|
622
658
|
while (
|
|
623
659
|
sum(a[0] for a in asp_grouped)
|
|
@@ -641,6 +677,7 @@ class TransferPlan:
|
|
|
641
677
|
self._sources[0],
|
|
642
678
|
)
|
|
643
679
|
for step in asp_grouped:
|
|
680
|
+
|
|
644
681
|
yield from self._dispense_actions(
|
|
645
682
|
vol=step[0],
|
|
646
683
|
src=self._sources[0],
|
|
@@ -653,7 +690,7 @@ class TransferPlan:
|
|
|
653
690
|
|
|
654
691
|
@staticmethod
|
|
655
692
|
def _expand_for_volume_constraints(
|
|
656
|
-
volumes:
|
|
693
|
+
volumes: Iterable[float], targets: Iterable[Target], max_volume: float
|
|
657
694
|
) -> Generator[Tuple[float, "Target"], None, None]:
|
|
658
695
|
"""Split a sequence of proposed transfers if necessary to keep each
|
|
659
696
|
transfer under the given max volume.
|
|
@@ -672,7 +709,7 @@ class TransferPlan:
|
|
|
672
709
|
yield volume, target
|
|
673
710
|
yield volume, target
|
|
674
711
|
|
|
675
|
-
def _plan_consolidate(self):
|
|
712
|
+
def _plan_consolidate(self) -> Generator[TransferStep, None, None]:
|
|
676
713
|
"""
|
|
677
714
|
* **Source/ Dest:** Many sources to one destination
|
|
678
715
|
* **Volume:** Single volume or List of volumes is acceptable. This list
|
|
@@ -728,7 +765,7 @@ class TransferPlan:
|
|
|
728
765
|
yield self._format_dict("pick_up_tip", kwargs=self._tip_opts)
|
|
729
766
|
done = False
|
|
730
767
|
while not done:
|
|
731
|
-
asp_grouped: List[Tuple[float, Well]] = []
|
|
768
|
+
asp_grouped: List[Tuple[float, Union[Well, types.Location]]] = []
|
|
732
769
|
try:
|
|
733
770
|
while (
|
|
734
771
|
sum([a[0] for a in asp_grouped])
|
|
@@ -759,18 +796,28 @@ class TransferPlan:
|
|
|
759
796
|
)
|
|
760
797
|
yield from self._new_tip_action()
|
|
761
798
|
|
|
762
|
-
def _aspirate_actions(
|
|
799
|
+
def _aspirate_actions(
|
|
800
|
+
self, vol: float, loc: Union[Well, types.Location]
|
|
801
|
+
) -> Generator[TransferStep, None, None]:
|
|
763
802
|
yield from self._before_aspirate(loc)
|
|
764
803
|
yield self._format_dict("aspirate", [vol, loc, self._options.aspirate.rate])
|
|
765
804
|
yield from self._after_aspirate()
|
|
766
805
|
|
|
767
|
-
def _dispense_actions(
|
|
806
|
+
def _dispense_actions(
|
|
807
|
+
self,
|
|
808
|
+
vol: float,
|
|
809
|
+
dest: Union[Well, types.Location],
|
|
810
|
+
src: Optional[Union[Well, types.Location]] = None,
|
|
811
|
+
is_disp_next: bool = False,
|
|
812
|
+
) -> Generator[TransferStep, None, None]:
|
|
768
813
|
if self._strategy.air_gap:
|
|
769
814
|
vol += self._strategy.air_gap
|
|
770
815
|
yield self._format_dict("dispense", [vol, dest, self._options.dispense.rate])
|
|
771
816
|
yield from self._after_dispense(dest=dest, src=src, is_disp_next=is_disp_next)
|
|
772
817
|
|
|
773
|
-
def _before_aspirate(
|
|
818
|
+
def _before_aspirate(
|
|
819
|
+
self, loc: Union[Well, types.Location]
|
|
820
|
+
) -> Generator[TransferStep, None, None]:
|
|
774
821
|
if (
|
|
775
822
|
self._strategy.mix_strategy == MixStrategy.BEFORE
|
|
776
823
|
or self._strategy.mix_strategy == MixStrategy.BOTH
|
|
@@ -780,13 +827,33 @@ class TransferPlan:
|
|
|
780
827
|
mix_before_opts["location"] = loc
|
|
781
828
|
yield self._format_dict("mix", kwargs=mix_before_opts)
|
|
782
829
|
|
|
783
|
-
def _after_aspirate(self):
|
|
830
|
+
def _after_aspirate(self) -> Generator[TransferStep, None, None]:
|
|
784
831
|
if self._strategy.air_gap:
|
|
785
832
|
yield self._format_dict("air_gap", [self._strategy.air_gap])
|
|
786
833
|
if self._strategy.touch_tip_strategy == TouchTipStrategy.ALWAYS:
|
|
787
834
|
yield self._format_dict("touch_tip", kwargs=self._touch_tip_opts)
|
|
788
835
|
|
|
789
|
-
def
|
|
836
|
+
def _after_dispense_trash(self) -> Generator[TransferStep, None, None]:
|
|
837
|
+
if isinstance(self._instr.trash_container, Labware):
|
|
838
|
+
yield self._format_dict(
|
|
839
|
+
"blow_out", [self._instr.trash_container.wells()[0]]
|
|
840
|
+
)
|
|
841
|
+
else:
|
|
842
|
+
yield self._format_dict("blow_out", [self._instr.trash_container])
|
|
843
|
+
|
|
844
|
+
def _after_dispense_helper(self) -> Generator[TransferStep, None, None]:
|
|
845
|
+
# Used by distribute
|
|
846
|
+
if self._strategy.air_gap:
|
|
847
|
+
yield self._format_dict("air_gap", [self._strategy.air_gap])
|
|
848
|
+
if self._strategy.touch_tip_strategy == TouchTipStrategy.ALWAYS:
|
|
849
|
+
yield self._format_dict("touch_tip", kwargs=self._touch_tip_opts)
|
|
850
|
+
|
|
851
|
+
def _after_dispense(
|
|
852
|
+
self,
|
|
853
|
+
dest: Union[Well, types.Location],
|
|
854
|
+
src: Optional[Union[types.Location, Well]],
|
|
855
|
+
is_disp_next: bool = False,
|
|
856
|
+
) -> Generator[TransferStep, None, None]:
|
|
790
857
|
# This sequence of actions is subject to change
|
|
791
858
|
if not is_disp_next:
|
|
792
859
|
# If the next command is an aspirate, we are switching
|
|
@@ -813,21 +880,11 @@ class TransferPlan:
|
|
|
813
880
|
self._strategy.blow_out_strategy == BlowOutStrategy.TRASH
|
|
814
881
|
or self._strategy.disposal_volume
|
|
815
882
|
):
|
|
816
|
-
|
|
817
|
-
yield self._format_dict(
|
|
818
|
-
"blow_out", [self._instr.trash_container.wells()[0]]
|
|
819
|
-
)
|
|
820
|
-
else:
|
|
821
|
-
yield self._format_dict("blow_out", [self._instr.trash_container])
|
|
822
|
-
|
|
883
|
+
yield from self._after_dispense_trash()
|
|
823
884
|
else:
|
|
824
|
-
|
|
825
|
-
if self._strategy.air_gap:
|
|
826
|
-
yield self._format_dict("air_gap", [self._strategy.air_gap])
|
|
827
|
-
if self._strategy.touch_tip_strategy == TouchTipStrategy.ALWAYS:
|
|
828
|
-
yield self._format_dict("touch_tip", kwargs=self._touch_tip_opts)
|
|
885
|
+
yield from self._after_dispense_helper()
|
|
829
886
|
|
|
830
|
-
def _new_tip_action(self):
|
|
887
|
+
def _new_tip_action(self) -> Generator[TransferStep, None, None]:
|
|
831
888
|
if self._strategy.new_tip == types.TransferTipPolicy.ALWAYS:
|
|
832
889
|
if self._strategy.drop_tip_strategy == DropTipStrategy.RETURN:
|
|
833
890
|
yield self._format_dict("return_tip")
|
|
@@ -837,9 +894,9 @@ class TransferPlan:
|
|
|
837
894
|
def _format_dict(
|
|
838
895
|
self,
|
|
839
896
|
method: str,
|
|
840
|
-
args: List = None,
|
|
841
|
-
kwargs: Union[
|
|
842
|
-
):
|
|
897
|
+
args: Optional[List[Any]] = None,
|
|
898
|
+
kwargs: Optional[Union[Dict[Any, Any], FormatDictArgs]] = None,
|
|
899
|
+
) -> TransferStep:
|
|
843
900
|
if kwargs:
|
|
844
901
|
if isinstance(kwargs, Dict):
|
|
845
902
|
params = {key: val for key, val in kwargs.items() if val}
|
|
@@ -851,9 +908,11 @@ class TransferPlan:
|
|
|
851
908
|
args = []
|
|
852
909
|
return {"method": method, "args": args, "kwargs": params}
|
|
853
910
|
|
|
854
|
-
def _create_volume_list(
|
|
911
|
+
def _create_volume_list(
|
|
912
|
+
self, volume: Union[Union[float, int], Sequence[float]], total_xfers: int
|
|
913
|
+
) -> List[float]:
|
|
855
914
|
if isinstance(volume, (float, int)):
|
|
856
|
-
return [volume] * total_xfers
|
|
915
|
+
return [float(volume)] * total_xfers
|
|
857
916
|
elif isinstance(volume, tuple):
|
|
858
917
|
return self._create_volume_gradient(
|
|
859
918
|
volume[0], volume[-1], total_xfers, self._strategy.gradient_function
|
|
@@ -870,11 +929,17 @@ class TransferPlan:
|
|
|
870
929
|
)
|
|
871
930
|
return volume
|
|
872
931
|
|
|
873
|
-
def _create_volume_gradient(
|
|
932
|
+
def _create_volume_gradient(
|
|
933
|
+
self,
|
|
934
|
+
min_v: float,
|
|
935
|
+
max_v: float,
|
|
936
|
+
total: int,
|
|
937
|
+
gradient: Optional[Callable[[float], float]] = None,
|
|
938
|
+
) -> List[float]:
|
|
874
939
|
|
|
875
940
|
diff_vol = max_v - min_v
|
|
876
941
|
|
|
877
|
-
def _map_volume(i):
|
|
942
|
+
def _map_volume(i: int) -> float:
|
|
878
943
|
nonlocal diff_vol, total
|
|
879
944
|
rel_x = i / (total - 1)
|
|
880
945
|
rel_y = gradient(rel_x) if gradient else rel_x
|
|
@@ -884,7 +949,7 @@ class TransferPlan:
|
|
|
884
949
|
|
|
885
950
|
def _check_valid_volume_parameters(
|
|
886
951
|
self, disposal_volume: float, air_gap: float, max_volume: float
|
|
887
|
-
):
|
|
952
|
+
) -> None:
|
|
888
953
|
if air_gap >= max_volume:
|
|
889
954
|
raise ValueError(
|
|
890
955
|
"The air gap must be less than the maximum volume of the pipette"
|
|
@@ -898,7 +963,9 @@ class TransferPlan:
|
|
|
898
963
|
"The sum of the air gap and disposal volume must be less than the maximum volume of the pipette"
|
|
899
964
|
)
|
|
900
965
|
|
|
901
|
-
def _check_valid_well_list(
|
|
966
|
+
def _check_valid_well_list(
|
|
967
|
+
self, well_list: List[Any], id: str, old_well_list: List[Any]
|
|
968
|
+
) -> None:
|
|
902
969
|
if self._api_version >= APIVersion(2, 2) and len(well_list) < 1:
|
|
903
970
|
raise RuntimeError(
|
|
904
971
|
f"Invalid {id} for multichannel transfer: {old_well_list}"
|
|
@@ -914,7 +981,9 @@ class TransferPlan:
|
|
|
914
981
|
return True
|
|
915
982
|
return False
|
|
916
983
|
|
|
917
|
-
def _multichannel_transfer(
|
|
984
|
+
def _multichannel_transfer(
|
|
985
|
+
self, s: AdvancedLiquidHandling, d: AdvancedLiquidHandling
|
|
986
|
+
) -> Tuple[List[Union[Well, types.Location]], List[Union[Well, types.Location]]]:
|
|
918
987
|
# TODO: add a check for container being multi-channel compatible?
|
|
919
988
|
# Helper function for multi-channel use-case
|
|
920
989
|
assert (
|
|
@@ -958,7 +1027,7 @@ class TransferPlan:
|
|
|
958
1027
|
self._check_valid_well_list(new_dst, "target", d)
|
|
959
1028
|
return new_src, new_dst
|
|
960
1029
|
|
|
961
|
-
def _is_valid_row(self, well: Union[Well, types.Location]):
|
|
1030
|
+
def _is_valid_row(self, well: Union[Well, types.Location]) -> bool:
|
|
962
1031
|
if isinstance(well, types.Location):
|
|
963
1032
|
test_well = well.labware.as_well()
|
|
964
1033
|
else:
|
|
@@ -4,5 +4,5 @@ from opentrons.config import get_opentrons_path
|
|
|
4
4
|
|
|
5
5
|
OPENTRONS_NAMESPACE = "opentrons"
|
|
6
6
|
CUSTOM_NAMESPACE = "custom_beta"
|
|
7
|
-
STANDARD_DEFS_PATH = Path("labware/definitions
|
|
7
|
+
STANDARD_DEFS_PATH = Path("labware/definitions")
|
|
8
8
|
USER_DEFS_PATH = get_opentrons_path("labware_user_definitions_dir_v2")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from enum import Enum, auto
|
|
2
|
-
from typing import TYPE_CHECKING, Optional, Union, cast, Tuple, List, Set
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Optional, Union, cast, Tuple, List, Set
|
|
3
3
|
|
|
4
4
|
if TYPE_CHECKING:
|
|
5
5
|
from opentrons.protocol_api.labware import Labware, Well
|
|
@@ -161,7 +161,7 @@ class LabwareLike:
|
|
|
161
161
|
seen: Set[LabwareLike] = set()
|
|
162
162
|
|
|
163
163
|
# internal function to have the cycle detector different per call
|
|
164
|
-
def _fp_recurse(location: LabwareLike):
|
|
164
|
+
def _fp_recurse(location: LabwareLike) -> Optional[str]:
|
|
165
165
|
if location in seen:
|
|
166
166
|
raise RuntimeError("Cycle in labware parent")
|
|
167
167
|
seen.add(location)
|
|
@@ -222,12 +222,12 @@ class LabwareLike:
|
|
|
222
222
|
def __repr__(self) -> str:
|
|
223
223
|
return str(self)
|
|
224
224
|
|
|
225
|
-
def __eq__(self, other):
|
|
225
|
+
def __eq__(self, other: Any) -> bool:
|
|
226
226
|
return (
|
|
227
227
|
other is not None
|
|
228
228
|
and isinstance(other, LabwareLike)
|
|
229
229
|
and self.object == other.object
|
|
230
230
|
)
|
|
231
231
|
|
|
232
|
-
def __hash__(self):
|
|
232
|
+
def __hash__(self) -> int:
|
|
233
233
|
return id(self)
|
|
@@ -65,7 +65,7 @@ class TipTracker:
|
|
|
65
65
|
start_well: AbstractWellCore,
|
|
66
66
|
num_channels: int = 1,
|
|
67
67
|
fail_if_full: bool = False,
|
|
68
|
-
):
|
|
68
|
+
) -> None:
|
|
69
69
|
"""
|
|
70
70
|
Removes tips from the tip tracker.
|
|
71
71
|
|
|
@@ -142,7 +142,7 @@ class TipTracker:
|
|
|
142
142
|
except IndexError:
|
|
143
143
|
return None
|
|
144
144
|
|
|
145
|
-
def return_tips(self, start_well: AbstractWellCore, num_channels: int = 1):
|
|
145
|
+
def return_tips(self, start_well: AbstractWellCore, num_channels: int = 1) -> None:
|
|
146
146
|
"""
|
|
147
147
|
Re-adds tips to the tip tracker
|
|
148
148
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import NamedTuple
|
|
2
|
+
from typing import NamedTuple, TypedDict
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class APIVersion(NamedTuple):
|
|
@@ -15,5 +15,18 @@ class APIVersion(NamedTuple):
|
|
|
15
15
|
|
|
16
16
|
return cls(major=intparts[0], minor=intparts[1])
|
|
17
17
|
|
|
18
|
-
def __str__(self):
|
|
18
|
+
def __str__(self) -> str:
|
|
19
19
|
return f"{self.major}.{self.minor}"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ThermocyclerStepBase(TypedDict):
|
|
23
|
+
"""Required elements of a thermocycler step: the temperature."""
|
|
24
|
+
|
|
25
|
+
temperature: float
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ThermocyclerStep(ThermocyclerStepBase, total=False):
|
|
29
|
+
"""Optional elements of a thermocycler step: the hold time. One of these must be present."""
|
|
30
|
+
|
|
31
|
+
hold_time_seconds: float
|
|
32
|
+
hold_time_minutes: float
|
|
@@ -11,10 +11,13 @@ from typing import (
|
|
|
11
11
|
Callable,
|
|
12
12
|
Dict,
|
|
13
13
|
List,
|
|
14
|
+
Iterator,
|
|
14
15
|
Optional,
|
|
15
16
|
TypeVar,
|
|
16
17
|
Union,
|
|
17
18
|
cast,
|
|
19
|
+
KeysView,
|
|
20
|
+
ItemsView,
|
|
18
21
|
)
|
|
19
22
|
|
|
20
23
|
from opentrons import types as top_types
|
|
@@ -180,7 +183,7 @@ class FlowRates:
|
|
|
180
183
|
return self._instr.get_aspirate_flow_rate()
|
|
181
184
|
|
|
182
185
|
@aspirate.setter
|
|
183
|
-
def aspirate(self, new_val: float):
|
|
186
|
+
def aspirate(self, new_val: float) -> None:
|
|
184
187
|
self._instr.set_flow_rate(
|
|
185
188
|
aspirate=_assert_gzero(
|
|
186
189
|
new_val, "flow rate should be a numerical value in ul/s"
|
|
@@ -192,7 +195,7 @@ class FlowRates:
|
|
|
192
195
|
return self._instr.get_dispense_flow_rate()
|
|
193
196
|
|
|
194
197
|
@dispense.setter
|
|
195
|
-
def dispense(self, new_val: float):
|
|
198
|
+
def dispense(self, new_val: float) -> None:
|
|
196
199
|
self._instr.set_flow_rate(
|
|
197
200
|
dispense=_assert_gzero(
|
|
198
201
|
new_val, "flow rate should be a numerical value in ul/s"
|
|
@@ -204,7 +207,7 @@ class FlowRates:
|
|
|
204
207
|
return self._instr.get_blow_out_flow_rate()
|
|
205
208
|
|
|
206
209
|
@blow_out.setter
|
|
207
|
-
def blow_out(self, new_val: float):
|
|
210
|
+
def blow_out(self, new_val: float) -> None:
|
|
208
211
|
self._instr.set_flow_rate(
|
|
209
212
|
blow_out=_assert_gzero(
|
|
210
213
|
new_val, "flow rate should be a numerical value in ul/s"
|
|
@@ -247,7 +250,7 @@ class PlungerSpeeds:
|
|
|
247
250
|
return self._instr.get_hardware_state()["aspirate_speed"]
|
|
248
251
|
|
|
249
252
|
@aspirate.setter
|
|
250
|
-
def aspirate(self, new_val: float):
|
|
253
|
+
def aspirate(self, new_val: float) -> None:
|
|
251
254
|
self._instr.set_pipette_speed(
|
|
252
255
|
aspirate=_assert_gzero(new_val, "speed should be a numerical value in mm/s")
|
|
253
256
|
)
|
|
@@ -257,7 +260,7 @@ class PlungerSpeeds:
|
|
|
257
260
|
return self._instr.get_hardware_state()["dispense_speed"]
|
|
258
261
|
|
|
259
262
|
@dispense.setter
|
|
260
|
-
def dispense(self, new_val: float):
|
|
263
|
+
def dispense(self, new_val: float) -> None:
|
|
261
264
|
self._instr.set_pipette_speed(
|
|
262
265
|
dispense=_assert_gzero(new_val, "speed should be a numerical value in mm/s")
|
|
263
266
|
)
|
|
@@ -267,13 +270,13 @@ class PlungerSpeeds:
|
|
|
267
270
|
return self._instr.get_hardware_state()["blow_out_speed"]
|
|
268
271
|
|
|
269
272
|
@blow_out.setter
|
|
270
|
-
def blow_out(self, new_val: float):
|
|
273
|
+
def blow_out(self, new_val: float) -> None:
|
|
271
274
|
self._instr.set_pipette_speed(
|
|
272
275
|
blow_out=_assert_gzero(new_val, "speed should be a numerical value in mm/s")
|
|
273
276
|
)
|
|
274
277
|
|
|
275
278
|
|
|
276
|
-
class AxisMaxSpeeds(UserDict):
|
|
279
|
+
class AxisMaxSpeeds(UserDict[Union[str, Axis], float]):
|
|
277
280
|
"""Special mapping allowing internal storage by Mount enums and
|
|
278
281
|
user access by string
|
|
279
282
|
"""
|
|
@@ -283,12 +286,12 @@ class AxisMaxSpeeds(UserDict):
|
|
|
283
286
|
super().__init__()
|
|
284
287
|
self._robot_type = robot_type
|
|
285
288
|
|
|
286
|
-
def __getitem__(self, key: Union[str, Axis]):
|
|
289
|
+
def __getitem__(self, key: Union[str, Axis]) -> float:
|
|
287
290
|
checked_key = AxisMaxSpeeds._verify_key(key)
|
|
288
291
|
return self.data[checked_key]
|
|
289
292
|
|
|
290
293
|
@staticmethod
|
|
291
|
-
def _verify_key(key:
|
|
294
|
+
def _verify_key(key: object) -> Axis:
|
|
292
295
|
if isinstance(key, Axis):
|
|
293
296
|
checked_key: Optional[Axis] = key
|
|
294
297
|
elif isinstance(key, str):
|
|
@@ -299,47 +302,40 @@ class AxisMaxSpeeds(UserDict):
|
|
|
299
302
|
raise KeyError(key)
|
|
300
303
|
return checked_key
|
|
301
304
|
|
|
302
|
-
def __setitem__(self, key:
|
|
305
|
+
def __setitem__(self, key: object, value: object) -> None:
|
|
306
|
+
|
|
307
|
+
checked_key = AxisMaxSpeeds._verify_key(key)
|
|
303
308
|
if value is None:
|
|
304
|
-
del self[
|
|
309
|
+
del self[checked_key]
|
|
305
310
|
return
|
|
306
311
|
|
|
307
|
-
checked_key = AxisMaxSpeeds._verify_key(key)
|
|
308
312
|
checked_val = _assert_gzero(
|
|
309
313
|
value, "max speeds should be numerical values in mm/s"
|
|
310
314
|
)
|
|
311
315
|
|
|
312
316
|
self.data[checked_key] = checked_val
|
|
313
317
|
|
|
314
|
-
def
|
|
318
|
+
def _axis_to_string(self, axis: Union[str, Axis]) -> str:
|
|
319
|
+
if isinstance(axis, str):
|
|
320
|
+
return axis
|
|
321
|
+
if self._robot_type == "OT-3 Standard":
|
|
322
|
+
return axis.name
|
|
323
|
+
return ot2_axis_to_string(axis)
|
|
324
|
+
|
|
325
|
+
def __delitem__(self, key: Union[str, Axis]) -> None:
|
|
315
326
|
checked_key = AxisMaxSpeeds._verify_key(key)
|
|
316
327
|
del self.data[checked_key]
|
|
317
328
|
|
|
318
|
-
def __iter__(self):
|
|
329
|
+
def __iter__(self) -> Iterator[str]:
|
|
319
330
|
"""keys() and dict iteration return string keys"""
|
|
320
|
-
string_keys = (
|
|
321
|
-
k.name if self._robot_type == "OT-3 Standard" else ot2_axis_to_string(k)
|
|
322
|
-
for k in self.data.keys()
|
|
323
|
-
)
|
|
331
|
+
string_keys = (self._axis_to_string(k) for k in self.data.keys())
|
|
324
332
|
return string_keys
|
|
325
333
|
|
|
326
|
-
def keys(self):
|
|
327
|
-
|
|
328
|
-
k.name if self._robot_type == "OT-3 Standard" else ot2_axis_to_string(k)
|
|
329
|
-
for k in self.data.keys()
|
|
330
|
-
)
|
|
331
|
-
return string_keys
|
|
334
|
+
def keys(self) -> KeysView[str]:
|
|
335
|
+
return ({self._axis_to_string(k): v for k, v in self.data.items()}).keys()
|
|
332
336
|
|
|
333
|
-
def items(self):
|
|
334
|
-
return (
|
|
335
|
-
(
|
|
336
|
-
k.name
|
|
337
|
-
if self._robot_type == "OT-3 Standard"
|
|
338
|
-
else ot2_axis_to_string(k),
|
|
339
|
-
v,
|
|
340
|
-
)
|
|
341
|
-
for k, v in self.data.items()
|
|
342
|
-
)
|
|
337
|
+
def items(self) -> ItemsView[str, float]:
|
|
338
|
+
return ({self._axis_to_string(k): v for k, v in self.data.items()}).items()
|
|
343
339
|
|
|
344
340
|
|
|
345
341
|
def clamp_value(
|
|
@@ -395,11 +391,3 @@ def requires_version(major: int, minor: int) -> Callable[[FuncT], FuncT]:
|
|
|
395
391
|
return cast(FuncT, _check_version_wrapper)
|
|
396
392
|
|
|
397
393
|
return _set_version
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
class ModifiedList(list):
|
|
401
|
-
def __contains__(self, item):
|
|
402
|
-
for name in self:
|
|
403
|
-
if name == item.replace("-", "_").lower():
|
|
404
|
-
return True
|
|
405
|
-
return False
|