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,14 +1,22 @@
|
|
|
1
1
|
"""Structures to represent changes that commands want to make to engine state."""
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import dataclasses
|
|
5
4
|
import enum
|
|
6
5
|
import typing
|
|
6
|
+
from typing_extensions import Self
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
|
|
9
9
|
from opentrons.hardware_control.nozzle_manager import NozzleMap
|
|
10
10
|
from opentrons.protocol_engine.resources import pipette_data_provider
|
|
11
|
-
from opentrons.protocol_engine.types import
|
|
11
|
+
from opentrons.protocol_engine.types import (
|
|
12
|
+
DeckPoint,
|
|
13
|
+
LabwareLocation,
|
|
14
|
+
OnLabwareLocation,
|
|
15
|
+
TipGeometry,
|
|
16
|
+
AspiratedFluid,
|
|
17
|
+
LiquidClassRecord,
|
|
18
|
+
ABSMeasureMode,
|
|
19
|
+
)
|
|
12
20
|
from opentrons.types import MountType
|
|
13
21
|
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
14
22
|
from opentrons_shared_data.pipette.types import PipetteNameType
|
|
@@ -92,7 +100,7 @@ class LabwareLocationUpdate:
|
|
|
92
100
|
new_location: LabwareLocation
|
|
93
101
|
"""The labware's new location."""
|
|
94
102
|
|
|
95
|
-
offset_id:
|
|
103
|
+
offset_id: str | None
|
|
96
104
|
"""The ID of the labware's new offset, for its new location."""
|
|
97
105
|
|
|
98
106
|
|
|
@@ -106,12 +114,46 @@ class LoadedLabwareUpdate:
|
|
|
106
114
|
new_location: LabwareLocation
|
|
107
115
|
"""The labware's initial location."""
|
|
108
116
|
|
|
109
|
-
offset_id:
|
|
117
|
+
offset_id: str | None
|
|
110
118
|
"""The ID of the labware's offset."""
|
|
111
119
|
|
|
112
|
-
display_name:
|
|
120
|
+
display_name: str | None
|
|
121
|
+
|
|
122
|
+
definition: LabwareDefinition
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclasses.dataclass
|
|
126
|
+
class LoadedLidStackUpdate:
|
|
127
|
+
"""An update that loads a new lid stack."""
|
|
128
|
+
|
|
129
|
+
stack_id: str
|
|
130
|
+
"""The unique ID of the Lid Stack Object."""
|
|
131
|
+
|
|
132
|
+
stack_object_definition: LabwareDefinition
|
|
133
|
+
"The System-only Labware Definition of the Lid Stack Object"
|
|
134
|
+
|
|
135
|
+
stack_location: LabwareLocation
|
|
136
|
+
"The initial location of the Lid Stack Object."
|
|
137
|
+
|
|
138
|
+
labware_ids: typing.List[str]
|
|
139
|
+
"""The unique IDs of the new lids."""
|
|
140
|
+
|
|
141
|
+
new_locations_by_id: typing.Dict[str, OnLabwareLocation]
|
|
142
|
+
"""Each lid's initial location keyed by Labware ID."""
|
|
113
143
|
|
|
114
144
|
definition: LabwareDefinition
|
|
145
|
+
"The Labware Definition of the Lid Labware(s) loaded."
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@dataclasses.dataclass
|
|
149
|
+
class LabwareLidUpdate:
|
|
150
|
+
"""An update that identifies a lid on a given parent labware."""
|
|
151
|
+
|
|
152
|
+
parent_labware_id: str
|
|
153
|
+
"""The unique ID of the parent labware."""
|
|
154
|
+
|
|
155
|
+
lid_id: str
|
|
156
|
+
"""The unique IDs of the new lids."""
|
|
115
157
|
|
|
116
158
|
|
|
117
159
|
@dataclasses.dataclass
|
|
@@ -127,7 +169,7 @@ class LoadPipetteUpdate:
|
|
|
127
169
|
|
|
128
170
|
pipette_name: PipetteNameType
|
|
129
171
|
mount: MountType
|
|
130
|
-
liquid_presence_detection:
|
|
172
|
+
liquid_presence_detection: bool | None
|
|
131
173
|
|
|
132
174
|
|
|
133
175
|
@dataclasses.dataclass
|
|
@@ -156,7 +198,7 @@ class PipetteTipStateUpdate:
|
|
|
156
198
|
"""Update pipette tip state."""
|
|
157
199
|
|
|
158
200
|
pipette_id: str
|
|
159
|
-
tip_geometry:
|
|
201
|
+
tip_geometry: TipGeometry | None
|
|
160
202
|
|
|
161
203
|
|
|
162
204
|
@dataclasses.dataclass
|
|
@@ -201,18 +243,101 @@ class LiquidOperatedUpdate:
|
|
|
201
243
|
"""An update from operating a liquid."""
|
|
202
244
|
|
|
203
245
|
labware_id: str
|
|
204
|
-
|
|
246
|
+
well_names: list[str]
|
|
205
247
|
volume_added: float | ClearType
|
|
206
248
|
|
|
207
249
|
|
|
250
|
+
@dataclasses.dataclass
|
|
251
|
+
class PipetteAspiratedFluidUpdate:
|
|
252
|
+
"""Represents the pipette aspirating something. Might be air or liquid from a well."""
|
|
253
|
+
|
|
254
|
+
pipette_id: str
|
|
255
|
+
fluid: AspiratedFluid
|
|
256
|
+
type: typing.Literal["aspirated"] = "aspirated"
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@dataclasses.dataclass
|
|
260
|
+
class PipetteEjectedFluidUpdate:
|
|
261
|
+
"""Represents the pipette pushing something out. Might be air or liquid."""
|
|
262
|
+
|
|
263
|
+
pipette_id: str
|
|
264
|
+
volume: float
|
|
265
|
+
type: typing.Literal["ejected"] = "ejected"
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@dataclasses.dataclass
|
|
269
|
+
class PipetteUnknownFluidUpdate:
|
|
270
|
+
"""Represents the amount of fluid in the pipette becoming unknown."""
|
|
271
|
+
|
|
272
|
+
pipette_id: str
|
|
273
|
+
type: typing.Literal["unknown"] = "unknown"
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@dataclasses.dataclass
|
|
277
|
+
class PipetteEmptyFluidUpdate:
|
|
278
|
+
"""Sets the pipette to be valid and empty."""
|
|
279
|
+
|
|
280
|
+
pipette_id: str
|
|
281
|
+
type: typing.Literal["empty"] = "empty"
|
|
282
|
+
|
|
283
|
+
|
|
208
284
|
@dataclasses.dataclass
|
|
209
285
|
class AbsorbanceReaderLidUpdate:
|
|
210
286
|
"""An update to an absorbance reader's lid location."""
|
|
211
287
|
|
|
212
|
-
module_id: str
|
|
213
288
|
is_lid_on: bool
|
|
214
289
|
|
|
215
290
|
|
|
291
|
+
@dataclasses.dataclass
|
|
292
|
+
class AbsorbanceReaderDataUpdate:
|
|
293
|
+
"""An update to an absorbance reader's lid location."""
|
|
294
|
+
|
|
295
|
+
read_result: typing.Dict[int, typing.Dict[str, float]]
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@dataclasses.dataclass(frozen=True)
|
|
299
|
+
class AbsorbanceReaderInitializeUpdate:
|
|
300
|
+
"""An update to an absorbance reader's initialization."""
|
|
301
|
+
|
|
302
|
+
measure_mode: ABSMeasureMode
|
|
303
|
+
sample_wave_lengths: typing.List[int]
|
|
304
|
+
reference_wave_length: typing.Optional[int]
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
@dataclasses.dataclass
|
|
308
|
+
class AbsorbanceReaderStateUpdate:
|
|
309
|
+
"""An update to the absorbance reader module state."""
|
|
310
|
+
|
|
311
|
+
module_id: str
|
|
312
|
+
absorbance_reader_lid: AbsorbanceReaderLidUpdate | NoChangeType = NO_CHANGE
|
|
313
|
+
absorbance_reader_data: AbsorbanceReaderDataUpdate | NoChangeType = NO_CHANGE
|
|
314
|
+
initialize_absorbance_reader_update: AbsorbanceReaderInitializeUpdate | NoChangeType = (
|
|
315
|
+
NO_CHANGE
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
@dataclasses.dataclass
|
|
320
|
+
class LiquidClassLoadedUpdate:
|
|
321
|
+
"""The state update from loading a liquid class."""
|
|
322
|
+
|
|
323
|
+
liquid_class_id: str
|
|
324
|
+
liquid_class_record: LiquidClassRecord
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
@dataclasses.dataclass
|
|
328
|
+
class FilesAddedUpdate:
|
|
329
|
+
"""An update that adds a new data file."""
|
|
330
|
+
|
|
331
|
+
file_ids: list[str]
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@dataclasses.dataclass
|
|
335
|
+
class AddressableAreaUsedUpdate:
|
|
336
|
+
"""An update that says an addressable area has been used."""
|
|
337
|
+
|
|
338
|
+
addressable_area_name: str
|
|
339
|
+
|
|
340
|
+
|
|
216
341
|
@dataclasses.dataclass
|
|
217
342
|
class StateUpdate:
|
|
218
343
|
"""Represents an update to perform on engine state."""
|
|
@@ -227,10 +352,22 @@ class StateUpdate:
|
|
|
227
352
|
|
|
228
353
|
pipette_tip_state: PipetteTipStateUpdate | NoChangeType = NO_CHANGE
|
|
229
354
|
|
|
355
|
+
pipette_aspirated_fluid: (
|
|
356
|
+
PipetteAspiratedFluidUpdate
|
|
357
|
+
| PipetteEjectedFluidUpdate
|
|
358
|
+
| PipetteUnknownFluidUpdate
|
|
359
|
+
| PipetteEmptyFluidUpdate
|
|
360
|
+
| NoChangeType
|
|
361
|
+
) = NO_CHANGE
|
|
362
|
+
|
|
230
363
|
labware_location: LabwareLocationUpdate | NoChangeType = NO_CHANGE
|
|
231
364
|
|
|
232
365
|
loaded_labware: LoadedLabwareUpdate | NoChangeType = NO_CHANGE
|
|
233
366
|
|
|
367
|
+
loaded_lid_stack: LoadedLidStackUpdate | NoChangeType = NO_CHANGE
|
|
368
|
+
|
|
369
|
+
labware_lid: LabwareLidUpdate | NoChangeType = NO_CHANGE
|
|
370
|
+
|
|
234
371
|
tips_used: TipsUsedUpdate | NoChangeType = NO_CHANGE
|
|
235
372
|
|
|
236
373
|
liquid_loaded: LiquidLoadedUpdate | NoChangeType = NO_CHANGE
|
|
@@ -239,42 +376,81 @@ class StateUpdate:
|
|
|
239
376
|
|
|
240
377
|
liquid_operated: LiquidOperatedUpdate | NoChangeType = NO_CHANGE
|
|
241
378
|
|
|
242
|
-
|
|
379
|
+
absorbance_reader_state_update: AbsorbanceReaderStateUpdate | NoChangeType = (
|
|
380
|
+
NO_CHANGE
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
liquid_class_loaded: LiquidClassLoadedUpdate | NoChangeType = NO_CHANGE
|
|
384
|
+
|
|
385
|
+
files_added: FilesAddedUpdate | NoChangeType = NO_CHANGE
|
|
386
|
+
|
|
387
|
+
addressable_area_used: AddressableAreaUsedUpdate | NoChangeType = NO_CHANGE
|
|
388
|
+
|
|
389
|
+
def append(self, other: Self) -> Self:
|
|
390
|
+
"""Apply another `StateUpdate` "on top of" this one.
|
|
391
|
+
|
|
392
|
+
This object is mutated in-place, taking values from `other`.
|
|
393
|
+
If an attribute in `other` is `NO_CHANGE`, the value in this object is kept.
|
|
394
|
+
"""
|
|
395
|
+
fields = dataclasses.fields(other)
|
|
396
|
+
for field in fields:
|
|
397
|
+
other_value = other.__dict__[field.name]
|
|
398
|
+
if other_value != NO_CHANGE:
|
|
399
|
+
self.__dict__[field.name] = other_value
|
|
400
|
+
return self
|
|
401
|
+
|
|
402
|
+
@classmethod
|
|
403
|
+
def reduce(cls: typing.Type[Self], *args: Self) -> Self:
|
|
404
|
+
"""Fuse multiple state updates into a single one.
|
|
405
|
+
|
|
406
|
+
State updates that are later in the parameter list are preferred to those that are earlier;
|
|
407
|
+
NO_CHANGE is ignored.
|
|
408
|
+
"""
|
|
409
|
+
accumulator = cls()
|
|
410
|
+
for arg in args:
|
|
411
|
+
accumulator.append(arg)
|
|
412
|
+
return accumulator
|
|
243
413
|
|
|
244
414
|
# These convenience functions let the caller avoid the boilerplate of constructing a
|
|
245
|
-
# complicated dataclass tree.
|
|
415
|
+
# complicated dataclass tree, and allow chaining.
|
|
246
416
|
|
|
247
417
|
@typing.overload
|
|
248
418
|
def set_pipette_location(
|
|
249
|
-
self,
|
|
419
|
+
self: Self, *, pipette_id: str, new_deck_point: DeckPoint
|
|
420
|
+
) -> Self:
|
|
421
|
+
"""Schedule a pipette's coordinates to be changed while preserving its logical location."""
|
|
422
|
+
|
|
423
|
+
@typing.overload
|
|
424
|
+
def set_pipette_location(
|
|
425
|
+
self: Self,
|
|
250
426
|
*,
|
|
251
427
|
pipette_id: str,
|
|
252
428
|
new_labware_id: str,
|
|
253
429
|
new_well_name: str,
|
|
254
430
|
new_deck_point: DeckPoint,
|
|
255
|
-
) ->
|
|
431
|
+
) -> Self:
|
|
256
432
|
"""Schedule a pipette's location to be set to a well."""
|
|
257
433
|
|
|
258
434
|
@typing.overload
|
|
259
435
|
def set_pipette_location(
|
|
260
|
-
self,
|
|
436
|
+
self: Self,
|
|
261
437
|
*,
|
|
262
438
|
pipette_id: str,
|
|
263
439
|
new_addressable_area_name: str,
|
|
264
440
|
new_deck_point: DeckPoint,
|
|
265
|
-
) ->
|
|
441
|
+
) -> Self:
|
|
266
442
|
"""Schedule a pipette's location to be set to an addressable area."""
|
|
267
443
|
pass
|
|
268
444
|
|
|
269
445
|
def set_pipette_location( # noqa: D102
|
|
270
|
-
self,
|
|
446
|
+
self: Self,
|
|
271
447
|
*,
|
|
272
448
|
pipette_id: str,
|
|
273
449
|
new_labware_id: str | NoChangeType = NO_CHANGE,
|
|
274
450
|
new_well_name: str | NoChangeType = NO_CHANGE,
|
|
275
451
|
new_addressable_area_name: str | NoChangeType = NO_CHANGE,
|
|
276
452
|
new_deck_point: DeckPoint,
|
|
277
|
-
) ->
|
|
453
|
+
) -> Self:
|
|
278
454
|
if new_addressable_area_name != NO_CHANGE:
|
|
279
455
|
self.pipette_location = PipetteLocationUpdate(
|
|
280
456
|
pipette_id=pipette_id,
|
|
@@ -283,43 +459,48 @@ class StateUpdate:
|
|
|
283
459
|
),
|
|
284
460
|
new_deck_point=new_deck_point,
|
|
285
461
|
)
|
|
462
|
+
elif new_labware_id == NO_CHANGE or new_well_name == NO_CHANGE:
|
|
463
|
+
self.pipette_location = PipetteLocationUpdate(
|
|
464
|
+
pipette_id=pipette_id,
|
|
465
|
+
new_location=NO_CHANGE,
|
|
466
|
+
new_deck_point=new_deck_point,
|
|
467
|
+
)
|
|
286
468
|
else:
|
|
287
|
-
# These asserts should always pass because of the overloads.
|
|
288
|
-
assert new_labware_id != NO_CHANGE
|
|
289
|
-
assert new_well_name != NO_CHANGE
|
|
290
|
-
|
|
291
469
|
self.pipette_location = PipetteLocationUpdate(
|
|
292
470
|
pipette_id=pipette_id,
|
|
293
471
|
new_location=Well(labware_id=new_labware_id, well_name=new_well_name),
|
|
294
472
|
new_deck_point=new_deck_point,
|
|
295
473
|
)
|
|
474
|
+
return self
|
|
296
475
|
|
|
297
|
-
def clear_all_pipette_locations(self) ->
|
|
476
|
+
def clear_all_pipette_locations(self) -> Self:
|
|
298
477
|
"""Mark all pipettes as having an unknown location."""
|
|
299
478
|
self.pipette_location = CLEAR
|
|
479
|
+
return self
|
|
300
480
|
|
|
301
481
|
def set_labware_location(
|
|
302
|
-
self,
|
|
482
|
+
self: Self,
|
|
303
483
|
*,
|
|
304
484
|
labware_id: str,
|
|
305
485
|
new_location: LabwareLocation,
|
|
306
486
|
new_offset_id: str | None,
|
|
307
|
-
) ->
|
|
487
|
+
) -> Self:
|
|
308
488
|
"""Set a labware's location. See `LabwareLocationUpdate`."""
|
|
309
489
|
self.labware_location = LabwareLocationUpdate(
|
|
310
490
|
labware_id=labware_id,
|
|
311
491
|
new_location=new_location,
|
|
312
492
|
offset_id=new_offset_id,
|
|
313
493
|
)
|
|
494
|
+
return self
|
|
314
495
|
|
|
315
496
|
def set_loaded_labware(
|
|
316
|
-
self,
|
|
497
|
+
self: Self,
|
|
317
498
|
definition: LabwareDefinition,
|
|
318
499
|
labware_id: str,
|
|
319
|
-
offset_id:
|
|
320
|
-
display_name:
|
|
500
|
+
offset_id: str | None,
|
|
501
|
+
display_name: str | None,
|
|
321
502
|
location: LabwareLocation,
|
|
322
|
-
) ->
|
|
503
|
+
) -> Self:
|
|
323
504
|
"""Add a new labware to state. See `LoadedLabwareUpdate`."""
|
|
324
505
|
self.loaded_labware = LoadedLabwareUpdate(
|
|
325
506
|
definition=definition,
|
|
@@ -328,14 +509,47 @@ class StateUpdate:
|
|
|
328
509
|
new_location=location,
|
|
329
510
|
display_name=display_name,
|
|
330
511
|
)
|
|
512
|
+
return self
|
|
513
|
+
|
|
514
|
+
def set_loaded_lid_stack(
|
|
515
|
+
self: Self,
|
|
516
|
+
stack_id: str,
|
|
517
|
+
stack_object_definition: LabwareDefinition,
|
|
518
|
+
stack_location: LabwareLocation,
|
|
519
|
+
labware_definition: LabwareDefinition,
|
|
520
|
+
labware_ids: typing.List[str],
|
|
521
|
+
locations: typing.Dict[str, OnLabwareLocation],
|
|
522
|
+
) -> Self:
|
|
523
|
+
"""Add a new lid stack to state. See `LoadedLidStackUpdate`."""
|
|
524
|
+
self.loaded_lid_stack = LoadedLidStackUpdate(
|
|
525
|
+
stack_id=stack_id,
|
|
526
|
+
stack_object_definition=stack_object_definition,
|
|
527
|
+
stack_location=stack_location,
|
|
528
|
+
definition=labware_definition,
|
|
529
|
+
labware_ids=labware_ids,
|
|
530
|
+
new_locations_by_id=locations,
|
|
531
|
+
)
|
|
532
|
+
return self
|
|
533
|
+
|
|
534
|
+
def set_lid(
|
|
535
|
+
self: Self,
|
|
536
|
+
parent_labware_id: str,
|
|
537
|
+
lid_id: str,
|
|
538
|
+
) -> Self:
|
|
539
|
+
"""Update the labware parent of a loaded or moved lid. See `LabwareLidUpdate`."""
|
|
540
|
+
self.labware_lid = LabwareLidUpdate(
|
|
541
|
+
parent_labware_id=parent_labware_id,
|
|
542
|
+
lid_id=lid_id,
|
|
543
|
+
)
|
|
544
|
+
return self
|
|
331
545
|
|
|
332
546
|
def set_load_pipette(
|
|
333
|
-
self,
|
|
547
|
+
self: Self,
|
|
334
548
|
pipette_id: str,
|
|
335
549
|
pipette_name: PipetteNameType,
|
|
336
550
|
mount: MountType,
|
|
337
|
-
liquid_presence_detection:
|
|
338
|
-
) ->
|
|
551
|
+
liquid_presence_detection: bool | None,
|
|
552
|
+
) -> Self:
|
|
339
553
|
"""Add a new pipette to state. See `LoadPipetteUpdate`."""
|
|
340
554
|
self.loaded_pipette = LoadPipetteUpdate(
|
|
341
555
|
pipette_id=pipette_id,
|
|
@@ -343,61 +557,69 @@ class StateUpdate:
|
|
|
343
557
|
mount=mount,
|
|
344
558
|
liquid_presence_detection=liquid_presence_detection,
|
|
345
559
|
)
|
|
560
|
+
return self
|
|
346
561
|
|
|
347
562
|
def update_pipette_config(
|
|
348
|
-
self,
|
|
563
|
+
self: Self,
|
|
349
564
|
pipette_id: str,
|
|
350
565
|
config: pipette_data_provider.LoadedStaticPipetteData,
|
|
351
566
|
serial_number: str,
|
|
352
|
-
) ->
|
|
567
|
+
) -> Self:
|
|
353
568
|
"""Update a pipette's config. See `PipetteConfigUpdate`."""
|
|
354
569
|
self.pipette_config = PipetteConfigUpdate(
|
|
355
570
|
pipette_id=pipette_id, config=config, serial_number=serial_number
|
|
356
571
|
)
|
|
572
|
+
return self
|
|
357
573
|
|
|
358
|
-
def update_pipette_nozzle(
|
|
574
|
+
def update_pipette_nozzle(
|
|
575
|
+
self: Self, pipette_id: str, nozzle_map: NozzleMap
|
|
576
|
+
) -> Self:
|
|
359
577
|
"""Update a pipette's nozzle map. See `PipetteNozzleMapUpdate`."""
|
|
360
578
|
self.pipette_nozzle_map = PipetteNozzleMapUpdate(
|
|
361
579
|
pipette_id=pipette_id, nozzle_map=nozzle_map
|
|
362
580
|
)
|
|
581
|
+
return self
|
|
363
582
|
|
|
364
583
|
def update_pipette_tip_state(
|
|
365
|
-
self, pipette_id: str, tip_geometry:
|
|
366
|
-
) ->
|
|
584
|
+
self: Self, pipette_id: str, tip_geometry: TipGeometry | None
|
|
585
|
+
) -> Self:
|
|
367
586
|
"""Update a pipette's tip state. See `PipetteTipStateUpdate`."""
|
|
368
587
|
self.pipette_tip_state = PipetteTipStateUpdate(
|
|
369
588
|
pipette_id=pipette_id, tip_geometry=tip_geometry
|
|
370
589
|
)
|
|
590
|
+
return self
|
|
371
591
|
|
|
372
592
|
def mark_tips_as_used(
|
|
373
|
-
self, pipette_id: str, labware_id: str, well_name: str
|
|
374
|
-
) ->
|
|
593
|
+
self: Self, pipette_id: str, labware_id: str, well_name: str
|
|
594
|
+
) -> Self:
|
|
375
595
|
"""Mark tips in a tip rack as used. See `TipsUsedUpdate`."""
|
|
376
596
|
self.tips_used = TipsUsedUpdate(
|
|
377
597
|
pipette_id=pipette_id, labware_id=labware_id, well_name=well_name
|
|
378
598
|
)
|
|
599
|
+
return self
|
|
379
600
|
|
|
380
601
|
def set_liquid_loaded(
|
|
381
|
-
self,
|
|
602
|
+
self: Self,
|
|
382
603
|
labware_id: str,
|
|
383
604
|
volumes: typing.Dict[str, float],
|
|
384
605
|
last_loaded: datetime,
|
|
385
|
-
) ->
|
|
606
|
+
) -> Self:
|
|
386
607
|
"""Add liquid volumes to well state. See `LoadLiquidUpdate`."""
|
|
387
608
|
self.liquid_loaded = LiquidLoadedUpdate(
|
|
388
609
|
labware_id=labware_id,
|
|
389
610
|
volumes=volumes,
|
|
390
611
|
last_loaded=last_loaded,
|
|
391
612
|
)
|
|
613
|
+
return self
|
|
392
614
|
|
|
393
615
|
def set_liquid_probed(
|
|
394
|
-
self,
|
|
616
|
+
self: Self,
|
|
395
617
|
labware_id: str,
|
|
396
618
|
well_name: str,
|
|
397
619
|
last_probed: datetime,
|
|
398
620
|
height: float | ClearType,
|
|
399
621
|
volume: float | ClearType,
|
|
400
|
-
) ->
|
|
622
|
+
) -> Self:
|
|
401
623
|
"""Add a liquid height and volume to well state. See `ProbeLiquidUpdate`."""
|
|
402
624
|
self.liquid_probed = LiquidProbedUpdate(
|
|
403
625
|
labware_id=labware_id,
|
|
@@ -406,19 +628,92 @@ class StateUpdate:
|
|
|
406
628
|
volume=volume,
|
|
407
629
|
last_probed=last_probed,
|
|
408
630
|
)
|
|
631
|
+
return self
|
|
409
632
|
|
|
410
633
|
def set_liquid_operated(
|
|
411
|
-
self
|
|
412
|
-
|
|
634
|
+
self: Self,
|
|
635
|
+
labware_id: str,
|
|
636
|
+
well_names: list[str],
|
|
637
|
+
volume_added: float | ClearType,
|
|
638
|
+
) -> Self:
|
|
413
639
|
"""Update liquid volumes in well state. See `OperateLiquidUpdate`."""
|
|
414
640
|
self.liquid_operated = LiquidOperatedUpdate(
|
|
415
641
|
labware_id=labware_id,
|
|
416
|
-
|
|
642
|
+
well_names=well_names,
|
|
417
643
|
volume_added=volume_added,
|
|
418
644
|
)
|
|
645
|
+
return self
|
|
419
646
|
|
|
420
|
-
def
|
|
647
|
+
def set_fluid_aspirated(self: Self, pipette_id: str, fluid: AspiratedFluid) -> Self:
|
|
648
|
+
"""Update record of fluid held inside a pipette. See `PipetteAspiratedFluidUpdate`."""
|
|
649
|
+
self.pipette_aspirated_fluid = PipetteAspiratedFluidUpdate(
|
|
650
|
+
type="aspirated", pipette_id=pipette_id, fluid=fluid
|
|
651
|
+
)
|
|
652
|
+
return self
|
|
653
|
+
|
|
654
|
+
def set_fluid_ejected(self: Self, pipette_id: str, volume: float) -> Self:
|
|
655
|
+
"""Update record of fluid held inside a pipette. See `PipetteEjectedFluidUpdate`."""
|
|
656
|
+
self.pipette_aspirated_fluid = PipetteEjectedFluidUpdate(
|
|
657
|
+
type="ejected", pipette_id=pipette_id, volume=volume
|
|
658
|
+
)
|
|
659
|
+
return self
|
|
660
|
+
|
|
661
|
+
def set_fluid_unknown(self: Self, pipette_id: str) -> Self:
|
|
662
|
+
"""Update record of fluid held inside a pipette. See `PipetteUnknownFluidUpdate`."""
|
|
663
|
+
self.pipette_aspirated_fluid = PipetteUnknownFluidUpdate(
|
|
664
|
+
type="unknown", pipette_id=pipette_id
|
|
665
|
+
)
|
|
666
|
+
return self
|
|
667
|
+
|
|
668
|
+
def set_fluid_empty(self: Self, pipette_id: str) -> Self:
|
|
669
|
+
"""Update record fo fluid held inside a pipette. See `PipetteEmptyFluidUpdate`."""
|
|
670
|
+
self.pipette_aspirated_fluid = PipetteEmptyFluidUpdate(
|
|
671
|
+
type="empty", pipette_id=pipette_id
|
|
672
|
+
)
|
|
673
|
+
return self
|
|
674
|
+
|
|
675
|
+
def set_absorbance_reader_lid(self: Self, module_id: str, is_lid_on: bool) -> Self:
|
|
421
676
|
"""Update an absorbance reader's lid location. See `AbsorbanceReaderLidUpdate`."""
|
|
422
|
-
self.
|
|
423
|
-
|
|
677
|
+
assert self.absorbance_reader_state_update == NO_CHANGE
|
|
678
|
+
self.absorbance_reader_state_update = AbsorbanceReaderStateUpdate(
|
|
679
|
+
module_id=module_id,
|
|
680
|
+
absorbance_reader_lid=AbsorbanceReaderLidUpdate(is_lid_on=is_lid_on),
|
|
681
|
+
)
|
|
682
|
+
return self
|
|
683
|
+
|
|
684
|
+
def set_absorbance_reader_data(
|
|
685
|
+
self, module_id: str, read_result: typing.Dict[int, typing.Dict[str, float]]
|
|
686
|
+
) -> Self:
|
|
687
|
+
"""Update an absorbance reader's read data. See `AbsorbanceReaderReadDataUpdate`."""
|
|
688
|
+
assert self.absorbance_reader_state_update == NO_CHANGE
|
|
689
|
+
self.absorbance_reader_state_update = AbsorbanceReaderStateUpdate(
|
|
690
|
+
module_id=module_id,
|
|
691
|
+
absorbance_reader_data=AbsorbanceReaderDataUpdate(read_result=read_result),
|
|
692
|
+
)
|
|
693
|
+
return self
|
|
694
|
+
|
|
695
|
+
def initialize_absorbance_reader(
|
|
696
|
+
self,
|
|
697
|
+
module_id: str,
|
|
698
|
+
measure_mode: ABSMeasureMode,
|
|
699
|
+
sample_wave_lengths: typing.List[int],
|
|
700
|
+
reference_wave_length: typing.Optional[int],
|
|
701
|
+
) -> Self:
|
|
702
|
+
"""Initialize absorbance reader."""
|
|
703
|
+
assert self.absorbance_reader_state_update == NO_CHANGE
|
|
704
|
+
self.absorbance_reader_state_update = AbsorbanceReaderStateUpdate(
|
|
705
|
+
module_id=module_id,
|
|
706
|
+
initialize_absorbance_reader_update=AbsorbanceReaderInitializeUpdate(
|
|
707
|
+
measure_mode=measure_mode,
|
|
708
|
+
sample_wave_lengths=sample_wave_lengths,
|
|
709
|
+
reference_wave_length=reference_wave_length,
|
|
710
|
+
),
|
|
711
|
+
)
|
|
712
|
+
return self
|
|
713
|
+
|
|
714
|
+
def set_addressable_area_used(self: Self, addressable_area_name: str) -> Self:
|
|
715
|
+
"""Mark that an addressable area has been used. See `AddressableAreaUsedUpdate`."""
|
|
716
|
+
self.addressable_area_used = AddressableAreaUsedUpdate(
|
|
717
|
+
addressable_area_name=addressable_area_name
|
|
424
718
|
)
|
|
719
|
+
return self
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Basic well data state and store."""
|
|
2
|
+
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
from typing import Dict, List, Union, Iterator, Optional, Tuple, overload, TypeVar
|
|
4
5
|
|
|
@@ -54,7 +55,7 @@ class WellStore(HasState[WellState], HandlesActions):
|
|
|
54
55
|
labware_id = state_update.labware_id
|
|
55
56
|
if labware_id not in self._state.loaded_volumes:
|
|
56
57
|
self._state.loaded_volumes[labware_id] = {}
|
|
57
|
-
for
|
|
58
|
+
for well, volume in state_update.volumes.items():
|
|
58
59
|
self._state.loaded_volumes[labware_id][well] = LoadedVolumeInfo(
|
|
59
60
|
volume=_none_from_clear(volume),
|
|
60
61
|
last_loaded=state_update.last_loaded,
|
|
@@ -83,19 +84,28 @@ class WellStore(HasState[WellState], HandlesActions):
|
|
|
83
84
|
def _handle_liquid_operated_update(
|
|
84
85
|
self, state_update: update_types.LiquidOperatedUpdate
|
|
85
86
|
) -> None:
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
for well_name in state_update.well_names:
|
|
88
|
+
self._handle_well_operated(
|
|
89
|
+
state_update.labware_id, well_name, state_update.volume_added
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def _handle_well_operated(
|
|
93
|
+
self,
|
|
94
|
+
labware_id: str,
|
|
95
|
+
well_name: str,
|
|
96
|
+
volume_added: float | update_types.ClearType,
|
|
97
|
+
) -> None:
|
|
88
98
|
if (
|
|
89
99
|
labware_id in self._state.loaded_volumes
|
|
90
100
|
and well_name in self._state.loaded_volumes[labware_id]
|
|
91
101
|
):
|
|
92
|
-
if
|
|
102
|
+
if volume_added is update_types.CLEAR:
|
|
93
103
|
del self._state.loaded_volumes[labware_id][well_name]
|
|
94
104
|
else:
|
|
95
105
|
prev_loaded_vol_info = self._state.loaded_volumes[labware_id][well_name]
|
|
96
106
|
assert prev_loaded_vol_info.volume is not None
|
|
97
107
|
self._state.loaded_volumes[labware_id][well_name] = LoadedVolumeInfo(
|
|
98
|
-
volume=prev_loaded_vol_info.volume +
|
|
108
|
+
volume=prev_loaded_vol_info.volume + volume_added,
|
|
99
109
|
last_loaded=prev_loaded_vol_info.last_loaded,
|
|
100
110
|
operations_since_load=prev_loaded_vol_info.operations_since_load
|
|
101
111
|
+ 1,
|
|
@@ -109,16 +119,14 @@ class WellStore(HasState[WellState], HandlesActions):
|
|
|
109
119
|
labware_id in self._state.probed_volumes
|
|
110
120
|
and well_name in self._state.probed_volumes[labware_id]
|
|
111
121
|
):
|
|
112
|
-
if
|
|
122
|
+
if volume_added is update_types.CLEAR:
|
|
113
123
|
del self._state.probed_volumes[labware_id][well_name]
|
|
114
124
|
else:
|
|
115
125
|
prev_probed_vol_info = self._state.probed_volumes[labware_id][well_name]
|
|
116
126
|
if prev_probed_vol_info.volume is None:
|
|
117
127
|
new_vol_info: float | None = None
|
|
118
128
|
else:
|
|
119
|
-
new_vol_info =
|
|
120
|
-
prev_probed_vol_info.volume + state_update.volume_added
|
|
121
|
-
)
|
|
129
|
+
new_vol_info = prev_probed_vol_info.volume + volume_added
|
|
122
130
|
self._state.probed_volumes[labware_id][well_name] = ProbedVolumeInfo(
|
|
123
131
|
volume=new_vol_info,
|
|
124
132
|
last_probed=prev_probed_vol_info.last_probed,
|
|
@@ -127,7 +135,7 @@ class WellStore(HasState[WellState], HandlesActions):
|
|
|
127
135
|
)
|
|
128
136
|
|
|
129
137
|
|
|
130
|
-
class WellView
|
|
138
|
+
class WellView:
|
|
131
139
|
"""Read-only well state view."""
|
|
132
140
|
|
|
133
141
|
_state: WellState
|
|
@@ -214,7 +222,7 @@ def _volume_from_info(info: Optional[LoadedVolumeInfo]) -> Optional[float]:
|
|
|
214
222
|
|
|
215
223
|
|
|
216
224
|
def _volume_from_info(
|
|
217
|
-
info: Union[ProbedVolumeInfo, LoadedVolumeInfo, None]
|
|
225
|
+
info: Union[ProbedVolumeInfo, LoadedVolumeInfo, None],
|
|
218
226
|
) -> Optional[float]:
|
|
219
227
|
if info is None:
|
|
220
228
|
return None
|