opentrons 8.4.0a2__py2.py3-none-any.whl → 8.4.0a4__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/legacy_commands/commands.py +83 -2
- opentrons/legacy_commands/helpers.py +59 -1
- opentrons/legacy_commands/types.py +30 -0
- opentrons/protocol_api/core/engine/instrument.py +158 -87
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +6 -14
- opentrons/protocol_api/core/engine/transfer_components_executor.py +12 -23
- opentrons/protocol_api/core/instrument.py +7 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +7 -30
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +7 -4
- opentrons/protocol_api/core/well.py +1 -1
- opentrons/protocol_api/instrument_context.py +189 -75
- opentrons/protocol_api/labware.py +7 -6
- opentrons/protocol_api/protocol_context.py +18 -16
- opentrons/protocol_engine/commands/__init__.py +38 -38
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +0 -6
- opentrons/protocol_engine/commands/command_unions.py +33 -33
- opentrons/protocol_engine/commands/dispense_while_tracking.py +1 -6
- opentrons/protocol_engine/commands/flex_stacker/empty.py +6 -6
- opentrons/protocol_engine/commands/flex_stacker/fill.py +6 -6
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +6 -6
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +9 -9
- opentrons/protocol_engine/commands/flex_stacker/store.py +16 -13
- opentrons/protocol_engine/commands/labware_handling_common.py +6 -1
- opentrons/protocol_engine/commands/liquid_probe.py +1 -2
- opentrons/protocol_engine/commands/move_to_well.py +5 -11
- opentrons/protocol_engine/commands/{evotip_dispense.py → pressure_dispense.py} +27 -27
- opentrons/protocol_engine/commands/{evotip_seal_pipette.py → seal_pipette_to_tip.py} +32 -27
- opentrons/protocol_engine/commands/{evotip_unseal_pipette.py → unseal_pipette_from_tip.py} +22 -22
- opentrons/protocol_engine/labware_offset_standardization.py +22 -1
- opentrons/protocol_engine/resources/deck_configuration_provider.py +8 -4
- opentrons/protocol_engine/state/frustum_helpers.py +12 -4
- opentrons/protocol_engine/state/geometry.py +122 -73
- opentrons/protocol_engine/state/update_types.py +1 -1
- opentrons/protocol_engine/state/wells.py +1 -1
- opentrons/protocol_engine/types/__init__.py +6 -0
- opentrons/protocol_engine/types/location.py +2 -1
- opentrons/protocol_engine/types/well_position.py +18 -1
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +1 -1
- opentrons/protocols/labware.py +23 -18
- {opentrons-8.4.0a2.dist-info → opentrons-8.4.0a4.dist-info}/METADATA +4 -4
- {opentrons-8.4.0a2.dist-info → opentrons-8.4.0a4.dist-info}/RECORD +45 -45
- {opentrons-8.4.0a2.dist-info → opentrons-8.4.0a4.dist-info}/LICENSE +0 -0
- {opentrons-8.4.0a2.dist-info → opentrons-8.4.0a4.dist-info}/WHEEL +0 -0
- {opentrons-8.4.0a2.dist-info → opentrons-8.4.0a4.dist-info}/entry_points.txt +0 -0
- {opentrons-8.4.0a2.dist-info → opentrons-8.4.0a4.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Pressure Dispense-in-place command request, result, and implementation models."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
from typing import TYPE_CHECKING, Optional, Type, Union
|
|
@@ -35,33 +35,33 @@ if TYPE_CHECKING:
|
|
|
35
35
|
from ..state.state import StateView
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
PressureDispenseCommandType = Literal["pressureDispense"]
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
class
|
|
41
|
+
class PressureDispenseParams(
|
|
42
42
|
PipetteIdMixin, DispenseVolumeMixin, FlowRateMixin, LiquidHandlingWellLocationMixin
|
|
43
43
|
):
|
|
44
|
-
"""Payload required to dispense in place."""
|
|
44
|
+
"""Payload required to pressure dispense in place."""
|
|
45
45
|
|
|
46
46
|
pass
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
class
|
|
50
|
-
"""Result data from the execution of a
|
|
49
|
+
class PressureDispenseResult(BaseLiquidHandlingResult):
|
|
50
|
+
"""Result data from the execution of a PressureDispense command."""
|
|
51
51
|
|
|
52
52
|
pass
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
_ExecuteReturn = Union[
|
|
56
|
-
SuccessData[
|
|
56
|
+
SuccessData[PressureDispenseResult],
|
|
57
57
|
DefinedErrorData[StallOrCollisionError],
|
|
58
58
|
]
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
class
|
|
62
|
-
AbstractCommandImpl[
|
|
61
|
+
class PressureDispenseImplementation(
|
|
62
|
+
AbstractCommandImpl[PressureDispenseParams, _ExecuteReturn]
|
|
63
63
|
):
|
|
64
|
-
"""
|
|
64
|
+
"""Pressure dispense command implementation."""
|
|
65
65
|
|
|
66
66
|
def __init__(
|
|
67
67
|
self,
|
|
@@ -78,8 +78,8 @@ class EvotipDispenseImplementation(
|
|
|
78
78
|
self._model_utils = model_utils
|
|
79
79
|
self._movement = movement
|
|
80
80
|
|
|
81
|
-
async def execute(self, params:
|
|
82
|
-
"""Move to and dispense to the requested well."""
|
|
81
|
+
async def execute(self, params: PressureDispenseParams) -> _ExecuteReturn:
|
|
82
|
+
"""Move to and pressure dispense to the requested well."""
|
|
83
83
|
well_location = params.wellLocation
|
|
84
84
|
labware_id = params.labwareId
|
|
85
85
|
well_name = params.wellName
|
|
@@ -121,35 +121,35 @@ class EvotipDispenseImplementation(
|
|
|
121
121
|
message="Overpressure Error during Resin Tip Dispense Command."
|
|
122
122
|
)
|
|
123
123
|
return SuccessData(
|
|
124
|
-
public=
|
|
124
|
+
public=PressureDispenseResult(volume=result.public.volume),
|
|
125
125
|
state_update=StateUpdate.reduce(
|
|
126
126
|
move_result.state_update, result.state_update
|
|
127
127
|
),
|
|
128
128
|
)
|
|
129
129
|
|
|
130
130
|
|
|
131
|
-
class
|
|
131
|
+
class PressureDispense(
|
|
132
132
|
BaseCommand[
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
PressureDispenseParams,
|
|
134
|
+
PressureDispenseResult,
|
|
135
135
|
StallOrCollisionError,
|
|
136
136
|
]
|
|
137
137
|
):
|
|
138
|
-
"""
|
|
138
|
+
"""PressureDispense command model."""
|
|
139
139
|
|
|
140
|
-
commandType:
|
|
141
|
-
params:
|
|
142
|
-
result: Optional[
|
|
140
|
+
commandType: PressureDispenseCommandType = "pressureDispense"
|
|
141
|
+
params: PressureDispenseParams
|
|
142
|
+
result: Optional[PressureDispenseResult] = None
|
|
143
143
|
|
|
144
144
|
_ImplementationCls: Type[
|
|
145
|
-
|
|
146
|
-
] =
|
|
145
|
+
PressureDispenseImplementation
|
|
146
|
+
] = PressureDispenseImplementation
|
|
147
147
|
|
|
148
148
|
|
|
149
|
-
class
|
|
150
|
-
"""
|
|
149
|
+
class PressureDispenseCreate(BaseCommandCreate[PressureDispenseParams]):
|
|
150
|
+
"""PressureDispense command request model."""
|
|
151
151
|
|
|
152
|
-
commandType:
|
|
153
|
-
params:
|
|
152
|
+
commandType: PressureDispenseCommandType = "pressureDispense"
|
|
153
|
+
params: PressureDispenseParams
|
|
154
154
|
|
|
155
|
-
_CommandCls: Type[
|
|
155
|
+
_CommandCls: Type[PressureDispense] = PressureDispense
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Seal
|
|
1
|
+
"""Seal tips to pipette command request, result, and implementation models."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
from pydantic import Field, BaseModel
|
|
@@ -7,7 +7,7 @@ from opentrons.types import MountType
|
|
|
7
7
|
from opentrons.protocol_engine.types import MotorAxis
|
|
8
8
|
from typing_extensions import Literal
|
|
9
9
|
|
|
10
|
-
from ..resources import ModelUtils
|
|
10
|
+
from ..resources import ModelUtils, ensure_ot3_hardware
|
|
11
11
|
from ..types import PickUpTipWellLocation, FluidKind, AspiratedFluid
|
|
12
12
|
from .pipetting_common import (
|
|
13
13
|
PipetteIdMixin,
|
|
@@ -39,7 +39,7 @@ if TYPE_CHECKING:
|
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
SealPipetteToTipCommandType = Literal["sealPipetteToTip"]
|
|
43
43
|
_CAM_PREP_DISTANCE_DEFAULT = 8.25
|
|
44
44
|
_CAM_PRESS_DISTANCE_DEFAULT = 3.5
|
|
45
45
|
_CAM_EJECTOR_PUSH_MM_DEFAULT = 7.0
|
|
@@ -64,7 +64,7 @@ class TipPickUpParams(BaseModel):
|
|
|
64
64
|
)
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
class
|
|
67
|
+
class SealPipetteToTipParams(PipetteIdMixin):
|
|
68
68
|
"""Payload needed to seal resin tips to a pipette."""
|
|
69
69
|
|
|
70
70
|
labwareId: str = Field(..., description="Identifier of labware to use.")
|
|
@@ -78,8 +78,8 @@ class EvotipSealPipetteParams(PipetteIdMixin):
|
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
class
|
|
82
|
-
"""Result data from the execution of a
|
|
81
|
+
class SealPipetteToTipResult(DestinationPositionResult):
|
|
82
|
+
"""Result data from the execution of a SealPipetteToTip."""
|
|
83
83
|
|
|
84
84
|
tipVolume: float = Field(
|
|
85
85
|
0,
|
|
@@ -101,15 +101,15 @@ class EvotipSealPipetteResult(DestinationPositionResult):
|
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
_ExecuteReturn = Union[
|
|
104
|
-
SuccessData[
|
|
104
|
+
SuccessData[SealPipetteToTipResult],
|
|
105
105
|
DefinedErrorData[StallOrCollisionError],
|
|
106
106
|
]
|
|
107
107
|
|
|
108
108
|
|
|
109
|
-
class
|
|
110
|
-
AbstractCommandImpl[
|
|
109
|
+
class SealPipetteToTipImplementation(
|
|
110
|
+
AbstractCommandImpl[SealPipetteToTipParams, _ExecuteReturn]
|
|
111
111
|
):
|
|
112
|
-
"""
|
|
112
|
+
"""Seal pipette command implementation."""
|
|
113
113
|
|
|
114
114
|
def __init__(
|
|
115
115
|
self,
|
|
@@ -159,6 +159,11 @@ class EvotipSealPipetteImplementation(
|
|
|
159
159
|
axis_map={mount_axis: retract_distance}, speed=5.5, relative_move=True
|
|
160
160
|
)
|
|
161
161
|
|
|
162
|
+
ot3_hardware_api = ensure_ot3_hardware(self._hardware_api)
|
|
163
|
+
await ot3_hardware_api.update_axis_position_estimations(
|
|
164
|
+
self._gantry_mover.motor_axes_to_present_hardware_axes([mount_axis])
|
|
165
|
+
)
|
|
166
|
+
|
|
162
167
|
async def cam_action_relative_pickup_tip(
|
|
163
168
|
self,
|
|
164
169
|
tip_pick_up_params: TipPickUpParams,
|
|
@@ -212,8 +217,8 @@ class EvotipSealPipetteImplementation(
|
|
|
212
217
|
)
|
|
213
218
|
|
|
214
219
|
async def execute(
|
|
215
|
-
self, params:
|
|
216
|
-
) -> Union[SuccessData[
|
|
220
|
+
self, params: SealPipetteToTipParams
|
|
221
|
+
) -> Union[SuccessData[SealPipetteToTipResult], _ExecuteReturn]:
|
|
217
222
|
"""Move to and pick up a tip using the requested pipette."""
|
|
218
223
|
pipette_id = params.pipetteId
|
|
219
224
|
labware_id = params.labwareId
|
|
@@ -289,7 +294,7 @@ class EvotipSealPipetteImplementation(
|
|
|
289
294
|
fluid=AspiratedFluid(kind=FluidKind.LIQUID, volume=_SAFE_TOP_VOLUME),
|
|
290
295
|
)
|
|
291
296
|
return SuccessData(
|
|
292
|
-
public=
|
|
297
|
+
public=SealPipetteToTipResult(
|
|
293
298
|
tipVolume=tip_geometry.volume,
|
|
294
299
|
tipLength=tip_geometry.length,
|
|
295
300
|
tipDiameter=tip_geometry.diameter,
|
|
@@ -299,28 +304,28 @@ class EvotipSealPipetteImplementation(
|
|
|
299
304
|
)
|
|
300
305
|
|
|
301
306
|
|
|
302
|
-
class
|
|
307
|
+
class SealPipetteToTip(
|
|
303
308
|
BaseCommand[
|
|
304
|
-
|
|
305
|
-
|
|
309
|
+
SealPipetteToTipParams,
|
|
310
|
+
SealPipetteToTipResult,
|
|
306
311
|
StallOrCollisionError,
|
|
307
312
|
]
|
|
308
313
|
):
|
|
309
|
-
"""Seal
|
|
314
|
+
"""Seal tip command model."""
|
|
310
315
|
|
|
311
|
-
commandType:
|
|
312
|
-
params:
|
|
313
|
-
result: Optional[
|
|
316
|
+
commandType: SealPipetteToTipCommandType = "sealPipetteToTip"
|
|
317
|
+
params: SealPipetteToTipParams
|
|
318
|
+
result: Optional[SealPipetteToTipResult] = None
|
|
314
319
|
|
|
315
320
|
_ImplementationCls: Type[
|
|
316
|
-
|
|
317
|
-
] =
|
|
321
|
+
SealPipetteToTipImplementation
|
|
322
|
+
] = SealPipetteToTipImplementation
|
|
318
323
|
|
|
319
324
|
|
|
320
|
-
class
|
|
321
|
-
"""Seal
|
|
325
|
+
class SealPipetteToTipCreate(BaseCommandCreate[SealPipetteToTipParams]):
|
|
326
|
+
"""Seal tip command creation request model."""
|
|
322
327
|
|
|
323
|
-
commandType:
|
|
324
|
-
params:
|
|
328
|
+
commandType: SealPipetteToTipCommandType = "sealPipetteToTip"
|
|
329
|
+
params: SealPipetteToTipParams
|
|
325
330
|
|
|
326
|
-
_CommandCls: Type[
|
|
331
|
+
_CommandCls: Type[SealPipetteToTip] = SealPipetteToTip
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Unseal
|
|
1
|
+
"""Unseal tip from pipette command request, result, and implementation models."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -32,10 +32,10 @@ if TYPE_CHECKING:
|
|
|
32
32
|
from ..execution import MovementHandler, TipHandler, GantryMover
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
UnsealPipetteFromTipCommandType = Literal["unsealPipetteFromTip"]
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
class
|
|
38
|
+
class UnsealPipetteFromTipParams(PipetteIdMixin):
|
|
39
39
|
"""Payload required to drop a tip in a specific well."""
|
|
40
40
|
|
|
41
41
|
labwareId: str = Field(..., description="Identifier of labware to use.")
|
|
@@ -46,19 +46,19 @@ class EvotipUnsealPipetteParams(PipetteIdMixin):
|
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
class
|
|
49
|
+
class UnsealPipetteFromTipResult(DestinationPositionResult):
|
|
50
50
|
"""Result data from the execution of a DropTip command."""
|
|
51
51
|
|
|
52
52
|
pass
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
_ExecuteReturn = (
|
|
56
|
-
SuccessData[
|
|
56
|
+
SuccessData[UnsealPipetteFromTipResult] | DefinedErrorData[StallOrCollisionError]
|
|
57
57
|
)
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
class
|
|
61
|
-
AbstractCommandImpl[
|
|
60
|
+
class UnsealPipetteFromTipImplementation(
|
|
61
|
+
AbstractCommandImpl[UnsealPipetteFromTipParams, _ExecuteReturn]
|
|
62
62
|
):
|
|
63
63
|
"""Drop tip command implementation."""
|
|
64
64
|
|
|
@@ -77,7 +77,7 @@ class EvotipUnsealPipetteImplementation(
|
|
|
77
77
|
self._model_utils = model_utils
|
|
78
78
|
self._gantry_mover = gantry_mover
|
|
79
79
|
|
|
80
|
-
async def execute(self, params:
|
|
80
|
+
async def execute(self, params: UnsealPipetteFromTipParams) -> _ExecuteReturn:
|
|
81
81
|
"""Move to and drop a tip using the requested pipette."""
|
|
82
82
|
pipette_id = params.pipetteId
|
|
83
83
|
labware_id = params.labwareId
|
|
@@ -122,33 +122,33 @@ class EvotipUnsealPipetteImplementation(
|
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
return SuccessData(
|
|
125
|
-
public=
|
|
125
|
+
public=UnsealPipetteFromTipResult(position=move_result.public.position),
|
|
126
126
|
state_update=move_result.state_update.set_fluid_unknown(
|
|
127
127
|
pipette_id=pipette_id
|
|
128
128
|
).update_pipette_tip_state(pipette_id=params.pipetteId, tip_geometry=None),
|
|
129
129
|
)
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
class
|
|
132
|
+
class UnsealPipetteFromTip(
|
|
133
133
|
BaseCommand[
|
|
134
|
-
|
|
134
|
+
UnsealPipetteFromTipParams, UnsealPipetteFromTipResult, StallOrCollisionError
|
|
135
135
|
]
|
|
136
136
|
):
|
|
137
|
-
"""
|
|
137
|
+
"""Unseal pipette command model."""
|
|
138
138
|
|
|
139
|
-
commandType:
|
|
140
|
-
params:
|
|
141
|
-
result: Optional[
|
|
139
|
+
commandType: UnsealPipetteFromTipCommandType = "unsealPipetteFromTip"
|
|
140
|
+
params: UnsealPipetteFromTipParams
|
|
141
|
+
result: Optional[UnsealPipetteFromTipResult] = None
|
|
142
142
|
|
|
143
143
|
_ImplementationCls: Type[
|
|
144
|
-
|
|
145
|
-
] =
|
|
144
|
+
UnsealPipetteFromTipImplementation
|
|
145
|
+
] = UnsealPipetteFromTipImplementation
|
|
146
146
|
|
|
147
147
|
|
|
148
|
-
class
|
|
149
|
-
"""
|
|
148
|
+
class UnsealPipetteFromTipCreate(BaseCommandCreate[UnsealPipetteFromTipParams]):
|
|
149
|
+
"""Unseal pipette command creation request model."""
|
|
150
150
|
|
|
151
|
-
commandType:
|
|
152
|
-
params:
|
|
151
|
+
commandType: UnsealPipetteFromTipCommandType = "unsealPipetteFromTip"
|
|
152
|
+
params: UnsealPipetteFromTipParams
|
|
153
153
|
|
|
154
|
-
_CommandCls: Type[
|
|
154
|
+
_CommandCls: Type[UnsealPipetteFromTip] = UnsealPipetteFromTip
|
|
@@ -53,7 +53,28 @@ def legacy_offset_location_to_offset_location_sequence(
|
|
|
53
53
|
cutout_id = deck_configuration_provider.get_cutout_id_by_deck_slot_name(
|
|
54
54
|
location.slotName
|
|
55
55
|
)
|
|
56
|
-
|
|
56
|
+
|
|
57
|
+
# Given a module model, try to figure out the equivalent cutout fixture.
|
|
58
|
+
#
|
|
59
|
+
# The Thermocycler is special. A single Thermocycler is represented in a deck
|
|
60
|
+
# configuration as two separate cutout fixtures, because it spans two separate
|
|
61
|
+
# cutouts. This makes it the only module whose module model string does not map
|
|
62
|
+
# 1:1 with a cutout fixture ID string.
|
|
63
|
+
#
|
|
64
|
+
# TODO(mm, 2025-04-11): This is fragile, and the failure mode when it does the
|
|
65
|
+
# wrong thing can mean labware offsets don't apply, which is pretty bad. We
|
|
66
|
+
# either need a more explicit module<->cutout-fixture mapping, or we need to
|
|
67
|
+
# avoid this mapping entirely.
|
|
68
|
+
if (
|
|
69
|
+
# Check for v2 specifically because v1 is OT-2-only and OT-2s don't have
|
|
70
|
+
# modules in their deck definitions; and v3 does not exist at the time of writing.
|
|
71
|
+
location.moduleModel
|
|
72
|
+
== ModuleModel.THERMOCYCLER_MODULE_V2
|
|
73
|
+
):
|
|
74
|
+
possible_cutout_fixture_id = "thermocyclerModuleV2Front"
|
|
75
|
+
else:
|
|
76
|
+
possible_cutout_fixture_id = location.moduleModel.value
|
|
77
|
+
|
|
57
78
|
try:
|
|
58
79
|
addressable_area = deck_configuration_provider.get_labware_hosting_addressable_area_name_for_cutout_and_cutout_fixture(
|
|
59
80
|
cutout_id, possible_cutout_fixture_id, deck_definition
|
|
@@ -144,16 +144,20 @@ def get_deck_slot_for_cutout_id(cutout_id: str) -> DeckSlotName:
|
|
|
144
144
|
"""Get the corresponding deck slot for an addressable area."""
|
|
145
145
|
try:
|
|
146
146
|
return CUTOUT_TO_DECK_SLOT_MAP[cutout_id]
|
|
147
|
-
except KeyError:
|
|
148
|
-
raise CutoutDoesNotExistError(
|
|
147
|
+
except KeyError as e:
|
|
148
|
+
raise CutoutDoesNotExistError(
|
|
149
|
+
f"Could not find data for cutout {cutout_id}"
|
|
150
|
+
) from e
|
|
149
151
|
|
|
150
152
|
|
|
151
153
|
def get_cutout_id_by_deck_slot_name(slot_name: DeckSlotName) -> str:
|
|
152
154
|
"""Get the Cutout ID of a given Deck Slot by Deck Slot Name."""
|
|
153
155
|
try:
|
|
154
156
|
return DECK_SLOT_TO_CUTOUT_MAP[slot_name]
|
|
155
|
-
except KeyError:
|
|
156
|
-
raise SlotDoesNotExistError(
|
|
157
|
+
except KeyError as e:
|
|
158
|
+
raise SlotDoesNotExistError(
|
|
159
|
+
f"Could not find data for slot {slot_name.value}"
|
|
160
|
+
) from e
|
|
157
161
|
|
|
158
162
|
|
|
159
163
|
def get_labware_hosting_addressable_area_name_for_cutout_and_cutout_fixture(
|
|
@@ -353,8 +353,9 @@ def _find_volume_in_partial_frustum(
|
|
|
353
353
|
section_height=section_height,
|
|
354
354
|
)
|
|
355
355
|
# if we've looked through all sections and can't find the target volume, raise an error
|
|
356
|
+
# this code should never be reached- an error should be raised by find_volume_at_well_height
|
|
356
357
|
raise InvalidLiquidHeightFound(
|
|
357
|
-
f"
|
|
358
|
+
f"Target height {target_height} mm exceeds the well height."
|
|
358
359
|
)
|
|
359
360
|
|
|
360
361
|
|
|
@@ -369,7 +370,9 @@ def find_volume_at_well_height(
|
|
|
369
370
|
volumetric_capacity = get_well_volumetric_capacity(well_geometry)
|
|
370
371
|
max_height = volumetric_capacity[-1][0]
|
|
371
372
|
if target_height < 0 or target_height > max_height:
|
|
372
|
-
raise InvalidLiquidHeightFound(
|
|
373
|
+
raise InvalidLiquidHeightFound(
|
|
374
|
+
"Invalid target height {target_height} mm; max well height is {max_height} mm."
|
|
375
|
+
)
|
|
373
376
|
# volumes in volumetric_capacity are relative to each frustum,
|
|
374
377
|
# so we have to find the volume of all the full sections enclosed
|
|
375
378
|
# beneath the target height
|
|
@@ -417,9 +420,12 @@ def _find_height_in_partial_frustum(
|
|
|
417
420
|
# viewed section
|
|
418
421
|
bottom_section_volume += section_volume
|
|
419
422
|
|
|
423
|
+
# if we finish looping through the whole well, bottom_section will be the well's volume
|
|
424
|
+
total_well_volume = bottom_section_volume
|
|
420
425
|
# if we've looked through all sections and can't find the target volume, raise an error
|
|
426
|
+
# also this code should never be reached bc an error should be raised by find_height_at_well_volume
|
|
421
427
|
raise InvalidLiquidHeightFound(
|
|
422
|
-
f"
|
|
428
|
+
f"Target volume {target_volume} uL exceeds the well volume {total_well_volume} uL."
|
|
423
429
|
)
|
|
424
430
|
|
|
425
431
|
|
|
@@ -439,7 +445,9 @@ def find_height_at_well_volume(
|
|
|
439
445
|
|
|
440
446
|
if raise_error_if_result_invalid:
|
|
441
447
|
if target_volume < 0 or target_volume > max_volume:
|
|
442
|
-
raise InvalidLiquidHeightFound(
|
|
448
|
+
raise InvalidLiquidHeightFound(
|
|
449
|
+
f"Invalid target volume {target_volume} uL; max volume is {max_volume} uL"
|
|
450
|
+
)
|
|
443
451
|
|
|
444
452
|
sorted_well = sorted(well_geometry.sections, key=lambda section: section.topHeight)
|
|
445
453
|
# find the section the target volume is in and compute the height
|