opentrons 8.7.0a9__py3-none-any.whl → 8.8.0a7__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/_version.py +2 -2
- opentrons/cli/analyze.py +4 -1
- opentrons/config/__init__.py +7 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +126 -49
- opentrons/drivers/heater_shaker/abstract.py +5 -0
- opentrons/drivers/heater_shaker/driver.py +10 -0
- opentrons/drivers/heater_shaker/simulator.py +4 -0
- opentrons/drivers/thermocycler/abstract.py +6 -0
- opentrons/drivers/thermocycler/driver.py +61 -10
- opentrons/drivers/thermocycler/simulator.py +6 -0
- opentrons/drivers/vacuum_module/__init__.py +5 -0
- opentrons/drivers/vacuum_module/abstract.py +93 -0
- opentrons/drivers/vacuum_module/driver.py +208 -0
- opentrons/drivers/vacuum_module/errors.py +39 -0
- opentrons/drivers/vacuum_module/simulator.py +85 -0
- opentrons/drivers/vacuum_module/types.py +79 -0
- opentrons/execute.py +3 -0
- opentrons/hardware_control/api.py +24 -5
- opentrons/hardware_control/backends/controller.py +8 -2
- opentrons/hardware_control/backends/flex_protocol.py +1 -0
- opentrons/hardware_control/backends/ot3controller.py +35 -2
- opentrons/hardware_control/backends/ot3simulator.py +3 -1
- opentrons/hardware_control/backends/ot3utils.py +37 -0
- opentrons/hardware_control/backends/simulator.py +2 -1
- opentrons/hardware_control/backends/subsystem_manager.py +5 -2
- opentrons/hardware_control/emulation/abstract_emulator.py +6 -4
- opentrons/hardware_control/emulation/connection_handler.py +8 -5
- opentrons/hardware_control/emulation/heater_shaker.py +12 -3
- opentrons/hardware_control/emulation/settings.py +1 -1
- opentrons/hardware_control/emulation/thermocycler.py +67 -15
- opentrons/hardware_control/module_control.py +105 -10
- opentrons/hardware_control/modules/__init__.py +3 -0
- opentrons/hardware_control/modules/absorbance_reader.py +11 -4
- opentrons/hardware_control/modules/flex_stacker.py +38 -9
- opentrons/hardware_control/modules/heater_shaker.py +42 -5
- opentrons/hardware_control/modules/magdeck.py +8 -4
- opentrons/hardware_control/modules/mod_abc.py +14 -6
- opentrons/hardware_control/modules/tempdeck.py +25 -5
- opentrons/hardware_control/modules/thermocycler.py +68 -11
- opentrons/hardware_control/modules/types.py +20 -1
- opentrons/hardware_control/modules/utils.py +11 -4
- opentrons/hardware_control/motion_utilities.py +6 -6
- opentrons/hardware_control/nozzle_manager.py +3 -0
- opentrons/hardware_control/ot3api.py +85 -17
- opentrons/hardware_control/poller.py +22 -8
- opentrons/hardware_control/protocols/liquid_handler.py +6 -2
- opentrons/hardware_control/scripts/update_module_fw.py +5 -0
- opentrons/hardware_control/types.py +43 -2
- opentrons/legacy_commands/commands.py +58 -5
- opentrons/legacy_commands/module_commands.py +52 -0
- opentrons/legacy_commands/protocol_commands.py +53 -1
- opentrons/legacy_commands/types.py +155 -1
- opentrons/motion_planning/deck_conflict.py +17 -12
- opentrons/motion_planning/waypoints.py +15 -29
- opentrons/protocol_api/__init__.py +5 -1
- opentrons/protocol_api/_transfer_liquid_validation.py +17 -2
- opentrons/protocol_api/_types.py +8 -1
- opentrons/protocol_api/core/common.py +3 -1
- opentrons/protocol_api/core/engine/_default_labware_versions.py +33 -11
- opentrons/protocol_api/core/engine/deck_conflict.py +3 -1
- opentrons/protocol_api/core/engine/instrument.py +109 -26
- opentrons/protocol_api/core/engine/labware.py +8 -1
- opentrons/protocol_api/core/engine/module_core.py +95 -4
- opentrons/protocol_api/core/engine/protocol.py +51 -2
- opentrons/protocol_api/core/engine/stringify.py +2 -0
- opentrons/protocol_api/core/engine/tasks.py +48 -0
- opentrons/protocol_api/core/engine/well.py +8 -0
- opentrons/protocol_api/core/instrument.py +19 -2
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +19 -2
- opentrons/protocol_api/core/legacy/legacy_module_core.py +33 -2
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +23 -1
- opentrons/protocol_api/core/legacy/legacy_well_core.py +4 -0
- opentrons/protocol_api/core/legacy/tasks.py +19 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +19 -2
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +14 -2
- opentrons/protocol_api/core/legacy_simulator/tasks.py +19 -0
- opentrons/protocol_api/core/module.py +58 -2
- opentrons/protocol_api/core/protocol.py +23 -2
- opentrons/protocol_api/core/tasks.py +31 -0
- opentrons/protocol_api/core/well.py +4 -0
- opentrons/protocol_api/instrument_context.py +388 -2
- opentrons/protocol_api/labware.py +10 -2
- opentrons/protocol_api/module_contexts.py +170 -6
- opentrons/protocol_api/protocol_context.py +87 -21
- opentrons/protocol_api/robot_context.py +41 -25
- opentrons/protocol_api/tasks.py +48 -0
- opentrons/protocol_api/validation.py +49 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/__init__.py +6 -2
- opentrons/protocol_engine/actions/actions.py +31 -9
- opentrons/protocol_engine/clients/sync_client.py +42 -7
- opentrons/protocol_engine/commands/__init__.py +56 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +2 -15
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +2 -15
- opentrons/protocol_engine/commands/absorbance_reader/read.py +22 -23
- opentrons/protocol_engine/commands/aspirate.py +1 -0
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +52 -19
- opentrons/protocol_engine/commands/capture_image.py +302 -0
- opentrons/protocol_engine/commands/command.py +2 -0
- opentrons/protocol_engine/commands/command_unions.py +62 -0
- opentrons/protocol_engine/commands/create_timer.py +83 -0
- opentrons/protocol_engine/commands/dispense.py +1 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +56 -19
- opentrons/protocol_engine/commands/drop_tip.py +32 -8
- opentrons/protocol_engine/commands/flex_stacker/common.py +35 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +7 -0
- opentrons/protocol_engine/commands/heater_shaker/__init__.py +14 -0
- opentrons/protocol_engine/commands/heater_shaker/common.py +20 -0
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +5 -4
- opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +136 -0
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +31 -5
- opentrons/protocol_engine/commands/move_labware.py +3 -4
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +1 -1
- opentrons/protocol_engine/commands/movement_common.py +31 -2
- opentrons/protocol_engine/commands/pick_up_tip.py +21 -11
- opentrons/protocol_engine/commands/pipetting_common.py +48 -3
- opentrons/protocol_engine/commands/set_tip_state.py +97 -0
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +38 -7
- opentrons/protocol_engine/commands/thermocycler/__init__.py +16 -0
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +6 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +8 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +44 -7
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +43 -14
- opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +191 -0
- opentrons/protocol_engine/commands/touch_tip.py +1 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +6 -22
- opentrons/protocol_engine/commands/wait_for_tasks.py +98 -0
- opentrons/protocol_engine/create_protocol_engine.py +12 -0
- opentrons/protocol_engine/engine_support.py +3 -0
- opentrons/protocol_engine/errors/__init__.py +12 -0
- opentrons/protocol_engine/errors/exceptions.py +119 -0
- opentrons/protocol_engine/execution/__init__.py +4 -0
- opentrons/protocol_engine/execution/command_executor.py +62 -1
- opentrons/protocol_engine/execution/create_queue_worker.py +9 -2
- opentrons/protocol_engine/execution/labware_movement.py +13 -15
- opentrons/protocol_engine/execution/movement.py +2 -0
- opentrons/protocol_engine/execution/pipetting.py +19 -25
- opentrons/protocol_engine/execution/queue_worker.py +4 -0
- opentrons/protocol_engine/execution/run_control.py +8 -0
- opentrons/protocol_engine/execution/task_handler.py +157 -0
- opentrons/protocol_engine/protocol_engine.py +137 -36
- opentrons/protocol_engine/resources/__init__.py +4 -0
- opentrons/protocol_engine/resources/camera_provider.py +110 -0
- opentrons/protocol_engine/resources/concurrency_provider.py +27 -0
- opentrons/protocol_engine/resources/deck_configuration_provider.py +7 -0
- opentrons/protocol_engine/resources/file_provider.py +133 -58
- opentrons/protocol_engine/resources/labware_validation.py +10 -6
- opentrons/protocol_engine/slot_standardization.py +2 -0
- opentrons/protocol_engine/state/_well_math.py +60 -18
- opentrons/protocol_engine/state/addressable_areas.py +2 -0
- opentrons/protocol_engine/state/camera.py +54 -0
- opentrons/protocol_engine/state/commands.py +37 -14
- opentrons/protocol_engine/state/geometry.py +276 -379
- opentrons/protocol_engine/state/labware.py +62 -108
- opentrons/protocol_engine/state/labware_origin_math/errors.py +94 -0
- opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +1336 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +37 -0
- opentrons/protocol_engine/state/modules.py +30 -8
- opentrons/protocol_engine/state/motion.py +44 -0
- opentrons/protocol_engine/state/preconditions.py +59 -0
- opentrons/protocol_engine/state/state.py +44 -0
- opentrons/protocol_engine/state/state_summary.py +4 -0
- opentrons/protocol_engine/state/tasks.py +139 -0
- opentrons/protocol_engine/state/tips.py +177 -258
- opentrons/protocol_engine/state/update_types.py +26 -9
- opentrons/protocol_engine/types/__init__.py +23 -4
- opentrons/protocol_engine/types/command_preconditions.py +18 -0
- opentrons/protocol_engine/types/deck_configuration.py +5 -1
- opentrons/protocol_engine/types/instrument.py +8 -1
- opentrons/protocol_engine/types/labware.py +1 -13
- opentrons/protocol_engine/types/location.py +26 -2
- opentrons/protocol_engine/types/module.py +11 -1
- opentrons/protocol_engine/types/tasks.py +38 -0
- opentrons/protocol_engine/types/tip.py +9 -0
- opentrons/protocol_runner/create_simulating_orchestrator.py +29 -2
- opentrons/protocol_runner/protocol_runner.py +14 -1
- opentrons/protocol_runner/run_orchestrator.py +49 -2
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +2 -2
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/types.py +2 -1
- opentrons/simulate.py +51 -15
- opentrons/system/camera.py +334 -4
- opentrons/system/ffmpeg.py +110 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a7.dist-info}/METADATA +4 -4
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a7.dist-info}/RECORD +188 -160
- opentrons/protocol_engine/state/_labware_origin_math.py +0 -636
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a7.dist-info}/WHEEL +0 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a7.dist-info}/entry_points.txt +0 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a7.dist-info}/licenses/LICENSE +0 -0
|
@@ -18,6 +18,7 @@ from opentrons.hardware_control.modules.types import (
|
|
|
18
18
|
SpeedStatus,
|
|
19
19
|
)
|
|
20
20
|
from .labware import LabwareCoreType, AbstractLabware
|
|
21
|
+
from .tasks import AbstractTaskCore
|
|
21
22
|
from opentrons.protocol_engine.types import ABSMeasureMode
|
|
22
23
|
from opentrons.types import DeckSlotName
|
|
23
24
|
|
|
@@ -59,7 +60,7 @@ class AbstractTemperatureModuleCore(
|
|
|
59
60
|
"""Get the module's unique hardware serial number."""
|
|
60
61
|
|
|
61
62
|
@abstractmethod
|
|
62
|
-
def set_target_temperature(self, celsius: float) ->
|
|
63
|
+
def set_target_temperature(self, celsius: float) -> AbstractTaskCore:
|
|
63
64
|
"""Set the Temperature Module's target temperature in °C."""
|
|
64
65
|
|
|
65
66
|
@abstractmethod
|
|
@@ -161,6 +162,7 @@ class AbstractThermocyclerCore(
|
|
|
161
162
|
def set_target_block_temperature(
|
|
162
163
|
self,
|
|
163
164
|
celsius: float,
|
|
165
|
+
ramp_rate: Optional[float],
|
|
164
166
|
hold_time_seconds: Optional[float] = None,
|
|
165
167
|
block_max_volume: Optional[float] = None,
|
|
166
168
|
) -> None:
|
|
@@ -178,6 +180,25 @@ class AbstractThermocyclerCore(
|
|
|
178
180
|
will default to 25µL/well.
|
|
179
181
|
"""
|
|
180
182
|
|
|
183
|
+
@abstractmethod
|
|
184
|
+
def start_set_target_block_temperature(
|
|
185
|
+
self,
|
|
186
|
+
celsius: float,
|
|
187
|
+
ramp_rate: Optional[float],
|
|
188
|
+
block_max_volume: Optional[float] = None,
|
|
189
|
+
) -> AbstractTaskCore:
|
|
190
|
+
"""Start setting the target temperature for the well block, in °C.
|
|
191
|
+
|
|
192
|
+
Note:
|
|
193
|
+
If ``hold_time_seconds`` is not specified, the Thermocycler
|
|
194
|
+
will proceed to the next command after ``temperature`` is reached.
|
|
195
|
+
Args:
|
|
196
|
+
celsius: The target temperature, in °C.
|
|
197
|
+
block_max_volume: The maximum volume of any individual well
|
|
198
|
+
of the loaded labware. If not supplied, the thermocycler
|
|
199
|
+
will default to 25µL/well.
|
|
200
|
+
"""
|
|
201
|
+
|
|
181
202
|
@abstractmethod
|
|
182
203
|
def wait_for_block_temperature(self) -> None:
|
|
183
204
|
"""Wait for target block temperature to be reached."""
|
|
@@ -186,6 +207,10 @@ class AbstractThermocyclerCore(
|
|
|
186
207
|
def set_target_lid_temperature(self, celsius: float) -> None:
|
|
187
208
|
"""Set the target temperature for the heated lid, in °C."""
|
|
188
209
|
|
|
210
|
+
@abstractmethod
|
|
211
|
+
def start_set_target_lid_temperature(self, celsius: float) -> AbstractTaskCore:
|
|
212
|
+
"""Start setting the target temperature for the heated lid, in °C."""
|
|
213
|
+
|
|
189
214
|
@abstractmethod
|
|
190
215
|
def wait_for_lid_temperature(self) -> None:
|
|
191
216
|
"""Wait for target lid temperature to be reached."""
|
|
@@ -217,6 +242,33 @@ class AbstractThermocyclerCore(
|
|
|
217
242
|
will default to 25µL/well.
|
|
218
243
|
"""
|
|
219
244
|
|
|
245
|
+
@abstractmethod
|
|
246
|
+
def start_execute_profile(
|
|
247
|
+
self,
|
|
248
|
+
steps: List[ThermocyclerStep],
|
|
249
|
+
repetitions: int,
|
|
250
|
+
block_max_volume: Optional[float] = None,
|
|
251
|
+
) -> AbstractTaskCore:
|
|
252
|
+
"""Start a Thermocycler Profile.
|
|
253
|
+
|
|
254
|
+
Profile defined as a cycle of ``steps`` to repeat for a given number of ``repetitions``
|
|
255
|
+
|
|
256
|
+
Note:
|
|
257
|
+
Unlike the :py:meth:`execute_profile`, once the profile has started
|
|
258
|
+
the protocol will immediately move on to the next command, rather than waiting
|
|
259
|
+
for it to finish.
|
|
260
|
+
Args:
|
|
261
|
+
steps: List of unique steps that make up a single cycle.
|
|
262
|
+
Each list item should be a dictionary that maps to
|
|
263
|
+
the parameters of the :py:meth:`set_block_temperature`
|
|
264
|
+
method with keys 'temperature', 'hold_time_seconds',
|
|
265
|
+
and 'hold_time_minutes'.
|
|
266
|
+
repetitions: The number of times to repeat the cycled steps.
|
|
267
|
+
block_max_volume: The maximum volume of any individual well
|
|
268
|
+
of the loaded labware. If not supplied, the thermocycler
|
|
269
|
+
will default to 25µL/well.
|
|
270
|
+
"""
|
|
271
|
+
|
|
220
272
|
@abstractmethod
|
|
221
273
|
def deactivate_lid(self) -> None:
|
|
222
274
|
"""Turn off the heated lid."""
|
|
@@ -294,7 +346,7 @@ class AbstractHeaterShakerCore(
|
|
|
294
346
|
"""Get the module's unique hardware serial number."""
|
|
295
347
|
|
|
296
348
|
@abstractmethod
|
|
297
|
-
def set_target_temperature(self, celsius: float) ->
|
|
349
|
+
def set_target_temperature(self, celsius: float) -> AbstractTaskCore:
|
|
298
350
|
"""Set the labware plate's target temperature in °C."""
|
|
299
351
|
|
|
300
352
|
@abstractmethod
|
|
@@ -305,6 +357,10 @@ class AbstractHeaterShakerCore(
|
|
|
305
357
|
def set_and_wait_for_shake_speed(self, rpm: int) -> None:
|
|
306
358
|
"""Set the shaker's target shake speed and wait for it to spin up."""
|
|
307
359
|
|
|
360
|
+
@abstractmethod
|
|
361
|
+
def set_shake_speed(self, rpm: int) -> AbstractTaskCore:
|
|
362
|
+
"""Set the shaker's target shake speed."""
|
|
363
|
+
|
|
308
364
|
@abstractmethod
|
|
309
365
|
def open_labware_latch(self) -> None:
|
|
310
366
|
"""Open the labware latch."""
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from abc import abstractmethod, ABC
|
|
6
|
-
from typing import Generic, List, Optional, Union, Tuple, Dict, TYPE_CHECKING
|
|
6
|
+
from typing import Generic, List, Optional, Union, Tuple, Dict, TYPE_CHECKING, Sequence
|
|
7
7
|
|
|
8
8
|
from opentrons_shared_data.deck.types import DeckDefinitionV5, SlotDefV3
|
|
9
9
|
from opentrons_shared_data.pipette.types import PipetteNameType
|
|
@@ -24,6 +24,7 @@ from opentrons.protocols.api_support.util import AxisMaxSpeeds
|
|
|
24
24
|
from .instrument import InstrumentCoreType
|
|
25
25
|
from .labware import LabwareCoreType, LabwareLoadParams
|
|
26
26
|
from .module import ModuleCoreType
|
|
27
|
+
from .tasks import TaskCoreType
|
|
27
28
|
from .._liquid import Liquid, LiquidClass
|
|
28
29
|
from .robot import AbstractRobot
|
|
29
30
|
from .._types import OffDeckType
|
|
@@ -34,7 +35,7 @@ if TYPE_CHECKING:
|
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
class AbstractProtocol(
|
|
37
|
-
ABC, Generic[InstrumentCoreType, LabwareCoreType, ModuleCoreType]
|
|
38
|
+
ABC, Generic[InstrumentCoreType, LabwareCoreType, ModuleCoreType, TaskCoreType]
|
|
38
39
|
):
|
|
39
40
|
@property
|
|
40
41
|
@abstractmethod
|
|
@@ -192,6 +193,14 @@ class AbstractProtocol(
|
|
|
192
193
|
def delay(self, seconds: float, msg: Optional[str]) -> None:
|
|
193
194
|
...
|
|
194
195
|
|
|
196
|
+
@abstractmethod
|
|
197
|
+
def wait_for_tasks(self, task_cores: Sequence[TaskCoreType]) -> None:
|
|
198
|
+
...
|
|
199
|
+
|
|
200
|
+
@abstractmethod
|
|
201
|
+
def create_timer(self, seconds: float) -> TaskCoreType:
|
|
202
|
+
...
|
|
203
|
+
|
|
195
204
|
@abstractmethod
|
|
196
205
|
def home(self) -> None:
|
|
197
206
|
...
|
|
@@ -306,6 +315,18 @@ class AbstractProtocol(
|
|
|
306
315
|
) -> Union[str, LabwareCoreType, ModuleCoreType, OffDeckType]:
|
|
307
316
|
"""Get labware parent location."""
|
|
308
317
|
|
|
318
|
+
@abstractmethod
|
|
319
|
+
def capture_image(
|
|
320
|
+
self,
|
|
321
|
+
filename: Optional[str] = None,
|
|
322
|
+
resolution: Optional[Tuple[int, int]] = None,
|
|
323
|
+
zoom: Optional[float] = None,
|
|
324
|
+
contrast: Optional[float] = None,
|
|
325
|
+
brightness: Optional[float] = None,
|
|
326
|
+
saturation: Optional[float] = None,
|
|
327
|
+
) -> None:
|
|
328
|
+
"Capture an image using a camera."
|
|
329
|
+
|
|
309
330
|
@abstractmethod
|
|
310
331
|
def load_robot(self) -> AbstractRobot:
|
|
311
332
|
"""Load a Robot Core context into a protocol"""
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from abc import abstractmethod, ABC
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import TypeVar
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AbstractTaskCore(ABC):
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def get_created_at_timestamp(self) -> datetime:
|
|
9
|
+
"""Get the createdAt timestamp of the task."""
|
|
10
|
+
...
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def is_done(self) -> bool:
|
|
14
|
+
"""Returns ``True`` if the task is done."""
|
|
15
|
+
...
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def is_started(self) -> bool:
|
|
19
|
+
"""Returns ``True`` if the task has started."""
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def get_finished_at_timestamp(self) -> datetime | None:
|
|
24
|
+
"""The timestamp of the when the task finished.
|
|
25
|
+
|
|
26
|
+
Returns ``None`` if the task hasn't finished yet.
|
|
27
|
+
"""
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
TaskCoreType = TypeVar("TaskCoreType", bound=AbstractTaskCore)
|
|
@@ -112,5 +112,9 @@ class AbstractWellCore(ABC):
|
|
|
112
112
|
def volume_from_height(self, height: LiquidTrackingType) -> LiquidTrackingType:
|
|
113
113
|
"""Return the volume contained in a well at any height."""
|
|
114
114
|
|
|
115
|
+
@abstractmethod
|
|
116
|
+
def has_tracked_liquid(self) -> bool:
|
|
117
|
+
"""Return true if liquid has been loaded or probed."""
|
|
118
|
+
|
|
115
119
|
|
|
116
120
|
WellCoreType = TypeVar("WellCoreType", bound=AbstractWellCore)
|