opentrons 8.1.0a0__py2.py3-none-any.whl → 8.2.0a0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opentrons/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 +207 -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/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 +230 -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 +126 -89
- 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/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 +10 -2
- opentrons/protocol_api/core/engine/module_core.py +129 -17
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +355 -0
- opentrons/protocol_api/core/engine/protocol.py +55 -2
- opentrons/protocol_api/core/instrument.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +5 -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 +5 -2
- opentrons/protocol_api/instrument_context.py +52 -20
- opentrons/protocol_api/labware.py +13 -1
- opentrons/protocol_api/module_contexts.py +68 -13
- opentrons/protocol_api/protocol_context.py +38 -4
- opentrons/protocol_api/validation.py +5 -3
- opentrons/protocol_engine/__init__.py +10 -9
- opentrons/protocol_engine/actions/__init__.py +5 -0
- opentrons/protocol_engine/actions/actions.py +42 -25
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/sync_client.py +7 -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 +161 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +53 -9
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +160 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +196 -0
- opentrons/protocol_engine/commands/aspirate.py +29 -16
- opentrons/protocol_engine/commands/aspirate_in_place.py +32 -15
- 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 +28 -17
- 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 +68 -15
- opentrons/protocol_engine/commands/drop_tip_in_place.py +52 -11
- 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 +19 -5
- opentrons/protocol_engine/commands/load_liquid.py +18 -7
- opentrons/protocol_engine/commands/load_module.py +43 -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 +106 -19
- 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 +50 -29
- opentrons/protocol_engine/commands/pipetting_common.py +39 -15
- 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 +194 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +75 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +5 -3
- 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 +41 -8
- opentrons/protocol_engine/engine_support.py +2 -1
- opentrons/protocol_engine/error_recovery_policy.py +14 -3
- opentrons/protocol_engine/errors/__init__.py +18 -0
- opentrons/protocol_engine/errors/exceptions.py +114 -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 +6 -3
- opentrons/protocol_engine/execution/movement.py +8 -3
- 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 +54 -31
- opentrons/protocol_engine/resources/__init__.py +2 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +58 -5
- opentrons/protocol_engine/resources/file_provider.py +157 -0
- opentrons/protocol_engine/resources/fixture_validation.py +5 -0
- 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 +359 -15
- opentrons/protocol_engine/state/labware.py +166 -63
- opentrons/protocol_engine/state/liquids.py +1 -1
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +19 -3
- opentrons/protocol_engine/state/modules.py +167 -85
- opentrons/protocol_engine/state/motion.py +16 -9
- 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 +408 -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 +26 -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/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.0a0.dist-info}/METADATA +5 -4
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/RECORD +227 -215
- 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.0a0.dist-info}/LICENSE +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/WHEEL +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Optional, List
|
|
2
|
+
from typing import Any, Optional, List, cast
|
|
3
3
|
from typing_extensions import Final
|
|
4
|
-
|
|
5
4
|
import math
|
|
6
5
|
import functools
|
|
7
6
|
|
|
@@ -54,7 +53,7 @@ class DurationEstimator:
|
|
|
54
53
|
Broker listener that calculates the duration of protocol steps.
|
|
55
54
|
"""
|
|
56
55
|
|
|
57
|
-
def __init__(self):
|
|
56
|
+
def __init__(self) -> None:
|
|
58
57
|
# Which slot the last command was in.
|
|
59
58
|
self._last_deckslot = STARTING_SLOT
|
|
60
59
|
# todo(mm, 2021-09-08): Support protocols with more than one
|
|
@@ -128,39 +127,50 @@ class DurationEstimator:
|
|
|
128
127
|
# TODO (al, 2021-09-09):
|
|
129
128
|
# - Make this into a map
|
|
130
129
|
# - Remove "noqa: C901"
|
|
131
|
-
# - type the payload in the on_X methods.
|
|
132
130
|
if message_name == types.PICK_UP_TIP:
|
|
131
|
+
payload = cast(types.PickUpTipCommandPayload, payload)
|
|
133
132
|
duration = self.on_pick_up_tip(payload=payload)
|
|
134
133
|
elif message_name == types.DROP_TIP:
|
|
134
|
+
payload = cast(types.DropTipCommandPayload, payload)
|
|
135
135
|
duration = self.on_drop_tip(payload=payload)
|
|
136
136
|
elif message_name == types.ASPIRATE:
|
|
137
|
+
payload = cast(types.AspirateDispenseCommandPayload, payload)
|
|
137
138
|
duration = self.on_aspirate(payload=payload)
|
|
138
139
|
elif message_name == types.DISPENSE:
|
|
140
|
+
payload = cast(types.AspirateDispenseCommandPayload, payload)
|
|
139
141
|
duration = self.on_dispense(payload=payload)
|
|
140
142
|
elif message_name == types.BLOW_OUT:
|
|
143
|
+
payload = cast(types.BlowOutCommandPayload, payload)
|
|
141
144
|
duration = self.on_blow_out(payload=payload)
|
|
142
145
|
elif message_name == types.TOUCH_TIP:
|
|
143
|
-
|
|
146
|
+
payload = cast(types.TouchTipCommandPayload, payload)
|
|
147
|
+
duration = self.on_touch_tip()
|
|
144
148
|
elif message_name == types.DELAY:
|
|
149
|
+
payload = cast(types.DelayCommandPayload, payload)
|
|
145
150
|
duration = self.on_delay(payload=payload)
|
|
146
151
|
elif message_name == types.TEMPDECK_SET_TEMP:
|
|
152
|
+
payload = cast(types.TempdeckSetTempCommandPayload, payload)
|
|
147
153
|
duration = self.on_tempdeck_set_temp(payload=payload)
|
|
148
154
|
elif message_name == types.TEMPDECK_DEACTIVATE:
|
|
149
|
-
|
|
155
|
+
payload = cast(types.TempdeckDeactivateCommandPayload, payload)
|
|
156
|
+
duration = self.on_tempdeck_deactivate()
|
|
150
157
|
elif message_name == types.TEMPDECK_AWAIT_TEMP:
|
|
151
|
-
|
|
158
|
+
payload = cast(types.TempdeckAwaitTempCommandPayload, payload)
|
|
159
|
+
duration = self.on_tempdeck_await_temp()
|
|
152
160
|
elif message_name == types.THERMOCYCLER_SET_BLOCK_TEMP:
|
|
161
|
+
payload = cast(types.ThermocyclerSetBlockTempCommandPayload, payload)
|
|
153
162
|
duration = self.on_thermocycler_block_temp(payload=payload)
|
|
154
163
|
elif message_name == types.THERMOCYCLER_EXECUTE_PROFILE:
|
|
164
|
+
payload = cast(types.ThermocyclerExecuteProfileCommandPayload, payload)
|
|
155
165
|
duration = self.on_execute_profile(payload=payload)
|
|
156
166
|
elif message_name == types.THERMOCYCLER_SET_LID_TEMP:
|
|
157
|
-
duration = self.on_thermocycler_set_lid_temp(
|
|
167
|
+
duration = self.on_thermocycler_set_lid_temp()
|
|
158
168
|
elif message_name == types.THERMOCYCLER_CLOSE:
|
|
159
|
-
duration = self.on_thermocycler_lid_close(
|
|
169
|
+
duration = self.on_thermocycler_lid_close()
|
|
160
170
|
elif message_name == types.THERMOCYCLER_DEACTIVATE_LID:
|
|
161
|
-
duration = self.on_thermocycler_deactivate_lid(
|
|
171
|
+
duration = self.on_thermocycler_deactivate_lid()
|
|
162
172
|
elif message_name == types.THERMOCYCLER_OPEN:
|
|
163
|
-
duration = self.on_thermocycler_lid_open(
|
|
173
|
+
duration = self.on_thermocycler_lid_open()
|
|
164
174
|
elif message_name == types.TRANSFER:
|
|
165
175
|
# Already accounted for in other steps
|
|
166
176
|
pass
|
|
@@ -177,10 +187,10 @@ class DurationEstimator:
|
|
|
177
187
|
)
|
|
178
188
|
return duration
|
|
179
189
|
|
|
180
|
-
def on_pick_up_tip(self, payload) -> float:
|
|
190
|
+
def on_pick_up_tip(self, payload: types.PickUpTipCommandPayload) -> float:
|
|
181
191
|
"""Handle a pick up tip event"""
|
|
182
|
-
instrument = payload["instrument"]
|
|
183
192
|
|
|
193
|
+
instrument = payload["instrument"]
|
|
184
194
|
location = payload["location"]
|
|
185
195
|
prev_slot = self._last_deckslot
|
|
186
196
|
curr_slot = self.get_slot(location)
|
|
@@ -200,7 +210,8 @@ class DurationEstimator:
|
|
|
200
210
|
)
|
|
201
211
|
return duration
|
|
202
212
|
|
|
203
|
-
def on_drop_tip(self, payload) -> float:
|
|
213
|
+
def on_drop_tip(self, payload: types.DropTipCommandPayload) -> float:
|
|
214
|
+
|
|
204
215
|
instrument = payload["instrument"]
|
|
205
216
|
# We are going to once again use our "deck movement" set up. This should
|
|
206
217
|
# be in pickup, drop tip, aspirate, dispense
|
|
@@ -221,7 +232,7 @@ class DurationEstimator:
|
|
|
221
232
|
logger.info(f"{instrument.name}, drop tip duration is {duration}")
|
|
222
233
|
return duration
|
|
223
234
|
|
|
224
|
-
def on_aspirate(self, payload) -> float:
|
|
235
|
+
def on_aspirate(self, payload: types.AspirateDispenseCommandPayload) -> float:
|
|
225
236
|
# General aspiration code
|
|
226
237
|
instrument = payload["instrument"]
|
|
227
238
|
volume = payload["volume"]
|
|
@@ -250,13 +261,14 @@ class DurationEstimator:
|
|
|
250
261
|
deck_travel_time = self.calc_deck_movement_time(
|
|
251
262
|
self._deck, curr_slot, prev_slot, gantry_speed
|
|
252
263
|
)
|
|
264
|
+
assert isinstance(aspiration_time, float)
|
|
253
265
|
duration = deck_travel_time + z_total_time + aspiration_time
|
|
254
266
|
logger.info(
|
|
255
267
|
f"{instrument.name} aspirate from {slot}, " f"the duration is {duration}"
|
|
256
268
|
)
|
|
257
269
|
return duration
|
|
258
270
|
|
|
259
|
-
def on_dispense(self, payload) -> float:
|
|
271
|
+
def on_dispense(self, payload: types.AspirateDispenseCommandPayload) -> float:
|
|
260
272
|
# General code for aspiration/dispense
|
|
261
273
|
instrument = payload["instrument"]
|
|
262
274
|
volume = payload["volume"]
|
|
@@ -282,6 +294,7 @@ class DurationEstimator:
|
|
|
282
294
|
self._deck, curr_slot, prev_slot, gantry_speed
|
|
283
295
|
)
|
|
284
296
|
|
|
297
|
+
assert isinstance(dispense_time, float)
|
|
285
298
|
duration = deck_travel_time + z_total_time + dispense_time
|
|
286
299
|
|
|
287
300
|
logger.info(
|
|
@@ -289,7 +302,7 @@ class DurationEstimator:
|
|
|
289
302
|
)
|
|
290
303
|
return duration
|
|
291
304
|
|
|
292
|
-
def on_blow_out(self, payload) -> float:
|
|
305
|
+
def on_blow_out(self, payload: types.BlowOutCommandPayload) -> float:
|
|
293
306
|
location = payload["location"]
|
|
294
307
|
curr_slot = self.get_slot(location)
|
|
295
308
|
# In theory, we could use instrument.flow_rate.blow_out, but we don't
|
|
@@ -299,7 +312,7 @@ class DurationEstimator:
|
|
|
299
312
|
logger.info(f"blowing_out_for {duration} seconds, in slot {curr_slot}")
|
|
300
313
|
return duration
|
|
301
314
|
|
|
302
|
-
def on_touch_tip(self
|
|
315
|
+
def on_touch_tip(self) -> float:
|
|
303
316
|
# base assumption. Touch_tip takes 0.5 seconds This is consistent with a
|
|
304
317
|
# ~7.5mm diameter (default 60mm/s, 4 sides)
|
|
305
318
|
# plate = protocol.load_labware('corning_96_wellplate_360ul_flat', '1')
|
|
@@ -311,17 +324,20 @@ class DurationEstimator:
|
|
|
311
324
|
logger.info(f"touch_tip for {duration} seconds")
|
|
312
325
|
return duration
|
|
313
326
|
|
|
314
|
-
def on_delay(self, payload) -> float:
|
|
327
|
+
def on_delay(self, payload: types.DelayCommandPayload) -> float:
|
|
315
328
|
# Explanation: we are gathering seconds and minutes here
|
|
316
329
|
seconds_delay = payload["seconds"]
|
|
317
330
|
minutes_delay = payload["minutes"]
|
|
318
331
|
duration = seconds_delay + minutes_delay * 60
|
|
332
|
+
duration = float(duration)
|
|
319
333
|
# Note will need to multiply minutes by 60
|
|
320
334
|
logger.info(f"delay for {seconds_delay} seconds and {minutes_delay} minutes")
|
|
321
335
|
|
|
322
336
|
return duration
|
|
323
337
|
|
|
324
|
-
def on_thermocycler_block_temp(
|
|
338
|
+
def on_thermocycler_block_temp(
|
|
339
|
+
self, payload: types.ThermocyclerSetBlockTempCommandPayload
|
|
340
|
+
) -> float:
|
|
325
341
|
temperature = payload["temperature"]
|
|
326
342
|
hold_time = payload["hold_time"]
|
|
327
343
|
temp0 = self._last_thermocycler_module_temperature
|
|
@@ -340,10 +356,13 @@ class DurationEstimator:
|
|
|
340
356
|
f"hold for {hold_time} seconds and set temp for {temperature}"
|
|
341
357
|
f" C total duration {duration}"
|
|
342
358
|
)
|
|
359
|
+
duration = float(duration)
|
|
343
360
|
|
|
344
361
|
return duration
|
|
345
362
|
|
|
346
|
-
def on_execute_profile(
|
|
363
|
+
def on_execute_profile(
|
|
364
|
+
self, payload: types.ThermocyclerExecuteProfileCommandPayload
|
|
365
|
+
) -> float:
|
|
347
366
|
# Overview We need to run each time a temperature change happens
|
|
348
367
|
# through thermocycler_handler and multiply
|
|
349
368
|
# By the cycle count. Then we also (in parallel) do the same with delays
|
|
@@ -386,35 +405,37 @@ class DurationEstimator:
|
|
|
386
405
|
)
|
|
387
406
|
return duration
|
|
388
407
|
|
|
389
|
-
def on_thermocycler_set_lid_temp(self
|
|
408
|
+
def on_thermocycler_set_lid_temp(self) -> float:
|
|
390
409
|
# Hardware said ~1 minute
|
|
391
410
|
duration = 60
|
|
392
411
|
thermoaction = "set lid temperature"
|
|
393
412
|
logger.info(f"thermocation = {thermoaction}")
|
|
394
413
|
return duration
|
|
395
414
|
|
|
396
|
-
def on_thermocycler_lid_close(self
|
|
415
|
+
def on_thermocycler_lid_close(self) -> float:
|
|
397
416
|
# Hardware said ~24 seconds
|
|
398
417
|
duration = 24
|
|
399
418
|
thermoaction = "closing"
|
|
400
419
|
logger.info(f"thermocation = {thermoaction}")
|
|
401
420
|
return duration
|
|
402
421
|
|
|
403
|
-
def on_thermocycler_lid_open(self
|
|
422
|
+
def on_thermocycler_lid_open(self) -> float:
|
|
404
423
|
# Hardware said ~24 seconds
|
|
405
424
|
duration = 24
|
|
406
425
|
thermoaction = "opening"
|
|
407
426
|
logger.info(f"thermocation = {thermoaction}")
|
|
408
427
|
return duration
|
|
409
428
|
|
|
410
|
-
def on_thermocycler_deactivate_lid(self
|
|
429
|
+
def on_thermocycler_deactivate_lid(self) -> float:
|
|
411
430
|
# Hardware said ~23 seconds
|
|
412
431
|
duration = 23
|
|
413
432
|
thermoaction = "Deactivating"
|
|
414
433
|
logger.info(f"thermocation = {thermoaction}")
|
|
415
434
|
return duration
|
|
416
435
|
|
|
417
|
-
def on_tempdeck_set_temp(
|
|
436
|
+
def on_tempdeck_set_temp(
|
|
437
|
+
self, payload: types.TempdeckSetTempCommandPayload
|
|
438
|
+
) -> float:
|
|
418
439
|
temperature_tempdeck = payload["celsius"]
|
|
419
440
|
temp0 = self._last_temperature_module_temperature
|
|
420
441
|
temp1 = float(temperature_tempdeck)
|
|
@@ -460,20 +481,20 @@ class DurationEstimator:
|
|
|
460
481
|
duration = self.rate_low(temp0, temp1)
|
|
461
482
|
return duration
|
|
462
483
|
|
|
463
|
-
def on_tempdeck_deactivate(self
|
|
484
|
+
def on_tempdeck_deactivate(self) -> float:
|
|
464
485
|
# TODO (al, 2021-09-08: Find an answer for this value.
|
|
465
486
|
duration = 0.0
|
|
466
487
|
logger.info("tempdeck deactivating")
|
|
467
488
|
return duration
|
|
468
489
|
|
|
469
|
-
def on_tempdeck_await_temp(self
|
|
490
|
+
def on_tempdeck_await_temp(self) -> float:
|
|
470
491
|
# The duration is accounted for in set temperature
|
|
471
492
|
duration = 0.0
|
|
472
493
|
logger.info("tempdeck awaiting temperature")
|
|
473
494
|
return duration
|
|
474
495
|
|
|
475
496
|
@staticmethod
|
|
476
|
-
def get_slot(location) -> Optional[str]:
|
|
497
|
+
def get_slot(location: Any) -> Optional[str]:
|
|
477
498
|
"""A utility function to extract the slot number from the location."""
|
|
478
499
|
if isinstance(location, Location):
|
|
479
500
|
return location.labware.first_parent()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Callable, Dict, TYPE_CHECKING
|
|
1
|
+
from typing import Callable, Dict, TYPE_CHECKING, Any
|
|
2
2
|
|
|
3
3
|
from typing_extensions import Protocol, TypedDict
|
|
4
4
|
|
|
@@ -45,7 +45,7 @@ if Protocol is not None:
|
|
|
45
45
|
not a type (https://github.com/python/mypy/issues/3915)
|
|
46
46
|
"""
|
|
47
47
|
|
|
48
|
-
async def _asdict(self):
|
|
48
|
+
async def _asdict(self) -> Dict[Any, Any]:
|
|
49
49
|
...
|
|
50
50
|
|
|
51
51
|
|
|
@@ -8,6 +8,11 @@ from opentrons.protocol_api import (
|
|
|
8
8
|
ModuleContext,
|
|
9
9
|
ThermocyclerContext,
|
|
10
10
|
)
|
|
11
|
+
from opentrons_shared_data.protocol.types import (
|
|
12
|
+
MagneticModuleCommand,
|
|
13
|
+
TemperatureModuleCommand,
|
|
14
|
+
ThermocyclerCommand,
|
|
15
|
+
)
|
|
11
16
|
from .execute_json_v3 import _delay, _move_to_slot
|
|
12
17
|
from opentrons.protocols.execution.types import LoadedLabware, Instruments
|
|
13
18
|
from opentrons_shared_data.protocol.constants import (
|
|
@@ -277,21 +282,21 @@ def dispatch_json(
|
|
|
277
282
|
params, # type: ignore
|
|
278
283
|
modules,
|
|
279
284
|
command_type, # type: ignore
|
|
280
|
-
magnetic_module_command_map,
|
|
285
|
+
magnetic_module_command_map, # type: ignore[arg-type]
|
|
281
286
|
)
|
|
282
287
|
elif command_type in temperature_module_command_map:
|
|
283
288
|
handleTemperatureCommand(
|
|
284
|
-
params, # type: ignore
|
|
289
|
+
params, # type: ignore[arg-type]
|
|
285
290
|
modules,
|
|
286
291
|
command_type, # type: ignore
|
|
287
|
-
temperature_module_command_map,
|
|
292
|
+
temperature_module_command_map, # type: ignore[arg-type]
|
|
288
293
|
)
|
|
289
294
|
elif command_type in thermocycler_module_command_map:
|
|
290
295
|
handleThermocyclerCommand(
|
|
291
296
|
params, # type: ignore
|
|
292
297
|
modules, # type: ignore
|
|
293
298
|
command_type, # type: ignore
|
|
294
|
-
thermocycler_module_command_map,
|
|
299
|
+
thermocycler_module_command_map, # type: ignore[arg-type]
|
|
295
300
|
)
|
|
296
301
|
elif command_item["command"] == JsonRobotCommand.delay.value:
|
|
297
302
|
_delay(context, params) # type: ignore
|
|
@@ -305,12 +310,12 @@ def handleTemperatureCommand(
|
|
|
305
310
|
params: Union["TemperatureParams", "ModuleIDParams"],
|
|
306
311
|
modules: Dict[str, ModuleContext],
|
|
307
312
|
command_type: "TemperatureModuleCommandId",
|
|
308
|
-
temperature_module_command_map,
|
|
313
|
+
temperature_module_command_map: TemperatureModuleCommand,
|
|
309
314
|
) -> None:
|
|
310
315
|
module_id = params["module"]
|
|
311
316
|
module = modules[module_id]
|
|
312
317
|
if isinstance(module, TemperatureModuleContext):
|
|
313
|
-
temperature_module_command_map[command_type](module, params)
|
|
318
|
+
temperature_module_command_map[command_type](module, params) # type: ignore[typeddict-item]
|
|
314
319
|
else:
|
|
315
320
|
raise RuntimeError(
|
|
316
321
|
"Temperature Module does not match " + "TemperatureModuleContext interface"
|
|
@@ -326,12 +331,12 @@ def handleThermocyclerCommand(
|
|
|
326
331
|
],
|
|
327
332
|
modules: Dict[str, ThermocyclerContext],
|
|
328
333
|
command_type: "ThermocyclerCommandId",
|
|
329
|
-
thermocycler_module_command_map,
|
|
334
|
+
thermocycler_module_command_map: ThermocyclerCommand,
|
|
330
335
|
) -> None:
|
|
331
336
|
module_id = params["module"]
|
|
332
337
|
module = modules[module_id]
|
|
333
338
|
if isinstance(module, ThermocyclerContext):
|
|
334
|
-
thermocycler_module_command_map[command_type](module, params)
|
|
339
|
+
thermocycler_module_command_map[command_type](module, params) # type: ignore[typeddict-item]
|
|
335
340
|
else:
|
|
336
341
|
raise RuntimeError(
|
|
337
342
|
"Thermocycler Module does not match ThermocyclerContext interface"
|
|
@@ -342,12 +347,12 @@ def handleMagnetCommand(
|
|
|
342
347
|
params: Union["ModuleIDParams", "MagneticModuleEngageParams"],
|
|
343
348
|
modules: Dict[str, ModuleContext],
|
|
344
349
|
command_type: "MagneticModuleCommandId",
|
|
345
|
-
magnetic_module_command_map,
|
|
350
|
+
magnetic_module_command_map: MagneticModuleCommand,
|
|
346
351
|
) -> None:
|
|
347
352
|
module_id = params["module"]
|
|
348
353
|
module = modules[module_id]
|
|
349
354
|
if isinstance(module, MagneticModuleContext):
|
|
350
|
-
magnetic_module_command_map[command_type](module, params)
|
|
355
|
+
magnetic_module_command_map[command_type](module, params) # type: ignore[typeddict-item]
|
|
351
356
|
else:
|
|
352
357
|
raise RuntimeError(
|
|
353
358
|
"Magnetic Module does not match MagneticModuleContext interface"
|
|
@@ -3,6 +3,7 @@ import inspect
|
|
|
3
3
|
import logging
|
|
4
4
|
import traceback
|
|
5
5
|
import sys
|
|
6
|
+
from types import TracebackType
|
|
6
7
|
from typing import Any, Dict, Optional
|
|
7
8
|
|
|
8
9
|
from opentrons.drivers.smoothie_drivers.errors import SmoothieAlarm
|
|
@@ -21,7 +22,7 @@ from opentrons_shared_data.errors.exceptions import ExecutionCancelledError
|
|
|
21
22
|
MODULE_LOG = logging.getLogger(__name__)
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
def _runfunc_ok(run_func: Any):
|
|
25
|
+
def _runfunc_ok(run_func: Any) -> None:
|
|
25
26
|
if not callable(run_func):
|
|
26
27
|
raise SyntaxError("No function 'run(ctx)' defined")
|
|
27
28
|
sig = inspect.Signature.from_callable(run_func)
|
|
@@ -44,10 +45,14 @@ def _add_parameters_func_ok(add_parameters_func: Any) -> None:
|
|
|
44
45
|
raise SyntaxError("Function 'add_parameters' must take exactly one argument.")
|
|
45
46
|
|
|
46
47
|
|
|
47
|
-
def _find_protocol_error(
|
|
48
|
+
def _find_protocol_error(
|
|
49
|
+
tb: TracebackType | None, proto_name: str
|
|
50
|
+
) -> traceback.FrameSummary:
|
|
48
51
|
"""Return the FrameInfo for the lowest frame in the traceback from the
|
|
49
52
|
protocol.
|
|
50
53
|
"""
|
|
54
|
+
if tb is None:
|
|
55
|
+
raise KeyError
|
|
51
56
|
tb_info = traceback.extract_tb(tb)
|
|
52
57
|
for frame in reversed(tb_info):
|
|
53
58
|
if frame.filename == proto_name:
|
|
@@ -57,7 +62,7 @@ def _find_protocol_error(tb, proto_name):
|
|
|
57
62
|
|
|
58
63
|
|
|
59
64
|
def _raise_pretty_protocol_error(exception: Exception, filename: str) -> None:
|
|
60
|
-
|
|
65
|
+
_, _, tb = sys.exc_info()
|
|
61
66
|
try:
|
|
62
67
|
frame = _find_protocol_error(tb, filename)
|
|
63
68
|
except KeyError:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import logging
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import List, Optional, Tuple
|
|
4
|
+
from typing import Any, List, Optional, Tuple, Type
|
|
5
5
|
|
|
6
6
|
from opentrons import types
|
|
7
7
|
from opentrons.hardware_control.types import CriticalPoint
|
|
@@ -27,7 +27,7 @@ class LabwareHeightError(Exception):
|
|
|
27
27
|
pass
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def max_many(*args):
|
|
30
|
+
def max_many(*args: float) -> float:
|
|
31
31
|
return functools.reduce(max, args[1:], args[0])
|
|
32
32
|
|
|
33
33
|
|
|
@@ -76,7 +76,7 @@ class MoveConstraints:
|
|
|
76
76
|
minimum_z_height: float = 0.0
|
|
77
77
|
|
|
78
78
|
@classmethod
|
|
79
|
-
def build(cls, **kwargs):
|
|
79
|
+
def build(cls: Type["MoveConstraints"], **kwargs: Any) -> "MoveConstraints":
|
|
80
80
|
return cls(**{k: v for k, v in kwargs.items() if v is not None})
|
|
81
81
|
|
|
82
82
|
|
|
@@ -103,10 +103,10 @@ def safe_height(
|
|
|
103
103
|
to_loc: types.Location,
|
|
104
104
|
deck: Deck,
|
|
105
105
|
instr_max_height: float,
|
|
106
|
-
well_z_margin: float = None,
|
|
107
|
-
lw_z_margin: float = None,
|
|
108
|
-
minimum_lw_z_margin: float = None,
|
|
109
|
-
minimum_z_height: float = None,
|
|
106
|
+
well_z_margin: Optional[float] = None,
|
|
107
|
+
lw_z_margin: Optional[float] = None,
|
|
108
|
+
minimum_lw_z_margin: Optional[float] = None,
|
|
109
|
+
minimum_z_height: Optional[float] = None,
|
|
110
110
|
) -> float:
|
|
111
111
|
"""
|
|
112
112
|
Derive the height required to clear the current deck setup along
|
|
@@ -147,7 +147,7 @@ def _build_safe_height(
|
|
|
147
147
|
from_point = from_loc.point
|
|
148
148
|
from_lw, from_well = from_loc.labware.get_parent_labware_and_well()
|
|
149
149
|
|
|
150
|
-
if to_lw and to_lw == from_lw:
|
|
150
|
+
if to_lw and from_lw and to_lw == from_lw:
|
|
151
151
|
# If we know the labwares we’re moving from and to, we can calculate
|
|
152
152
|
# a safe z based on their heights
|
|
153
153
|
if to_well:
|
|
@@ -206,11 +206,11 @@ def plan_moves(
|
|
|
206
206
|
to_loc: types.Location,
|
|
207
207
|
deck: Deck,
|
|
208
208
|
instr_max_height: float,
|
|
209
|
-
well_z_margin: float = None,
|
|
210
|
-
lw_z_margin: float = None,
|
|
209
|
+
well_z_margin: Optional[float] = None,
|
|
210
|
+
lw_z_margin: Optional[float] = None,
|
|
211
211
|
force_direct: bool = False,
|
|
212
|
-
minimum_lw_z_margin: float = None,
|
|
213
|
-
minimum_z_height: float = None,
|
|
212
|
+
minimum_lw_z_margin: Optional[float] = None,
|
|
213
|
+
minimum_z_height: Optional[float] = None,
|
|
214
214
|
use_experimental_waypoint_planning: bool = False,
|
|
215
215
|
) -> List[Tuple[types.Point, Optional[CriticalPoint]]]:
|
|
216
216
|
"""Plan moves between one :py:class:`.Location` and another.
|
opentrons/protocols/labware.py
CHANGED
|
@@ -2,14 +2,12 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
import json
|
|
5
|
-
import os
|
|
6
5
|
|
|
7
6
|
from pathlib import Path
|
|
8
|
-
from typing import Any, AnyStr,
|
|
7
|
+
from typing import Any, AnyStr, Dict, Optional, Union
|
|
9
8
|
|
|
10
9
|
import jsonschema # type: ignore
|
|
11
10
|
|
|
12
|
-
from opentrons.protocols.api_support.util import ModifiedList
|
|
13
11
|
from opentrons_shared_data import load_shared_data, get_shared_data_root
|
|
14
12
|
from opentrons.protocols.api_support.constants import (
|
|
15
13
|
OPENTRONS_NAMESPACE,
|
|
@@ -63,29 +61,6 @@ def get_labware_definition(
|
|
|
63
61
|
return _get_standard_labware_definition(load_name, namespace, version)
|
|
64
62
|
|
|
65
63
|
|
|
66
|
-
def get_all_labware_definitions() -> List[str]:
|
|
67
|
-
"""
|
|
68
|
-
Return a list of standard and custom labware definitions with load_name +
|
|
69
|
-
name_space + version existing on the robot
|
|
70
|
-
"""
|
|
71
|
-
labware_list = ModifiedList()
|
|
72
|
-
|
|
73
|
-
def _check_for_subdirectories(path):
|
|
74
|
-
with os.scandir(path) as top_path:
|
|
75
|
-
for sub_dir in top_path:
|
|
76
|
-
if sub_dir.is_dir():
|
|
77
|
-
labware_list.append(sub_dir.name)
|
|
78
|
-
|
|
79
|
-
# check for standard labware
|
|
80
|
-
_check_for_subdirectories(get_shared_data_root() / STANDARD_DEFS_PATH)
|
|
81
|
-
|
|
82
|
-
# check for custom labware
|
|
83
|
-
for namespace in os.scandir(USER_DEFS_PATH):
|
|
84
|
-
_check_for_subdirectories(namespace)
|
|
85
|
-
|
|
86
|
-
return labware_list
|
|
87
|
-
|
|
88
|
-
|
|
89
64
|
def save_definition(
|
|
90
65
|
labware_def: LabwareDefinition, force: bool = False, location: Optional[Path] = None
|
|
91
66
|
) -> None:
|
|
@@ -114,7 +89,6 @@ def save_definition(
|
|
|
114
89
|
f'Saving definitions to the "{OPENTRONS_NAMESPACE}" namespace '
|
|
115
90
|
+ "is not permitted"
|
|
116
91
|
)
|
|
117
|
-
|
|
118
92
|
def_path = _get_path_to_labware(load_name, namespace, version, location)
|
|
119
93
|
|
|
120
94
|
if not force and def_path.is_file():
|
|
@@ -150,7 +124,7 @@ def verify_definition(
|
|
|
150
124
|
jsonschema.validate(to_return, labware_schema_v2)
|
|
151
125
|
# we can type ignore this because if it passes the jsonschema it has
|
|
152
126
|
# the correct structure
|
|
153
|
-
return to_return # type: ignore
|
|
127
|
+
return to_return # type: ignore[return-value]
|
|
154
128
|
|
|
155
129
|
|
|
156
130
|
def _get_labware_definition_from_bundle(
|
|
@@ -219,7 +193,6 @@ def _get_standard_labware_definition(
|
|
|
219
193
|
Definitions Folder from the Opentrons App before
|
|
220
194
|
uploading your protocol.
|
|
221
195
|
"""
|
|
222
|
-
|
|
223
196
|
if namespace is None:
|
|
224
197
|
for fallback_namespace in [OPENTRONS_NAMESPACE, CUSTOM_NAMESPACE]:
|
|
225
198
|
try:
|
|
@@ -244,8 +217,7 @@ def _get_standard_labware_definition(
|
|
|
244
217
|
f'Labware "{load_name}" not found with version {checked_version} '
|
|
245
218
|
f'in namespace "{namespace}".'
|
|
246
219
|
)
|
|
247
|
-
|
|
248
|
-
return labware_def
|
|
220
|
+
return labware_def # type: ignore[no-any-return]
|
|
249
221
|
|
|
250
222
|
|
|
251
223
|
def _get_path_to_labware(
|
|
@@ -253,9 +225,21 @@ def _get_path_to_labware(
|
|
|
253
225
|
) -> Path:
|
|
254
226
|
if namespace == OPENTRONS_NAMESPACE:
|
|
255
227
|
# all labware in OPENTRONS_NAMESPACE is stored in shared data
|
|
256
|
-
|
|
257
|
-
get_shared_data_root()
|
|
228
|
+
schema_3_path = (
|
|
229
|
+
get_shared_data_root()
|
|
230
|
+
/ STANDARD_DEFS_PATH
|
|
231
|
+
/ "3"
|
|
232
|
+
/ load_name
|
|
233
|
+
/ f"{version}.json"
|
|
234
|
+
)
|
|
235
|
+
schema_2_path = (
|
|
236
|
+
get_shared_data_root()
|
|
237
|
+
/ STANDARD_DEFS_PATH
|
|
238
|
+
/ "2"
|
|
239
|
+
/ load_name
|
|
240
|
+
/ f"{version}.json"
|
|
258
241
|
)
|
|
242
|
+
return schema_3_path if schema_3_path.exists() else schema_2_path
|
|
259
243
|
if not base_path:
|
|
260
244
|
base_path = USER_DEFS_PATH
|
|
261
245
|
def_path = base_path / namespace / load_name / f"{version}.json"
|
opentrons/simulate.py
CHANGED
|
@@ -815,6 +815,7 @@ def _create_live_context_pe(
|
|
|
815
815
|
robot_type, use_pe_virtual_hardware=use_pe_virtual_hardware
|
|
816
816
|
),
|
|
817
817
|
deck_configuration=None,
|
|
818
|
+
file_provider=None,
|
|
818
819
|
error_recovery_policy=error_recovery_policy.never_recover,
|
|
819
820
|
drop_tips_after_run=False,
|
|
820
821
|
post_run_hardware_state=PostRunHardwareState.STAY_ENGAGED_IN_PLACE,
|
|
@@ -883,8 +884,6 @@ def _run_file_non_pe(
|
|
|
883
884
|
context.home()
|
|
884
885
|
with scraper.scrape():
|
|
885
886
|
try:
|
|
886
|
-
# TODO (spp, 2024-03-18): use true run-time param overrides once enabled
|
|
887
|
-
# for cli protocol simulation/ execution
|
|
888
887
|
execute.run_protocol(
|
|
889
888
|
protocol, context, run_time_parameters_with_overrides=None
|
|
890
889
|
)
|
|
@@ -914,6 +913,7 @@ def _run_file_pe(
|
|
|
914
913
|
log_level: str,
|
|
915
914
|
) -> _SimulateResult:
|
|
916
915
|
"""Run a protocol file with Protocol Engine."""
|
|
916
|
+
# TODO (spp, 2024-03-18): use run-time param overrides once enabled for cli protocol simulation.
|
|
917
917
|
|
|
918
918
|
async def run(protocol_source: ProtocolSource) -> _SimulateResult:
|
|
919
919
|
hardware_api_wrapped = hardware_api.wrapped()
|
|
@@ -1014,7 +1014,7 @@ def main() -> int:
|
|
|
1014
1014
|
args = parser.parse_args()
|
|
1015
1015
|
|
|
1016
1016
|
# TODO(mm, 2022-12-01): Configure the DurationEstimator with the correct deck type.
|
|
1017
|
-
duration_estimator = DurationEstimator() if args.estimate_duration else None
|
|
1017
|
+
duration_estimator = DurationEstimator() if args.estimate_duration else None
|
|
1018
1018
|
|
|
1019
1019
|
try:
|
|
1020
1020
|
runlog, maybe_bundle = simulate(
|
opentrons/types.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import enum
|
|
3
3
|
from math import sqrt, isclose
|
|
4
|
-
from typing import TYPE_CHECKING, Any, NamedTuple, Iterator, Union, List
|
|
4
|
+
from typing import TYPE_CHECKING, Any, NamedTuple, Iterator, Union, List, Optional
|
|
5
5
|
|
|
6
6
|
from opentrons_shared_data.robot.types import RobotType
|
|
7
7
|
|
|
@@ -79,7 +79,9 @@ LocationLabware = Union[
|
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
class Location:
|
|
82
|
-
"""
|
|
82
|
+
"""Location(point: Point, labware: Union["Labware", "Well", str, "ModuleGeometry", LabwareLike, None, "ModuleContext"])
|
|
83
|
+
|
|
84
|
+
A location to target as a motion.
|
|
83
85
|
|
|
84
86
|
The location contains a :py:class:`.Point` (in
|
|
85
87
|
:ref:`protocol-api-deck-coords`) and possibly an associated
|
|
@@ -116,10 +118,13 @@ class Location:
|
|
|
116
118
|
None,
|
|
117
119
|
"ModuleContext",
|
|
118
120
|
],
|
|
121
|
+
*,
|
|
122
|
+
_ot_internal_is_meniscus: Optional[bool] = None,
|
|
119
123
|
):
|
|
120
124
|
self._point = point
|
|
121
125
|
self._given_labware = labware
|
|
122
126
|
self._labware = LabwareLike(labware)
|
|
127
|
+
self._is_meniscus = _ot_internal_is_meniscus
|
|
123
128
|
|
|
124
129
|
# todo(mm, 2021-10-01): Figure out how to get .point and .labware to show up
|
|
125
130
|
# in the rendered docs, and then update the class docstring to use cross-references.
|
|
@@ -132,6 +137,10 @@ class Location:
|
|
|
132
137
|
def labware(self) -> LabwareLike:
|
|
133
138
|
return self._labware
|
|
134
139
|
|
|
140
|
+
@property
|
|
141
|
+
def is_meniscus(self) -> Optional[bool]:
|
|
142
|
+
return self._is_meniscus
|
|
143
|
+
|
|
135
144
|
def __iter__(self) -> Iterator[Union[Point, LabwareLike]]:
|
|
136
145
|
"""Iterable interface to support unpacking. Like a tuple.
|
|
137
146
|
|
|
@@ -148,6 +157,7 @@ class Location:
|
|
|
148
157
|
isinstance(other, Location)
|
|
149
158
|
and other._point == self._point
|
|
150
159
|
and other._labware == self._labware
|
|
160
|
+
and other._is_meniscus == self._is_meniscus
|
|
151
161
|
)
|
|
152
162
|
|
|
153
163
|
def move(self, point: Point) -> "Location":
|
|
@@ -173,7 +183,7 @@ class Location:
|
|
|
173
183
|
return Location(point=self.point + point, labware=self._given_labware)
|
|
174
184
|
|
|
175
185
|
def __repr__(self) -> str:
|
|
176
|
-
return f"Location(point={repr(self._point)}, labware={self._labware})"
|
|
186
|
+
return f"Location(point={repr(self._point)}, labware={self._labware}, is_meniscus={self._is_meniscus if self._is_meniscus is not None else False})"
|
|
177
187
|
|
|
178
188
|
|
|
179
189
|
# TODO(mc, 2020-10-22): use MountType implementation for Mount
|
|
@@ -282,6 +292,23 @@ class DeckSlotName(enum.Enum):
|
|
|
282
292
|
str_val = str(value).upper()
|
|
283
293
|
return cls(str_val)
|
|
284
294
|
|
|
295
|
+
@classmethod
|
|
296
|
+
def ot3_slots(cls) -> List["DeckSlotName"]:
|
|
297
|
+
return [
|
|
298
|
+
DeckSlotName.SLOT_A1,
|
|
299
|
+
DeckSlotName.SLOT_A2,
|
|
300
|
+
DeckSlotName.SLOT_A3,
|
|
301
|
+
DeckSlotName.SLOT_B1,
|
|
302
|
+
DeckSlotName.SLOT_B2,
|
|
303
|
+
DeckSlotName.SLOT_B3,
|
|
304
|
+
DeckSlotName.SLOT_C1,
|
|
305
|
+
DeckSlotName.SLOT_C2,
|
|
306
|
+
DeckSlotName.SLOT_C3,
|
|
307
|
+
DeckSlotName.SLOT_D1,
|
|
308
|
+
DeckSlotName.SLOT_D2,
|
|
309
|
+
DeckSlotName.SLOT_D3,
|
|
310
|
+
]
|
|
311
|
+
|
|
285
312
|
# TODO(mm, 2023-05-08):
|
|
286
313
|
# Migrate callers off of this method. https://opentrons.atlassian.net/browse/RLAB-345
|
|
287
314
|
def as_int(self) -> int:
|