opentrons 8.1.0__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.0.dist-info → opentrons-8.2.0.dist-info}/METADATA +5 -4
- {opentrons-8.1.0.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.0.dist-info → opentrons-8.2.0.dist-info}/LICENSE +0 -0
- {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/WHEEL +0 -0
- {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/top_level.txt +0 -0
|
@@ -14,7 +14,7 @@ from opentrons.util.change_notifier import ChangeNotifier
|
|
|
14
14
|
|
|
15
15
|
from ..resources import DeckFixedLabware
|
|
16
16
|
from ..actions import Action, ActionHandler
|
|
17
|
-
from .
|
|
17
|
+
from ._abstract_store import HasState, HandlesActions
|
|
18
18
|
from .commands import CommandState, CommandStore, CommandView
|
|
19
19
|
from .addressable_areas import (
|
|
20
20
|
AddressableAreaState,
|
|
@@ -26,8 +26,10 @@ from .pipettes import PipetteState, PipetteStore, PipetteView
|
|
|
26
26
|
from .modules import ModuleState, ModuleStore, ModuleView
|
|
27
27
|
from .liquids import LiquidState, LiquidView, LiquidStore
|
|
28
28
|
from .tips import TipState, TipView, TipStore
|
|
29
|
+
from .wells import WellState, WellView, WellStore
|
|
29
30
|
from .geometry import GeometryView
|
|
30
31
|
from .motion import MotionView
|
|
32
|
+
from .files import FileView, FileState, FileStore
|
|
31
33
|
from .config import Config
|
|
32
34
|
from .state_summary import StateSummary
|
|
33
35
|
from ..types import DeckConfigurationType
|
|
@@ -48,6 +50,8 @@ class State:
|
|
|
48
50
|
modules: ModuleState
|
|
49
51
|
liquids: LiquidState
|
|
50
52
|
tips: TipState
|
|
53
|
+
wells: WellState
|
|
54
|
+
files: FileState
|
|
51
55
|
|
|
52
56
|
|
|
53
57
|
class StateView(HasState[State]):
|
|
@@ -61,8 +65,10 @@ class StateView(HasState[State]):
|
|
|
61
65
|
_modules: ModuleView
|
|
62
66
|
_liquid: LiquidView
|
|
63
67
|
_tips: TipView
|
|
68
|
+
_wells: WellView
|
|
64
69
|
_geometry: GeometryView
|
|
65
70
|
_motion: MotionView
|
|
71
|
+
_files: FileView
|
|
66
72
|
_config: Config
|
|
67
73
|
|
|
68
74
|
@property
|
|
@@ -100,6 +106,11 @@ class StateView(HasState[State]):
|
|
|
100
106
|
"""Get state view selectors for tip state."""
|
|
101
107
|
return self._tips
|
|
102
108
|
|
|
109
|
+
@property
|
|
110
|
+
def wells(self) -> WellView:
|
|
111
|
+
"""Get state view selectors for well state."""
|
|
112
|
+
return self._wells
|
|
113
|
+
|
|
103
114
|
@property
|
|
104
115
|
def geometry(self) -> GeometryView:
|
|
105
116
|
"""Get state view selectors for derived geometry state."""
|
|
@@ -110,6 +121,11 @@ class StateView(HasState[State]):
|
|
|
110
121
|
"""Get state view selectors for derived motion state."""
|
|
111
122
|
return self._motion
|
|
112
123
|
|
|
124
|
+
@property
|
|
125
|
+
def files(self) -> FileView:
|
|
126
|
+
"""Get state view selectors for engine create file state."""
|
|
127
|
+
return self._files
|
|
128
|
+
|
|
113
129
|
@property
|
|
114
130
|
def config(self) -> Config:
|
|
115
131
|
"""Get ProtocolEngine configuration."""
|
|
@@ -129,7 +145,9 @@ class StateView(HasState[State]):
|
|
|
129
145
|
completedAt=self._state.commands.run_completed_at,
|
|
130
146
|
startedAt=self._state.commands.run_started_at,
|
|
131
147
|
liquids=self._liquid.get_all(),
|
|
148
|
+
wells=self._wells.get_all(),
|
|
132
149
|
hasEverEnteredErrorRecovery=self._commands.get_has_entered_recovery_mode(),
|
|
150
|
+
files=self._state.files.file_ids,
|
|
133
151
|
)
|
|
134
152
|
|
|
135
153
|
|
|
@@ -191,10 +209,13 @@ class StateStore(StateView, ActionHandler):
|
|
|
191
209
|
)
|
|
192
210
|
self._module_store = ModuleStore(
|
|
193
211
|
config=config,
|
|
212
|
+
deck_fixed_labware=deck_fixed_labware,
|
|
194
213
|
module_calibration_offsets=module_calibration_offsets,
|
|
195
214
|
)
|
|
196
215
|
self._liquid_store = LiquidStore()
|
|
197
216
|
self._tip_store = TipStore()
|
|
217
|
+
self._well_store = WellStore()
|
|
218
|
+
self._file_store = FileStore()
|
|
198
219
|
|
|
199
220
|
self._substores: List[HandlesActions] = [
|
|
200
221
|
self._command_store,
|
|
@@ -204,6 +225,8 @@ class StateStore(StateView, ActionHandler):
|
|
|
204
225
|
self._module_store,
|
|
205
226
|
self._liquid_store,
|
|
206
227
|
self._tip_store,
|
|
228
|
+
self._well_store,
|
|
229
|
+
self._file_store,
|
|
207
230
|
]
|
|
208
231
|
self._config = config
|
|
209
232
|
self._change_notifier = change_notifier or ChangeNotifier()
|
|
@@ -320,6 +343,8 @@ class StateStore(StateView, ActionHandler):
|
|
|
320
343
|
modules=self._module_store.state,
|
|
321
344
|
liquids=self._liquid_store.state,
|
|
322
345
|
tips=self._tip_store.state,
|
|
346
|
+
wells=self._well_store.state,
|
|
347
|
+
files=self._file_store.state,
|
|
323
348
|
)
|
|
324
349
|
|
|
325
350
|
def _initialize_state(self) -> None:
|
|
@@ -335,11 +360,14 @@ class StateStore(StateView, ActionHandler):
|
|
|
335
360
|
self._modules = ModuleView(state.modules)
|
|
336
361
|
self._liquid = LiquidView(state.liquids)
|
|
337
362
|
self._tips = TipView(state.tips)
|
|
363
|
+
self._wells = WellView(state.wells)
|
|
364
|
+
self._files = FileView(state.files)
|
|
338
365
|
|
|
339
366
|
# Derived states
|
|
340
367
|
self._geometry = GeometryView(
|
|
341
368
|
config=self._config,
|
|
342
369
|
labware_view=self._labware,
|
|
370
|
+
well_view=self._wells,
|
|
343
371
|
module_view=self._modules,
|
|
344
372
|
pipette_view=self._pipettes,
|
|
345
373
|
addressable_area_view=self._addressable_areas,
|
|
@@ -364,6 +392,7 @@ class StateStore(StateView, ActionHandler):
|
|
|
364
392
|
self._modules._state = next_state.modules
|
|
365
393
|
self._liquid._state = next_state.liquids
|
|
366
394
|
self._tips._state = next_state.tips
|
|
395
|
+
self._wells._state = next_state.wells
|
|
367
396
|
self._change_notifier.notify()
|
|
368
397
|
if self._notify_robot_server is not None:
|
|
369
398
|
self._notify_robot_server()
|
|
@@ -11,6 +11,7 @@ from ..types import (
|
|
|
11
11
|
LoadedModule,
|
|
12
12
|
LoadedPipette,
|
|
13
13
|
Liquid,
|
|
14
|
+
WellInfoSummary,
|
|
14
15
|
)
|
|
15
16
|
|
|
16
17
|
|
|
@@ -29,3 +30,5 @@ class StateSummary(BaseModel):
|
|
|
29
30
|
startedAt: Optional[datetime]
|
|
30
31
|
completedAt: Optional[datetime]
|
|
31
32
|
liquids: List[Liquid] = Field(default_factory=list)
|
|
33
|
+
wells: List[WellInfoSummary] = Field(default_factory=list)
|
|
34
|
+
files: List[str] = Field(default_factory=list)
|
|
@@ -3,27 +3,10 @@ from dataclasses import dataclass
|
|
|
3
3
|
from enum import Enum
|
|
4
4
|
from typing import Dict, Optional, List, Union
|
|
5
5
|
|
|
6
|
-
from .
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
FailCommandAction,
|
|
11
|
-
ResetTipsAction,
|
|
12
|
-
)
|
|
13
|
-
from ..commands import (
|
|
14
|
-
Command,
|
|
15
|
-
LoadLabwareResult,
|
|
16
|
-
PickUpTip,
|
|
17
|
-
PickUpTipResult,
|
|
18
|
-
DropTipResult,
|
|
19
|
-
DropTipInPlaceResult,
|
|
20
|
-
unsafe,
|
|
21
|
-
)
|
|
22
|
-
from ..commands.configuring_common import (
|
|
23
|
-
PipetteConfigUpdateResultMixin,
|
|
24
|
-
PipetteNozzleLayoutResultMixin,
|
|
25
|
-
)
|
|
26
|
-
from ..error_recovery_policy import ErrorRecoveryType
|
|
6
|
+
from opentrons.protocol_engine.state import update_types
|
|
7
|
+
|
|
8
|
+
from ._abstract_store import HasState, HandlesActions
|
|
9
|
+
from ..actions import Action, ResetTipsAction, get_state_updates
|
|
27
10
|
|
|
28
11
|
from opentrons.hardware_control.nozzle_manager import NozzleMap
|
|
29
12
|
|
|
@@ -38,16 +21,26 @@ class TipRackWellState(Enum):
|
|
|
38
21
|
TipRackStateByWellName = Dict[str, TipRackWellState]
|
|
39
22
|
|
|
40
23
|
|
|
24
|
+
# todo(mm, 2024-10-10): This info is duplicated between here and PipetteState because
|
|
25
|
+
# TipStore is using it to compute which tips a PickUpTip removes from the tip rack,
|
|
26
|
+
# given the pipette's current nozzle map. We could avoid this duplication by moving the
|
|
27
|
+
# computation to TipView, calling it from PickUpTipImplementation, and passing the
|
|
28
|
+
# precomputed list of wells to TipStore.
|
|
29
|
+
@dataclass
|
|
30
|
+
class _PipetteInfo:
|
|
31
|
+
channels: int
|
|
32
|
+
active_channels: int
|
|
33
|
+
nozzle_map: NozzleMap
|
|
34
|
+
|
|
35
|
+
|
|
41
36
|
@dataclass
|
|
42
37
|
class TipState:
|
|
43
38
|
"""State of all tips."""
|
|
44
39
|
|
|
45
40
|
tips_by_labware_id: Dict[str, TipRackStateByWellName]
|
|
46
41
|
column_by_labware_id: Dict[str, List[List[str]]]
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
active_channels_by_pipette_id: Dict[str, int]
|
|
50
|
-
nozzle_map_by_pipette_id: Dict[str, NozzleMap]
|
|
42
|
+
|
|
43
|
+
pipette_info_by_pipette_id: Dict[str, _PipetteInfo]
|
|
51
44
|
|
|
52
45
|
|
|
53
46
|
class TipStore(HasState[TipState], HandlesActions):
|
|
@@ -60,40 +53,15 @@ class TipStore(HasState[TipState], HandlesActions):
|
|
|
60
53
|
self._state = TipState(
|
|
61
54
|
tips_by_labware_id={},
|
|
62
55
|
column_by_labware_id={},
|
|
63
|
-
|
|
64
|
-
length_by_pipette_id={},
|
|
65
|
-
active_channels_by_pipette_id={},
|
|
66
|
-
nozzle_map_by_pipette_id={},
|
|
56
|
+
pipette_info_by_pipette_id={},
|
|
67
57
|
)
|
|
68
58
|
|
|
69
59
|
def handle_action(self, action: Action) -> None:
|
|
70
60
|
"""Modify state in reaction to an action."""
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
pipette_id = action.private_result.pipette_id
|
|
74
|
-
config = action.private_result.config
|
|
75
|
-
self._state.channels_by_pipette_id[pipette_id] = config.channels
|
|
76
|
-
self._state.active_channels_by_pipette_id[pipette_id] = config.channels
|
|
77
|
-
self._state.nozzle_map_by_pipette_id[pipette_id] = config.nozzle_map
|
|
78
|
-
self._handle_succeeded_command(action.command)
|
|
79
|
-
|
|
80
|
-
if isinstance(action.private_result, PipetteNozzleLayoutResultMixin):
|
|
81
|
-
pipette_id = action.private_result.pipette_id
|
|
82
|
-
nozzle_map = action.private_result.nozzle_map
|
|
83
|
-
if nozzle_map:
|
|
84
|
-
self._state.active_channels_by_pipette_id[
|
|
85
|
-
pipette_id
|
|
86
|
-
] = nozzle_map.tip_count
|
|
87
|
-
self._state.nozzle_map_by_pipette_id[pipette_id] = nozzle_map
|
|
88
|
-
else:
|
|
89
|
-
self._state.active_channels_by_pipette_id[
|
|
90
|
-
pipette_id
|
|
91
|
-
] = self._state.channels_by_pipette_id[pipette_id]
|
|
61
|
+
for state_update in get_state_updates(action):
|
|
62
|
+
self._handle_state_update(state_update)
|
|
92
63
|
|
|
93
|
-
|
|
94
|
-
self._handle_failed_command(action)
|
|
95
|
-
|
|
96
|
-
elif isinstance(action, ResetTipsAction):
|
|
64
|
+
if isinstance(action, ResetTipsAction):
|
|
97
65
|
labware_id = action.labware_id
|
|
98
66
|
|
|
99
67
|
for well_name in self._state.tips_by_labware_id[labware_id].keys():
|
|
@@ -101,67 +69,51 @@ class TipStore(HasState[TipState], HandlesActions):
|
|
|
101
69
|
well_name
|
|
102
70
|
] = TipRackWellState.CLEAN
|
|
103
71
|
|
|
104
|
-
def
|
|
105
|
-
if
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
for column in definition.ordering
|
|
114
|
-
for well_name in column
|
|
115
|
-
}
|
|
116
|
-
self._state.column_by_labware_id[labware_id] = [
|
|
117
|
-
column for column in definition.ordering
|
|
118
|
-
]
|
|
72
|
+
def _handle_state_update(self, state_update: update_types.StateUpdate) -> None:
|
|
73
|
+
if state_update.pipette_config != update_types.NO_CHANGE:
|
|
74
|
+
self._state.pipette_info_by_pipette_id[
|
|
75
|
+
state_update.pipette_config.pipette_id
|
|
76
|
+
] = _PipetteInfo(
|
|
77
|
+
channels=state_update.pipette_config.config.channels,
|
|
78
|
+
active_channels=state_update.pipette_config.config.channels,
|
|
79
|
+
nozzle_map=state_update.pipette_config.config.nozzle_map,
|
|
80
|
+
)
|
|
119
81
|
|
|
120
|
-
|
|
121
|
-
labware_id = command.params.labwareId
|
|
122
|
-
well_name = command.params.wellName
|
|
123
|
-
pipette_id = command.params.pipetteId
|
|
124
|
-
length = command.result.tipLength
|
|
82
|
+
if state_update.tips_used != update_types.NO_CHANGE:
|
|
125
83
|
self._set_used_tips(
|
|
126
|
-
pipette_id=pipette_id,
|
|
84
|
+
pipette_id=state_update.tips_used.pipette_id,
|
|
85
|
+
labware_id=state_update.tips_used.labware_id,
|
|
86
|
+
well_name=state_update.tips_used.well_name,
|
|
127
87
|
)
|
|
128
|
-
self._state.length_by_pipette_id[pipette_id] = length
|
|
129
|
-
|
|
130
|
-
elif isinstance(
|
|
131
|
-
command.result,
|
|
132
|
-
(DropTipResult, DropTipInPlaceResult, unsafe.UnsafeDropTipInPlaceResult),
|
|
133
|
-
):
|
|
134
|
-
pipette_id = command.params.pipetteId
|
|
135
|
-
self._state.length_by_pipette_id.pop(pipette_id, None)
|
|
136
88
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
# `get_next_tip()`, we'll move on to other tips as expected.
|
|
144
|
-
#
|
|
145
|
-
# We don't attempt this for nonrecoverable errors because maybe the failure
|
|
146
|
-
# was due to a bad labware ID or well name.
|
|
147
|
-
if (
|
|
148
|
-
isinstance(action.running_command, PickUpTip)
|
|
149
|
-
and action.type != ErrorRecoveryType.FAIL_RUN
|
|
150
|
-
):
|
|
151
|
-
self._set_used_tips(
|
|
152
|
-
pipette_id=action.running_command.params.pipetteId,
|
|
153
|
-
labware_id=action.running_command.params.labwareId,
|
|
154
|
-
well_name=action.running_command.params.wellName,
|
|
89
|
+
if state_update.pipette_nozzle_map != update_types.NO_CHANGE:
|
|
90
|
+
pipette_info = self._state.pipette_info_by_pipette_id[
|
|
91
|
+
state_update.pipette_nozzle_map.pipette_id
|
|
92
|
+
]
|
|
93
|
+
pipette_info.active_channels = (
|
|
94
|
+
state_update.pipette_nozzle_map.nozzle_map.tip_count
|
|
155
95
|
)
|
|
156
|
-
|
|
157
|
-
|
|
96
|
+
pipette_info.nozzle_map = state_update.pipette_nozzle_map.nozzle_map
|
|
97
|
+
|
|
98
|
+
if state_update.loaded_labware != update_types.NO_CHANGE:
|
|
99
|
+
labware_id = state_update.loaded_labware.labware_id
|
|
100
|
+
definition = state_update.loaded_labware.definition
|
|
101
|
+
if definition.parameters.isTiprack:
|
|
102
|
+
self._state.tips_by_labware_id[labware_id] = {
|
|
103
|
+
well_name: TipRackWellState.CLEAN
|
|
104
|
+
for column in definition.ordering
|
|
105
|
+
for well_name in column
|
|
106
|
+
}
|
|
107
|
+
self._state.column_by_labware_id[labware_id] = [
|
|
108
|
+
column for column in definition.ordering
|
|
109
|
+
]
|
|
158
110
|
|
|
159
111
|
def _set_used_tips( # noqa: C901
|
|
160
112
|
self, pipette_id: str, well_name: str, labware_id: str
|
|
161
113
|
) -> None:
|
|
162
114
|
columns = self._state.column_by_labware_id.get(labware_id, [])
|
|
163
115
|
wells = self._state.tips_by_labware_id.get(labware_id, {})
|
|
164
|
-
nozzle_map = self._state.
|
|
116
|
+
nozzle_map = self._state.pipette_info_by_pipette_id[pipette_id].nozzle_map
|
|
165
117
|
|
|
166
118
|
# TODO (cb, 02-28-2024): Transition from using partial nozzle map to full instrument map for the set used logic
|
|
167
119
|
num_nozzle_cols = len(nozzle_map.columns)
|
|
@@ -229,7 +181,7 @@ class TipView(HasState[TipState]):
|
|
|
229
181
|
critical_row: int,
|
|
230
182
|
entry_well: str,
|
|
231
183
|
) -> Optional[List[str]]:
|
|
232
|
-
tip_cluster = []
|
|
184
|
+
tip_cluster: list[str] = []
|
|
233
185
|
for i in range(active_columns):
|
|
234
186
|
if entry_well == "A1" or entry_well == "H1":
|
|
235
187
|
if critical_column - i >= 0:
|
|
@@ -280,12 +232,12 @@ class TipView(HasState[TipState]):
|
|
|
280
232
|
|
|
281
233
|
# In the case of a 96ch we can attempt to index in by singular rows and columns assuming that indexed direction is safe
|
|
282
234
|
# The tip cluster list is ordered: Each row from a column in order by columns
|
|
283
|
-
tip_cluster_final_column = []
|
|
235
|
+
tip_cluster_final_column: list[str] = []
|
|
284
236
|
for i in range(active_rows):
|
|
285
237
|
tip_cluster_final_column.append(
|
|
286
238
|
tip_cluster[((active_columns * active_rows) - 1) - i]
|
|
287
239
|
)
|
|
288
|
-
tip_cluster_final_row = []
|
|
240
|
+
tip_cluster_final_row: list[str] = []
|
|
289
241
|
for i in range(active_columns):
|
|
290
242
|
tip_cluster_final_row.append(
|
|
291
243
|
tip_cluster[(active_rows - 1) + (i * active_rows)]
|
|
@@ -476,15 +428,22 @@ class TipView(HasState[TipState]):
|
|
|
476
428
|
|
|
477
429
|
def get_pipette_channels(self, pipette_id: str) -> int:
|
|
478
430
|
"""Return the given pipette's number of channels."""
|
|
479
|
-
return self._state.
|
|
431
|
+
return self._state.pipette_info_by_pipette_id[pipette_id].channels
|
|
480
432
|
|
|
481
433
|
def get_pipette_active_channels(self, pipette_id: str) -> int:
|
|
482
434
|
"""Get the number of channels being used in the given pipette's configuration."""
|
|
483
|
-
return self._state.
|
|
435
|
+
return self._state.pipette_info_by_pipette_id[pipette_id].active_channels
|
|
484
436
|
|
|
485
437
|
def get_pipette_nozzle_map(self, pipette_id: str) -> NozzleMap:
|
|
486
438
|
"""Get the current nozzle map the given pipette's configuration."""
|
|
487
|
-
return self._state.
|
|
439
|
+
return self._state.pipette_info_by_pipette_id[pipette_id].nozzle_map
|
|
440
|
+
|
|
441
|
+
def get_pipette_nozzle_maps(self) -> Dict[str, NozzleMap]:
|
|
442
|
+
"""Get current nozzle maps keyed by pipette id."""
|
|
443
|
+
return {
|
|
444
|
+
pipette_id: pipette_info.nozzle_map
|
|
445
|
+
for pipette_id, pipette_info in self._state.pipette_info_by_pipette_id.items()
|
|
446
|
+
}
|
|
488
447
|
|
|
489
448
|
def has_clean_tip(self, labware_id: str, well_name: str) -> bool:
|
|
490
449
|
"""Get whether a well in a labware has a clean tip.
|
|
@@ -502,10 +461,6 @@ class TipView(HasState[TipState]):
|
|
|
502
461
|
|
|
503
462
|
return well_state == TipRackWellState.CLEAN
|
|
504
463
|
|
|
505
|
-
def get_tip_length(self, pipette_id: str) -> float:
|
|
506
|
-
"""Return the given pipette's tip length."""
|
|
507
|
-
return self._state.length_by_pipette_id.get(pipette_id, 0)
|
|
508
|
-
|
|
509
464
|
|
|
510
465
|
def _drop_wells_before_starting_tip(
|
|
511
466
|
wells: TipRackStateByWellName, starting_tip_name: str
|