opentrons 8.3.0a0__py2.py3-none-any.whl → 8.3.0a1__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/calibration_storage/deck_configuration.py +3 -3
- opentrons/calibration_storage/file_operators.py +3 -3
- opentrons/calibration_storage/helpers.py +3 -1
- opentrons/calibration_storage/ot2/models/v1.py +16 -29
- opentrons/calibration_storage/ot2/tip_length.py +7 -4
- opentrons/calibration_storage/ot3/models/v1.py +14 -23
- opentrons/cli/analyze.py +18 -6
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/errors.py +16 -3
- opentrons/drivers/asyncio/communication/serial_connection.py +24 -9
- opentrons/drivers/command_builder.py +2 -2
- opentrons/drivers/flex_stacker/__init__.py +9 -0
- opentrons/drivers/flex_stacker/abstract.py +89 -0
- opentrons/drivers/flex_stacker/driver.py +260 -0
- opentrons/drivers/flex_stacker/simulator.py +109 -0
- opentrons/drivers/flex_stacker/types.py +138 -0
- opentrons/drivers/heater_shaker/driver.py +18 -3
- opentrons/drivers/temp_deck/driver.py +13 -3
- opentrons/drivers/thermocycler/driver.py +17 -3
- opentrons/execute.py +3 -1
- opentrons/hardware_control/__init__.py +1 -2
- opentrons/hardware_control/api.py +28 -20
- opentrons/hardware_control/backends/flex_protocol.py +4 -6
- opentrons/hardware_control/backends/ot3controller.py +177 -59
- opentrons/hardware_control/backends/ot3simulator.py +10 -8
- opentrons/hardware_control/backends/ot3utils.py +3 -13
- opentrons/hardware_control/dev_types.py +2 -0
- opentrons/hardware_control/emulation/heater_shaker.py +4 -0
- opentrons/hardware_control/emulation/module_server/client.py +1 -1
- opentrons/hardware_control/emulation/module_server/server.py +5 -3
- opentrons/hardware_control/emulation/settings.py +3 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +2 -1
- opentrons/hardware_control/instruments/ot2/pipette.py +9 -21
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +8 -1
- opentrons/hardware_control/instruments/ot3/gripper.py +2 -2
- opentrons/hardware_control/instruments/ot3/pipette.py +13 -22
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -1
- opentrons/hardware_control/modules/mod_abc.py +2 -2
- opentrons/hardware_control/motion_utilities.py +68 -0
- opentrons/hardware_control/nozzle_manager.py +39 -41
- opentrons/hardware_control/ot3_calibration.py +1 -1
- opentrons/hardware_control/ot3api.py +34 -22
- opentrons/hardware_control/protocols/gripper_controller.py +3 -0
- opentrons/hardware_control/protocols/hardware_manager.py +5 -1
- opentrons/hardware_control/protocols/liquid_handler.py +18 -0
- opentrons/hardware_control/protocols/motion_controller.py +6 -0
- opentrons/hardware_control/robot_calibration.py +1 -1
- opentrons/hardware_control/types.py +61 -0
- opentrons/protocol_api/__init__.py +20 -1
- opentrons/protocol_api/_liquid.py +24 -49
- opentrons/protocol_api/_liquid_properties.py +754 -0
- opentrons/protocol_api/_types.py +24 -0
- opentrons/protocol_api/core/common.py +2 -0
- opentrons/protocol_api/core/engine/instrument.py +67 -10
- opentrons/protocol_api/core/engine/labware.py +29 -7
- opentrons/protocol_api/core/engine/protocol.py +130 -5
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/well.py +4 -1
- opentrons/protocol_api/core/instrument.py +42 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +32 -1
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +145 -43
- opentrons/protocol_api/labware.py +231 -7
- opentrons/protocol_api/module_contexts.py +21 -17
- opentrons/protocol_api/protocol_context.py +125 -4
- opentrons/protocol_api/robot_context.py +204 -32
- opentrons/protocol_api/validation.py +261 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/actions.py +2 -3
- opentrons/protocol_engine/clients/sync_client.py +18 -0
- opentrons/protocol_engine/commands/__init__.py +81 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +0 -2
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +19 -5
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +0 -1
- opentrons/protocol_engine/commands/absorbance_reader/read.py +32 -9
- opentrons/protocol_engine/commands/air_gap_in_place.py +160 -0
- opentrons/protocol_engine/commands/aspirate.py +103 -53
- opentrons/protocol_engine/commands/aspirate_in_place.py +55 -51
- opentrons/protocol_engine/commands/blow_out.py +44 -39
- opentrons/protocol_engine/commands/blow_out_in_place.py +21 -32
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +13 -6
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +1 -1
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +3 -3
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +1 -1
- opentrons/protocol_engine/commands/command.py +73 -66
- opentrons/protocol_engine/commands/command_unions.py +101 -1
- opentrons/protocol_engine/commands/comment.py +1 -1
- opentrons/protocol_engine/commands/configure_for_volume.py +10 -3
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +6 -4
- opentrons/protocol_engine/commands/custom.py +6 -12
- opentrons/protocol_engine/commands/dispense.py +82 -48
- opentrons/protocol_engine/commands/dispense_in_place.py +71 -51
- opentrons/protocol_engine/commands/drop_tip.py +52 -31
- opentrons/protocol_engine/commands/drop_tip_in_place.py +13 -3
- opentrons/protocol_engine/commands/generate_command_schema.py +4 -11
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/home.py +13 -4
- opentrons/protocol_engine/commands/liquid_probe.py +60 -25
- opentrons/protocol_engine/commands/load_labware.py +29 -7
- opentrons/protocol_engine/commands/load_lid.py +146 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +189 -0
- opentrons/protocol_engine/commands/load_liquid.py +12 -4
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +31 -10
- opentrons/protocol_engine/commands/load_pipette.py +19 -8
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +1 -1
- opentrons/protocol_engine/commands/magnetic_module/engage.py +1 -1
- opentrons/protocol_engine/commands/move_labware.py +19 -6
- opentrons/protocol_engine/commands/move_relative.py +35 -25
- opentrons/protocol_engine/commands/move_to_addressable_area.py +40 -27
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +53 -32
- opentrons/protocol_engine/commands/move_to_coordinates.py +36 -22
- opentrons/protocol_engine/commands/move_to_well.py +40 -24
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +49 -27
- opentrons/protocol_engine/commands/pipetting_common.py +169 -87
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +24 -33
- opentrons/protocol_engine/commands/reload_labware.py +1 -1
- opentrons/protocol_engine/commands/retract_axis.py +1 -1
- opentrons/protocol_engine/commands/robot/__init__.py +69 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +77 -0
- opentrons/protocol_engine/commands/save_position.py +14 -5
- opentrons/protocol_engine/commands/set_rail_lights.py +1 -1
- opentrons/protocol_engine/commands/set_status_bar.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +8 -2
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +9 -3
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +11 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/touch_tip.py +65 -16
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +1 -4
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -4
- opentrons/protocol_engine/commands/verify_tip_presence.py +11 -4
- opentrons/protocol_engine/commands/wait_for_duration.py +10 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +10 -3
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/error_occurrence.py +19 -20
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +73 -5
- opentrons/protocol_engine/execution/gantry_mover.py +364 -8
- opentrons/protocol_engine/execution/movement.py +27 -0
- opentrons/protocol_engine/execution/pipetting.py +5 -1
- opentrons/protocol_engine/execution/tip_handler.py +4 -6
- opentrons/protocol_engine/notes/notes.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +7 -6
- opentrons/protocol_engine/resources/labware_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_validation.py +5 -0
- opentrons/protocol_engine/resources/module_data_provider.py +1 -1
- opentrons/protocol_engine/resources/pipette_data_provider.py +12 -0
- opentrons/protocol_engine/slot_standardization.py +9 -9
- opentrons/protocol_engine/state/_move_types.py +9 -5
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +25 -61
- opentrons/protocol_engine/state/command_history.py +12 -0
- opentrons/protocol_engine/state/commands.py +17 -13
- opentrons/protocol_engine/state/files.py +10 -12
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/frustum_helpers.py +57 -32
- opentrons/protocol_engine/state/geometry.py +47 -1
- opentrons/protocol_engine/state/labware.py +79 -25
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +16 -4
- opentrons/protocol_engine/state/modules.py +52 -70
- opentrons/protocol_engine/state/motion.py +6 -1
- opentrons/protocol_engine/state/pipettes.py +135 -58
- opentrons/protocol_engine/state/state.py +21 -2
- opentrons/protocol_engine/state/state_summary.py +4 -2
- opentrons/protocol_engine/state/tips.py +11 -44
- opentrons/protocol_engine/state/update_types.py +343 -48
- opentrons/protocol_engine/state/wells.py +19 -11
- opentrons/protocol_engine/types.py +176 -28
- opentrons/protocol_reader/extract_labware_definitions.py +5 -2
- opentrons/protocol_reader/file_format_validator.py +5 -5
- opentrons/protocol_runner/json_file_reader.py +9 -3
- opentrons/protocol_runner/json_translator.py +51 -25
- opentrons/protocol_runner/legacy_command_mapper.py +66 -64
- opentrons/protocol_runner/protocol_runner.py +35 -4
- opentrons/protocol_runner/python_protocol_wrappers.py +1 -1
- opentrons/protocol_runner/run_orchestrator.py +13 -3
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +1 -1
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +56 -0
- opentrons/protocols/advanced_control/{transfers.py → transfers/transfer.py} +10 -85
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +1 -1
- opentrons/protocols/api_support/util.py +10 -0
- opentrons/protocols/labware.py +39 -6
- opentrons/protocols/models/json_protocol.py +5 -9
- opentrons/simulate.py +3 -1
- opentrons/types.py +162 -2
- opentrons/util/logging_config.py +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/METADATA +16 -15
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/RECORD +228 -201
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/WHEEL +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/LICENSE +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a1.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"""Command models to read absorbance."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from typing import Optional, Dict, TYPE_CHECKING, List
|
|
5
|
-
from typing_extensions import Literal, Type
|
|
4
|
+
from typing import Optional, Dict, TYPE_CHECKING, List, Any
|
|
6
5
|
|
|
6
|
+
from typing_extensions import Literal, Type
|
|
7
7
|
from pydantic import BaseModel, Field
|
|
8
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
8
9
|
|
|
9
10
|
from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
10
11
|
from ...errors import CannotPerformModuleAction, StorageLimitReachedError
|
|
@@ -16,12 +17,17 @@ from ...resources.file_provider import (
|
|
|
16
17
|
MAXIMUM_CSV_FILE_LIMIT,
|
|
17
18
|
)
|
|
18
19
|
from ...resources import FileProvider
|
|
20
|
+
from ...state import update_types
|
|
19
21
|
|
|
20
22
|
if TYPE_CHECKING:
|
|
21
23
|
from opentrons.protocol_engine.state.state import StateView
|
|
22
24
|
from opentrons.protocol_engine.execution import EquipmentHandler
|
|
23
25
|
|
|
24
26
|
|
|
27
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
28
|
+
s.pop("default", None)
|
|
29
|
+
|
|
30
|
+
|
|
25
31
|
ReadAbsorbanceCommandType = Literal["absorbanceReader/read"]
|
|
26
32
|
|
|
27
33
|
|
|
@@ -29,9 +35,10 @@ class ReadAbsorbanceParams(BaseModel):
|
|
|
29
35
|
"""Input parameters for an absorbance reading."""
|
|
30
36
|
|
|
31
37
|
moduleId: str = Field(..., description="Unique ID of the Absorbance Reader.")
|
|
32
|
-
fileName:
|
|
38
|
+
fileName: str | SkipJsonSchema[None] = Field(
|
|
33
39
|
None,
|
|
34
40
|
description="Optional file name to use when storing the results of a measurement.",
|
|
41
|
+
json_schema_extra=_remove_default,
|
|
35
42
|
)
|
|
36
43
|
|
|
37
44
|
|
|
@@ -67,6 +74,7 @@ class ReadAbsorbanceImpl(
|
|
|
67
74
|
self, params: ReadAbsorbanceParams
|
|
68
75
|
) -> SuccessData[ReadAbsorbanceResult]:
|
|
69
76
|
"""Initiate an absorbance measurement."""
|
|
77
|
+
state_update = update_types.StateUpdate()
|
|
70
78
|
abs_reader_substate = self._state_view.modules.get_absorbance_reader_substate(
|
|
71
79
|
module_id=params.moduleId
|
|
72
80
|
)
|
|
@@ -117,7 +125,9 @@ class ReadAbsorbanceImpl(
|
|
|
117
125
|
)
|
|
118
126
|
asbsorbance_result[wavelength] = converted_values
|
|
119
127
|
transform_results.append(
|
|
120
|
-
ReadData.
|
|
128
|
+
ReadData.model_construct(
|
|
129
|
+
wavelength=wavelength, data=converted_values
|
|
130
|
+
)
|
|
121
131
|
)
|
|
122
132
|
# Handle the virtual module case for data creation (all zeroes)
|
|
123
133
|
elif self._state_view.config.use_virtual_modules:
|
|
@@ -131,22 +141,27 @@ class ReadAbsorbanceImpl(
|
|
|
131
141
|
)
|
|
132
142
|
asbsorbance_result[wavelength] = converted_values
|
|
133
143
|
transform_results.append(
|
|
134
|
-
ReadData.
|
|
144
|
+
ReadData.model_construct(
|
|
145
|
+
wavelength=wavelength, data=converted_values
|
|
146
|
+
)
|
|
135
147
|
)
|
|
136
148
|
else:
|
|
137
149
|
raise CannotPerformModuleAction(
|
|
138
150
|
"Plate Reader data cannot be requested with a module that has not been initialized."
|
|
139
151
|
)
|
|
140
152
|
|
|
153
|
+
state_update.set_absorbance_reader_data(
|
|
154
|
+
module_id=abs_reader_substate.module_id, read_result=asbsorbance_result
|
|
155
|
+
)
|
|
141
156
|
# TODO (cb, 10-17-2024): FILE PROVIDER - Some day we may want to break the file provider behavior into a seperate API function.
|
|
142
157
|
# When this happens, we probably will to have the change the command results handler we utilize to track file IDs in engine.
|
|
143
158
|
# Today, the action handler for the FileStore looks for a ReadAbsorbanceResult command action, this will need to be delinked.
|
|
144
159
|
|
|
145
160
|
# Begin interfacing with the file provider if the user provided a filename
|
|
146
|
-
file_ids = []
|
|
161
|
+
file_ids: list[str] = []
|
|
147
162
|
if params.fileName is not None:
|
|
148
163
|
# Create the Plate Reader Transform
|
|
149
|
-
plate_read_result = PlateReaderData.
|
|
164
|
+
plate_read_result = PlateReaderData.model_construct(
|
|
150
165
|
read_results=transform_results,
|
|
151
166
|
reference_wavelength=abs_reader_substate.reference_wavelength,
|
|
152
167
|
start_time=start_time,
|
|
@@ -170,12 +185,20 @@ class ReadAbsorbanceImpl(
|
|
|
170
185
|
# Return success data to api
|
|
171
186
|
return SuccessData(
|
|
172
187
|
public=ReadAbsorbanceResult(
|
|
173
|
-
data=asbsorbance_result,
|
|
188
|
+
data=asbsorbance_result,
|
|
189
|
+
fileIds=file_ids,
|
|
174
190
|
),
|
|
191
|
+
state_update=state_update,
|
|
175
192
|
)
|
|
176
193
|
|
|
194
|
+
state_update.files_added = update_types.FilesAddedUpdate(file_ids=file_ids)
|
|
195
|
+
|
|
177
196
|
return SuccessData(
|
|
178
|
-
public=ReadAbsorbanceResult(
|
|
197
|
+
public=ReadAbsorbanceResult(
|
|
198
|
+
data=asbsorbance_result,
|
|
199
|
+
fileIds=file_ids,
|
|
200
|
+
),
|
|
201
|
+
state_update=state_update,
|
|
179
202
|
)
|
|
180
203
|
|
|
181
204
|
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""AirGap in place command request, result, and implementation models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import TYPE_CHECKING, Optional, Type, Union
|
|
5
|
+
from typing_extensions import Literal
|
|
6
|
+
|
|
7
|
+
from opentrons_shared_data.errors.exceptions import PipetteOverpressureError
|
|
8
|
+
|
|
9
|
+
from opentrons.hardware_control import HardwareControlAPI
|
|
10
|
+
|
|
11
|
+
from .pipetting_common import (
|
|
12
|
+
PipetteIdMixin,
|
|
13
|
+
AspirateVolumeMixin,
|
|
14
|
+
FlowRateMixin,
|
|
15
|
+
BaseLiquidHandlingResult,
|
|
16
|
+
OverpressureError,
|
|
17
|
+
)
|
|
18
|
+
from .command import (
|
|
19
|
+
AbstractCommandImpl,
|
|
20
|
+
BaseCommand,
|
|
21
|
+
BaseCommandCreate,
|
|
22
|
+
SuccessData,
|
|
23
|
+
DefinedErrorData,
|
|
24
|
+
)
|
|
25
|
+
from ..errors.error_occurrence import ErrorOccurrence
|
|
26
|
+
from ..errors.exceptions import PipetteNotReadyToAspirateError
|
|
27
|
+
from ..state.update_types import StateUpdate
|
|
28
|
+
from ..types import AspiratedFluid, FluidKind
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from ..execution import PipettingHandler, GantryMover
|
|
32
|
+
from ..resources import ModelUtils
|
|
33
|
+
from ..state.state import StateView
|
|
34
|
+
from ..notes import CommandNoteAdder
|
|
35
|
+
|
|
36
|
+
AirGapInPlaceCommandType = Literal["airGapInPlace"]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AirGapInPlaceParams(PipetteIdMixin, AspirateVolumeMixin, FlowRateMixin):
|
|
40
|
+
"""Payload required to air gap in place."""
|
|
41
|
+
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AirGapInPlaceResult(BaseLiquidHandlingResult):
|
|
46
|
+
"""Result data from the execution of a AirGapInPlace command."""
|
|
47
|
+
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
_ExecuteReturn = Union[
|
|
52
|
+
SuccessData[AirGapInPlaceResult],
|
|
53
|
+
DefinedErrorData[OverpressureError],
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class AirGapInPlaceImplementation(
|
|
58
|
+
AbstractCommandImpl[AirGapInPlaceParams, _ExecuteReturn]
|
|
59
|
+
):
|
|
60
|
+
"""AirGapInPlace command implementation."""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
pipetting: PipettingHandler,
|
|
65
|
+
hardware_api: HardwareControlAPI,
|
|
66
|
+
state_view: StateView,
|
|
67
|
+
command_note_adder: CommandNoteAdder,
|
|
68
|
+
model_utils: ModelUtils,
|
|
69
|
+
gantry_mover: GantryMover,
|
|
70
|
+
**kwargs: object,
|
|
71
|
+
) -> None:
|
|
72
|
+
self._pipetting = pipetting
|
|
73
|
+
self._state_view = state_view
|
|
74
|
+
self._hardware_api = hardware_api
|
|
75
|
+
self._command_note_adder = command_note_adder
|
|
76
|
+
self._model_utils = model_utils
|
|
77
|
+
self._gantry_mover = gantry_mover
|
|
78
|
+
|
|
79
|
+
async def execute(self, params: AirGapInPlaceParams) -> _ExecuteReturn:
|
|
80
|
+
"""Air gap without moving the pipette.
|
|
81
|
+
|
|
82
|
+
Raises:
|
|
83
|
+
TipNotAttachedError: if no tip is attached to the pipette.
|
|
84
|
+
PipetteNotReadyToAirGapError: pipette plunger is not ready.
|
|
85
|
+
"""
|
|
86
|
+
ready_to_aspirate = self._pipetting.get_is_ready_to_aspirate(
|
|
87
|
+
pipette_id=params.pipetteId,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if not ready_to_aspirate:
|
|
91
|
+
raise PipetteNotReadyToAspirateError(
|
|
92
|
+
"Pipette cannot air gap in place because of a previous blow out."
|
|
93
|
+
" The first aspirate following a blow-out must be from a specific well"
|
|
94
|
+
" so the plunger can be reset in a known safe position."
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
state_update = StateUpdate()
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
current_position = await self._gantry_mover.get_position(params.pipetteId)
|
|
101
|
+
volume = await self._pipetting.aspirate_in_place(
|
|
102
|
+
pipette_id=params.pipetteId,
|
|
103
|
+
volume=params.volume,
|
|
104
|
+
flow_rate=params.flowRate,
|
|
105
|
+
command_note_adder=self._command_note_adder,
|
|
106
|
+
)
|
|
107
|
+
except PipetteOverpressureError as e:
|
|
108
|
+
return DefinedErrorData(
|
|
109
|
+
public=OverpressureError(
|
|
110
|
+
id=self._model_utils.generate_id(),
|
|
111
|
+
createdAt=self._model_utils.get_timestamp(),
|
|
112
|
+
wrappedErrors=[
|
|
113
|
+
ErrorOccurrence.from_failed(
|
|
114
|
+
id=self._model_utils.generate_id(),
|
|
115
|
+
createdAt=self._model_utils.get_timestamp(),
|
|
116
|
+
error=e,
|
|
117
|
+
)
|
|
118
|
+
],
|
|
119
|
+
errorInfo=(
|
|
120
|
+
{
|
|
121
|
+
"retryLocation": (
|
|
122
|
+
current_position.x,
|
|
123
|
+
current_position.y,
|
|
124
|
+
current_position.z,
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
state_update=state_update,
|
|
130
|
+
)
|
|
131
|
+
else:
|
|
132
|
+
state_update.set_fluid_aspirated(
|
|
133
|
+
pipette_id=params.pipetteId,
|
|
134
|
+
fluid=AspiratedFluid(kind=FluidKind.AIR, volume=volume),
|
|
135
|
+
)
|
|
136
|
+
return SuccessData(
|
|
137
|
+
public=AirGapInPlaceResult(volume=volume),
|
|
138
|
+
state_update=state_update,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class AirGapInPlace(
|
|
143
|
+
BaseCommand[AirGapInPlaceParams, AirGapInPlaceResult, OverpressureError]
|
|
144
|
+
):
|
|
145
|
+
"""AirGapInPlace command model."""
|
|
146
|
+
|
|
147
|
+
commandType: AirGapInPlaceCommandType = "airGapInPlace"
|
|
148
|
+
params: AirGapInPlaceParams
|
|
149
|
+
result: Optional[AirGapInPlaceResult]
|
|
150
|
+
|
|
151
|
+
_ImplementationCls: Type[AirGapInPlaceImplementation] = AirGapInPlaceImplementation
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class AirGapInPlaceCreate(BaseCommandCreate[AirGapInPlaceParams]):
|
|
155
|
+
"""AirGapInPlace command request model."""
|
|
156
|
+
|
|
157
|
+
commandType: AirGapInPlaceCommandType = "airGapInPlace"
|
|
158
|
+
params: AirGapInPlaceParams
|
|
159
|
+
|
|
160
|
+
_CommandCls: Type[AirGapInPlace] = AirGapInPlace
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Aspirate command request, result, and implementation models."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
from typing import TYPE_CHECKING, Optional, Type, Union
|
|
4
|
-
from opentrons_shared_data.errors.exceptions import PipetteOverpressureError
|
|
5
5
|
from typing_extensions import Literal
|
|
6
6
|
|
|
7
7
|
from .pipetting_common import (
|
|
@@ -9,9 +9,15 @@ from .pipetting_common import (
|
|
|
9
9
|
PipetteIdMixin,
|
|
10
10
|
AspirateVolumeMixin,
|
|
11
11
|
FlowRateMixin,
|
|
12
|
-
LiquidHandlingWellLocationMixin,
|
|
13
12
|
BaseLiquidHandlingResult,
|
|
13
|
+
aspirate_in_place,
|
|
14
|
+
prepare_for_aspirate,
|
|
15
|
+
)
|
|
16
|
+
from .movement_common import (
|
|
17
|
+
LiquidHandlingWellLocationMixin,
|
|
14
18
|
DestinationPositionResult,
|
|
19
|
+
StallOrCollisionError,
|
|
20
|
+
move_to_well,
|
|
15
21
|
)
|
|
16
22
|
from .command import (
|
|
17
23
|
AbstractCommandImpl,
|
|
@@ -20,12 +26,15 @@ from .command import (
|
|
|
20
26
|
DefinedErrorData,
|
|
21
27
|
SuccessData,
|
|
22
28
|
)
|
|
23
|
-
from ..errors.error_occurrence import ErrorOccurrence
|
|
24
29
|
|
|
25
30
|
from opentrons.hardware_control import HardwareControlAPI
|
|
26
31
|
|
|
27
32
|
from ..state.update_types import StateUpdate, CLEAR
|
|
28
|
-
from ..types import
|
|
33
|
+
from ..types import (
|
|
34
|
+
WellLocation,
|
|
35
|
+
WellOrigin,
|
|
36
|
+
CurrentWell,
|
|
37
|
+
)
|
|
29
38
|
|
|
30
39
|
if TYPE_CHECKING:
|
|
31
40
|
from ..execution import MovementHandler, PipettingHandler
|
|
@@ -53,7 +62,7 @@ class AspirateResult(BaseLiquidHandlingResult, DestinationPositionResult):
|
|
|
53
62
|
|
|
54
63
|
_ExecuteReturn = Union[
|
|
55
64
|
SuccessData[AspirateResult],
|
|
56
|
-
DefinedErrorData[OverpressureError],
|
|
65
|
+
DefinedErrorData[OverpressureError] | DefinedErrorData[StallOrCollisionError],
|
|
57
66
|
]
|
|
58
67
|
|
|
59
68
|
|
|
@@ -86,23 +95,51 @@ class AspirateImplementation(AbstractCommandImpl[AspirateParams, _ExecuteReturn]
|
|
|
86
95
|
pipette_id = params.pipetteId
|
|
87
96
|
labware_id = params.labwareId
|
|
88
97
|
well_name = params.wellName
|
|
98
|
+
well_location = params.wellLocation
|
|
99
|
+
|
|
100
|
+
state_update = StateUpdate()
|
|
101
|
+
|
|
102
|
+
final_location = self._state_view.geometry.get_well_position(
|
|
103
|
+
labware_id=labware_id,
|
|
104
|
+
well_name=well_name,
|
|
105
|
+
well_location=well_location,
|
|
106
|
+
operation_volume=-params.volume,
|
|
107
|
+
pipette_id=pipette_id,
|
|
108
|
+
)
|
|
89
109
|
|
|
90
110
|
ready_to_aspirate = self._pipetting.get_is_ready_to_aspirate(
|
|
91
111
|
pipette_id=pipette_id
|
|
92
112
|
)
|
|
93
113
|
|
|
94
114
|
current_well = None
|
|
95
|
-
state_update = StateUpdate()
|
|
96
115
|
|
|
97
116
|
if not ready_to_aspirate:
|
|
98
|
-
await
|
|
117
|
+
move_result = await move_to_well(
|
|
118
|
+
movement=self._movement,
|
|
119
|
+
model_utils=self._model_utils,
|
|
99
120
|
pipette_id=pipette_id,
|
|
100
121
|
labware_id=labware_id,
|
|
101
122
|
well_name=well_name,
|
|
102
123
|
well_location=WellLocation(origin=WellOrigin.TOP),
|
|
103
124
|
)
|
|
125
|
+
state_update.append(move_result.state_update)
|
|
126
|
+
if isinstance(move_result, DefinedErrorData):
|
|
127
|
+
return DefinedErrorData(move_result.public, state_update=state_update)
|
|
104
128
|
|
|
105
|
-
await
|
|
129
|
+
prepare_result = await prepare_for_aspirate(
|
|
130
|
+
pipette_id=pipette_id,
|
|
131
|
+
pipetting=self._pipetting,
|
|
132
|
+
model_utils=self._model_utils,
|
|
133
|
+
# Note that the retryLocation is the final location, inside the liquid,
|
|
134
|
+
# because that's where we'd want the client to try re-aspirating if this
|
|
135
|
+
# command fails and the run enters error recovery.
|
|
136
|
+
location_if_error={"retryLocation": final_location},
|
|
137
|
+
)
|
|
138
|
+
state_update.append(prepare_result.state_update)
|
|
139
|
+
if isinstance(prepare_result, DefinedErrorData):
|
|
140
|
+
return DefinedErrorData(
|
|
141
|
+
public=prepare_result.public, state_update=state_update
|
|
142
|
+
)
|
|
106
143
|
|
|
107
144
|
# set our current deck location to the well now that we've made
|
|
108
145
|
# an intermediate move for the "prepare for aspirate" step
|
|
@@ -112,71 +149,84 @@ class AspirateImplementation(AbstractCommandImpl[AspirateParams, _ExecuteReturn]
|
|
|
112
149
|
well_name=well_name,
|
|
113
150
|
)
|
|
114
151
|
|
|
115
|
-
|
|
152
|
+
move_result = await move_to_well(
|
|
153
|
+
movement=self._movement,
|
|
154
|
+
model_utils=self._model_utils,
|
|
116
155
|
pipette_id=pipette_id,
|
|
117
156
|
labware_id=labware_id,
|
|
118
157
|
well_name=well_name,
|
|
119
|
-
well_location=
|
|
158
|
+
well_location=well_location,
|
|
120
159
|
current_well=current_well,
|
|
121
160
|
operation_volume=-params.volume,
|
|
122
161
|
)
|
|
123
|
-
|
|
124
|
-
|
|
162
|
+
state_update.append(move_result.state_update)
|
|
163
|
+
if isinstance(move_result, DefinedErrorData):
|
|
164
|
+
return DefinedErrorData(
|
|
165
|
+
public=move_result.public, state_update=state_update
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
aspirate_result = await aspirate_in_place(
|
|
125
169
|
pipette_id=pipette_id,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
170
|
+
volume=params.volume,
|
|
171
|
+
flow_rate=params.flowRate,
|
|
172
|
+
location_if_error={
|
|
173
|
+
"retryLocation": (
|
|
174
|
+
move_result.public.position.x,
|
|
175
|
+
move_result.public.position.y,
|
|
176
|
+
move_result.public.position.z,
|
|
177
|
+
)
|
|
178
|
+
},
|
|
179
|
+
command_note_adder=self._command_note_adder,
|
|
180
|
+
pipetting=self._pipetting,
|
|
181
|
+
model_utils=self._model_utils,
|
|
129
182
|
)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
volume_aspirated = await self._pipetting.aspirate_in_place(
|
|
133
|
-
pipette_id=pipette_id,
|
|
134
|
-
volume=params.volume,
|
|
135
|
-
flow_rate=params.flowRate,
|
|
136
|
-
command_note_adder=self._command_note_adder,
|
|
137
|
-
)
|
|
138
|
-
except PipetteOverpressureError as e:
|
|
183
|
+
state_update.append(aspirate_result.state_update)
|
|
184
|
+
if isinstance(aspirate_result, DefinedErrorData):
|
|
139
185
|
state_update.set_liquid_operated(
|
|
140
186
|
labware_id=labware_id,
|
|
141
|
-
|
|
187
|
+
well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
|
|
188
|
+
labware_id,
|
|
189
|
+
well_name,
|
|
190
|
+
params.pipetteId,
|
|
191
|
+
),
|
|
142
192
|
volume_added=CLEAR,
|
|
143
193
|
)
|
|
144
194
|
return DefinedErrorData(
|
|
145
|
-
public=
|
|
146
|
-
id=self._model_utils.generate_id(),
|
|
147
|
-
createdAt=self._model_utils.get_timestamp(),
|
|
148
|
-
wrappedErrors=[
|
|
149
|
-
ErrorOccurrence.from_failed(
|
|
150
|
-
id=self._model_utils.generate_id(),
|
|
151
|
-
createdAt=self._model_utils.get_timestamp(),
|
|
152
|
-
error=e,
|
|
153
|
-
)
|
|
154
|
-
],
|
|
155
|
-
errorInfo={"retryLocation": (position.x, position.y, position.z)},
|
|
156
|
-
),
|
|
157
|
-
state_update=state_update,
|
|
158
|
-
)
|
|
159
|
-
else:
|
|
160
|
-
state_update.set_liquid_operated(
|
|
161
|
-
labware_id=labware_id,
|
|
162
|
-
well_name=well_name,
|
|
163
|
-
volume_added=-volume_aspirated,
|
|
164
|
-
)
|
|
165
|
-
return SuccessData(
|
|
166
|
-
public=AspirateResult(
|
|
167
|
-
volume=volume_aspirated,
|
|
168
|
-
position=deck_point,
|
|
169
|
-
),
|
|
170
|
-
state_update=state_update,
|
|
195
|
+
public=aspirate_result.public, state_update=state_update
|
|
171
196
|
)
|
|
172
197
|
|
|
198
|
+
state_update.set_liquid_operated(
|
|
199
|
+
labware_id=labware_id,
|
|
200
|
+
well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
|
|
201
|
+
labware_id, well_name, pipette_id
|
|
202
|
+
),
|
|
203
|
+
volume_added=-aspirate_result.public.volume
|
|
204
|
+
* self._state_view.geometry.get_nozzles_per_well(
|
|
205
|
+
labware_id,
|
|
206
|
+
well_name,
|
|
207
|
+
params.pipetteId,
|
|
208
|
+
),
|
|
209
|
+
)
|
|
173
210
|
|
|
174
|
-
|
|
211
|
+
return SuccessData(
|
|
212
|
+
public=AspirateResult(
|
|
213
|
+
volume=aspirate_result.public.volume,
|
|
214
|
+
position=move_result.public.position,
|
|
215
|
+
),
|
|
216
|
+
state_update=state_update,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class Aspirate(
|
|
221
|
+
BaseCommand[
|
|
222
|
+
AspirateParams, AspirateResult, OverpressureError | StallOrCollisionError
|
|
223
|
+
]
|
|
224
|
+
):
|
|
175
225
|
"""Aspirate command model."""
|
|
176
226
|
|
|
177
227
|
commandType: AspirateCommandType = "aspirate"
|
|
178
228
|
params: AspirateParams
|
|
179
|
-
result: Optional[AspirateResult]
|
|
229
|
+
result: Optional[AspirateResult] = None
|
|
180
230
|
|
|
181
231
|
_ImplementationCls: Type[AspirateImplementation] = AspirateImplementation
|
|
182
232
|
|
|
@@ -4,8 +4,6 @@ from __future__ import annotations
|
|
|
4
4
|
from typing import TYPE_CHECKING, Optional, Type, Union
|
|
5
5
|
from typing_extensions import Literal
|
|
6
6
|
|
|
7
|
-
from opentrons_shared_data.errors.exceptions import PipetteOverpressureError
|
|
8
|
-
|
|
9
7
|
from opentrons.hardware_control import HardwareControlAPI
|
|
10
8
|
|
|
11
9
|
from .pipetting_common import (
|
|
@@ -14,6 +12,7 @@ from .pipetting_common import (
|
|
|
14
12
|
FlowRateMixin,
|
|
15
13
|
BaseLiquidHandlingResult,
|
|
16
14
|
OverpressureError,
|
|
15
|
+
aspirate_in_place,
|
|
17
16
|
)
|
|
18
17
|
from .command import (
|
|
19
18
|
AbstractCommandImpl,
|
|
@@ -22,9 +21,8 @@ from .command import (
|
|
|
22
21
|
SuccessData,
|
|
23
22
|
DefinedErrorData,
|
|
24
23
|
)
|
|
25
|
-
from ..errors.error_occurrence import ErrorOccurrence
|
|
26
24
|
from ..errors.exceptions import PipetteNotReadyToAspirateError
|
|
27
|
-
from ..state.update_types import
|
|
25
|
+
from ..state.update_types import CLEAR
|
|
28
26
|
from ..types import CurrentWell
|
|
29
27
|
|
|
30
28
|
if TYPE_CHECKING:
|
|
@@ -83,8 +81,6 @@ class AspirateInPlaceImplementation(
|
|
|
83
81
|
TipNotAttachedError: if no tip is attached to the pipette.
|
|
84
82
|
PipetteNotReadyToAspirateError: pipette plunger is not ready.
|
|
85
83
|
"""
|
|
86
|
-
state_update = StateUpdate()
|
|
87
|
-
|
|
88
84
|
ready_to_aspirate = self._pipetting.get_is_ready_to_aspirate(
|
|
89
85
|
pipette_id=params.pipetteId,
|
|
90
86
|
)
|
|
@@ -95,63 +91,71 @@ class AspirateInPlaceImplementation(
|
|
|
95
91
|
" so the plunger can be reset in a known safe position."
|
|
96
92
|
)
|
|
97
93
|
|
|
98
|
-
current_location = self._state_view.pipettes.get_current_location()
|
|
99
94
|
current_position = await self._gantry_mover.get_position(params.pipetteId)
|
|
95
|
+
current_location = self._state_view.pipettes.get_current_location()
|
|
100
96
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
97
|
+
result = await aspirate_in_place(
|
|
98
|
+
pipette_id=params.pipetteId,
|
|
99
|
+
volume=params.volume,
|
|
100
|
+
flow_rate=params.flowRate,
|
|
101
|
+
location_if_error={
|
|
102
|
+
"retryLocation": (
|
|
103
|
+
current_position.x,
|
|
104
|
+
current_position.y,
|
|
105
|
+
current_position.z,
|
|
106
|
+
)
|
|
107
|
+
},
|
|
108
|
+
command_note_adder=self._command_note_adder,
|
|
109
|
+
pipetting=self._pipetting,
|
|
110
|
+
model_utils=self._model_utils,
|
|
111
|
+
)
|
|
112
|
+
if isinstance(result, DefinedErrorData):
|
|
109
113
|
if (
|
|
110
114
|
isinstance(current_location, CurrentWell)
|
|
111
115
|
and current_location.pipette_id == params.pipetteId
|
|
112
116
|
):
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
ErrorOccurrence.from_failed(
|
|
124
|
-
id=self._model_utils.generate_id(),
|
|
125
|
-
createdAt=self._model_utils.get_timestamp(),
|
|
126
|
-
error=e,
|
|
127
|
-
)
|
|
128
|
-
],
|
|
129
|
-
errorInfo=(
|
|
130
|
-
{
|
|
131
|
-
"retryLocation": (
|
|
132
|
-
current_position.x,
|
|
133
|
-
current_position.y,
|
|
134
|
-
current_position.z,
|
|
135
|
-
)
|
|
136
|
-
}
|
|
117
|
+
return DefinedErrorData(
|
|
118
|
+
public=result.public,
|
|
119
|
+
state_update=result.state_update.set_liquid_operated(
|
|
120
|
+
labware_id=current_location.labware_id,
|
|
121
|
+
well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
|
|
122
|
+
current_location.labware_id,
|
|
123
|
+
current_location.well_name,
|
|
124
|
+
params.pipetteId,
|
|
125
|
+
),
|
|
126
|
+
volume_added=CLEAR,
|
|
137
127
|
),
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
128
|
+
state_update_if_false_positive=result.state_update_if_false_positive,
|
|
129
|
+
)
|
|
130
|
+
else:
|
|
131
|
+
return result
|
|
141
132
|
else:
|
|
142
133
|
if (
|
|
143
134
|
isinstance(current_location, CurrentWell)
|
|
144
135
|
and current_location.pipette_id == params.pipetteId
|
|
145
136
|
):
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
137
|
+
return SuccessData(
|
|
138
|
+
public=AspirateInPlaceResult(volume=result.public.volume),
|
|
139
|
+
state_update=result.state_update.set_liquid_operated(
|
|
140
|
+
labware_id=current_location.labware_id,
|
|
141
|
+
well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
|
|
142
|
+
current_location.labware_id,
|
|
143
|
+
current_location.well_name,
|
|
144
|
+
params.pipetteId,
|
|
145
|
+
),
|
|
146
|
+
volume_added=-result.public.volume
|
|
147
|
+
* self._state_view.geometry.get_nozzles_per_well(
|
|
148
|
+
current_location.labware_id,
|
|
149
|
+
current_location.well_name,
|
|
150
|
+
params.pipetteId,
|
|
151
|
+
),
|
|
152
|
+
),
|
|
153
|
+
)
|
|
154
|
+
else:
|
|
155
|
+
return SuccessData(
|
|
156
|
+
public=AspirateInPlaceResult(volume=result.public.volume),
|
|
157
|
+
state_update=result.state_update,
|
|
150
158
|
)
|
|
151
|
-
return SuccessData(
|
|
152
|
-
public=AspirateInPlaceResult(volume=volume),
|
|
153
|
-
state_update=state_update,
|
|
154
|
-
)
|
|
155
159
|
|
|
156
160
|
|
|
157
161
|
class AspirateInPlace(
|
|
@@ -161,7 +165,7 @@ class AspirateInPlace(
|
|
|
161
165
|
|
|
162
166
|
commandType: AspirateInPlaceCommandType = "aspirateInPlace"
|
|
163
167
|
params: AspirateInPlaceParams
|
|
164
|
-
result: Optional[AspirateInPlaceResult]
|
|
168
|
+
result: Optional[AspirateInPlaceResult] = None
|
|
165
169
|
|
|
166
170
|
_ImplementationCls: Type[
|
|
167
171
|
AspirateInPlaceImplementation
|