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,9 +1,10 @@
|
|
|
1
1
|
"""Command models to wait for a Heater-Shaker Module's target temperature."""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
-
from typing import Optional, TYPE_CHECKING
|
|
4
|
-
from typing_extensions import Literal, Type
|
|
3
|
+
from typing import Optional, TYPE_CHECKING, Any
|
|
5
4
|
|
|
5
|
+
from typing_extensions import Literal, Type
|
|
6
6
|
from pydantic import BaseModel, Field
|
|
7
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
7
8
|
|
|
8
9
|
from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
9
10
|
from ...errors.error_occurrence import ErrorOccurrence
|
|
@@ -16,11 +17,15 @@ if TYPE_CHECKING:
|
|
|
16
17
|
WaitForTemperatureCommandType = Literal["heaterShaker/waitForTemperature"]
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
21
|
+
s.pop("default", None)
|
|
22
|
+
|
|
23
|
+
|
|
19
24
|
class WaitForTemperatureParams(BaseModel):
|
|
20
25
|
"""Input parameters to wait for a Heater-Shaker's target temperature."""
|
|
21
26
|
|
|
22
27
|
moduleId: str = Field(..., description="Unique ID of the Heater-Shaker Module.")
|
|
23
|
-
celsius:
|
|
28
|
+
celsius: float | SkipJsonSchema[None] = Field(
|
|
24
29
|
None,
|
|
25
30
|
description="Target temperature in °C. If not specified, will "
|
|
26
31
|
"default to the module's target temperature. "
|
|
@@ -28,6 +33,7 @@ class WaitForTemperatureParams(BaseModel):
|
|
|
28
33
|
"could lead to unpredictable behavior and hence is not "
|
|
29
34
|
"recommended for use. This parameter can be removed in a "
|
|
30
35
|
"future version without prior notice.",
|
|
36
|
+
json_schema_extra=_remove_default,
|
|
31
37
|
)
|
|
32
38
|
|
|
33
39
|
|
|
@@ -82,7 +88,7 @@ class WaitForTemperature(
|
|
|
82
88
|
|
|
83
89
|
commandType: WaitForTemperatureCommandType = "heaterShaker/waitForTemperature"
|
|
84
90
|
params: WaitForTemperatureParams
|
|
85
|
-
result: Optional[WaitForTemperatureResult]
|
|
91
|
+
result: Optional[WaitForTemperatureResult] = None
|
|
86
92
|
|
|
87
93
|
_ImplementationCls: Type[WaitForTemperatureImpl] = WaitForTemperatureImpl
|
|
88
94
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"""Home command payload, result, and implementation models."""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
+
from typing import TYPE_CHECKING, Optional, List, Type, Any
|
|
4
|
+
|
|
3
5
|
from pydantic import BaseModel, Field
|
|
4
|
-
from
|
|
6
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
7
|
+
|
|
5
8
|
from typing_extensions import Literal
|
|
6
9
|
|
|
7
10
|
from opentrons.types import MountType
|
|
@@ -17,24 +20,30 @@ if TYPE_CHECKING:
|
|
|
17
20
|
HomeCommandType = Literal["home"]
|
|
18
21
|
|
|
19
22
|
|
|
23
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
24
|
+
s.pop("default", None)
|
|
25
|
+
|
|
26
|
+
|
|
20
27
|
class HomeParams(BaseModel):
|
|
21
28
|
"""Payload required for a Home command."""
|
|
22
29
|
|
|
23
|
-
axes:
|
|
30
|
+
axes: List[MotorAxis] | SkipJsonSchema[None] = Field(
|
|
24
31
|
None,
|
|
25
32
|
description=(
|
|
26
33
|
"Axes to return to their home positions. If omitted,"
|
|
27
34
|
" will home all motors. Extra axes may be implicitly homed"
|
|
28
35
|
" to ensure accurate homing of the explicitly specified axes."
|
|
29
36
|
),
|
|
37
|
+
json_schema_extra=_remove_default,
|
|
30
38
|
)
|
|
31
|
-
skipIfMountPositionOk:
|
|
39
|
+
skipIfMountPositionOk: MountType | SkipJsonSchema[None] = Field(
|
|
32
40
|
None,
|
|
33
41
|
description=(
|
|
34
42
|
"If this parameter is provided, the gantry will only be homed if the"
|
|
35
43
|
" specified mount has an invalid position. If omitted, the homing action"
|
|
36
44
|
" will be executed unconditionally."
|
|
37
45
|
),
|
|
46
|
+
json_schema_extra=_remove_default,
|
|
38
47
|
)
|
|
39
48
|
|
|
40
49
|
|
|
@@ -77,7 +86,7 @@ class Home(BaseCommand[HomeParams, HomeResult, ErrorOccurrence]):
|
|
|
77
86
|
|
|
78
87
|
commandType: HomeCommandType = "home"
|
|
79
88
|
params: HomeParams
|
|
80
|
-
result: Optional[HomeResult]
|
|
89
|
+
result: Optional[HomeResult] = None
|
|
81
90
|
|
|
82
91
|
_ImplementationCls: Type[HomeImplementation] = HomeImplementation
|
|
83
92
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"""The liquidProbe and tryLiquidProbe commands."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
|
-
from typing import TYPE_CHECKING, NamedTuple, Optional, Type, Union
|
|
5
|
-
from typing_extensions import Literal
|
|
4
|
+
from typing import TYPE_CHECKING, NamedTuple, Optional, Type, Union, Any
|
|
6
5
|
|
|
6
|
+
from typing_extensions import Literal
|
|
7
7
|
from pydantic import Field
|
|
8
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
8
9
|
|
|
9
10
|
from opentrons.protocol_engine.state import update_types
|
|
10
11
|
from opentrons.protocol_engine.errors.exceptions import (
|
|
@@ -12,6 +13,7 @@ from opentrons.protocol_engine.errors.exceptions import (
|
|
|
12
13
|
PipetteNotReadyToAspirateError,
|
|
13
14
|
TipNotEmptyError,
|
|
14
15
|
IncompleteLabwareDefinitionError,
|
|
16
|
+
TipNotAttachedError,
|
|
15
17
|
)
|
|
16
18
|
from opentrons.types import MountType
|
|
17
19
|
from opentrons_shared_data.errors.exceptions import (
|
|
@@ -23,8 +25,12 @@ from ..types import DeckPoint
|
|
|
23
25
|
from .pipetting_common import (
|
|
24
26
|
LiquidNotFoundError,
|
|
25
27
|
PipetteIdMixin,
|
|
28
|
+
)
|
|
29
|
+
from .movement_common import (
|
|
26
30
|
WellLocationMixin,
|
|
27
31
|
DestinationPositionResult,
|
|
32
|
+
StallOrCollisionError,
|
|
33
|
+
move_to_well,
|
|
28
34
|
)
|
|
29
35
|
from .command import (
|
|
30
36
|
AbstractCommandImpl,
|
|
@@ -42,6 +48,10 @@ if TYPE_CHECKING:
|
|
|
42
48
|
from ..state.state import StateView
|
|
43
49
|
|
|
44
50
|
|
|
51
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
52
|
+
s.pop("default", None)
|
|
53
|
+
|
|
54
|
+
|
|
45
55
|
LiquidProbeCommandType = Literal["liquidProbe"]
|
|
46
56
|
TryLiquidProbeCommandType = Literal["tryLiquidProbe"]
|
|
47
57
|
|
|
@@ -77,20 +87,23 @@ class LiquidProbeResult(DestinationPositionResult):
|
|
|
77
87
|
class TryLiquidProbeResult(DestinationPositionResult):
|
|
78
88
|
"""Result data from the execution of a `tryLiquidProbe` command."""
|
|
79
89
|
|
|
80
|
-
z_position:
|
|
90
|
+
z_position: float | SkipJsonSchema[None] = Field(
|
|
81
91
|
...,
|
|
82
92
|
description=(
|
|
83
93
|
"The Z coordinate, in mm, of the found liquid in deck space."
|
|
84
94
|
" If no liquid was found, `null` or omitted."
|
|
85
95
|
),
|
|
96
|
+
json_schema_extra=_remove_default,
|
|
86
97
|
)
|
|
87
98
|
|
|
88
99
|
|
|
89
100
|
_LiquidProbeExecuteReturn = Union[
|
|
90
101
|
SuccessData[LiquidProbeResult],
|
|
91
|
-
DefinedErrorData[LiquidNotFoundError],
|
|
102
|
+
DefinedErrorData[LiquidNotFoundError] | DefinedErrorData[StallOrCollisionError],
|
|
92
103
|
]
|
|
93
|
-
_TryLiquidProbeExecuteReturn =
|
|
104
|
+
_TryLiquidProbeExecuteReturn = (
|
|
105
|
+
SuccessData[TryLiquidProbeResult] | DefinedErrorData[StallOrCollisionError]
|
|
106
|
+
)
|
|
94
107
|
|
|
95
108
|
|
|
96
109
|
class _ExecuteCommonResult(NamedTuple):
|
|
@@ -107,13 +120,12 @@ async def _execute_common(
|
|
|
107
120
|
state_view: StateView,
|
|
108
121
|
movement: MovementHandler,
|
|
109
122
|
pipetting: PipettingHandler,
|
|
123
|
+
model_utils: ModelUtils,
|
|
110
124
|
params: _CommonParams,
|
|
111
|
-
) -> _ExecuteCommonResult:
|
|
125
|
+
) -> _ExecuteCommonResult | DefinedErrorData[StallOrCollisionError]:
|
|
112
126
|
pipette_id = params.pipetteId
|
|
113
127
|
labware_id = params.labwareId
|
|
114
128
|
well_name = params.wellName
|
|
115
|
-
|
|
116
|
-
state_update = update_types.StateUpdate()
|
|
117
129
|
if (
|
|
118
130
|
"pressure"
|
|
119
131
|
not in state_view.pipettes.get_config(pipette_id).available_sensors.sensors
|
|
@@ -122,6 +134,11 @@ async def _execute_common(
|
|
|
122
134
|
"Pressure sensor not available for this pipette"
|
|
123
135
|
)
|
|
124
136
|
|
|
137
|
+
if not state_view.pipettes.get_nozzle_configuration_supports_lld(pipette_id):
|
|
138
|
+
raise TipNotAttachedError(
|
|
139
|
+
"Either the front right or back left nozzle must have a tip attached to probe liquid height."
|
|
140
|
+
)
|
|
141
|
+
|
|
125
142
|
# May raise TipNotAttachedError.
|
|
126
143
|
aspirated_volume = state_view.pipettes.get_aspirated_volume(pipette_id)
|
|
127
144
|
|
|
@@ -145,20 +162,16 @@ async def _execute_common(
|
|
|
145
162
|
)
|
|
146
163
|
|
|
147
164
|
# liquid_probe process start position
|
|
148
|
-
|
|
165
|
+
move_result = await move_to_well(
|
|
166
|
+
movement=movement,
|
|
167
|
+
model_utils=model_utils,
|
|
149
168
|
pipette_id=pipette_id,
|
|
150
169
|
labware_id=labware_id,
|
|
151
170
|
well_name=well_name,
|
|
152
171
|
well_location=params.wellLocation,
|
|
153
172
|
)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
pipette_id=pipette_id,
|
|
157
|
-
new_labware_id=labware_id,
|
|
158
|
-
new_well_name=well_name,
|
|
159
|
-
new_deck_point=deck_point,
|
|
160
|
-
)
|
|
161
|
-
|
|
173
|
+
if isinstance(move_result, DefinedErrorData):
|
|
174
|
+
return move_result
|
|
162
175
|
try:
|
|
163
176
|
z_pos = await pipetting.liquid_probe_in_place(
|
|
164
177
|
pipette_id=pipette_id,
|
|
@@ -168,11 +181,15 @@ async def _execute_common(
|
|
|
168
181
|
)
|
|
169
182
|
except PipetteLiquidNotFoundError as exception:
|
|
170
183
|
return _ExecuteCommonResult(
|
|
171
|
-
z_pos_or_error=exception,
|
|
184
|
+
z_pos_or_error=exception,
|
|
185
|
+
state_update=move_result.state_update,
|
|
186
|
+
deck_point=move_result.public.position,
|
|
172
187
|
)
|
|
173
188
|
else:
|
|
174
189
|
return _ExecuteCommonResult(
|
|
175
|
-
z_pos_or_error=z_pos,
|
|
190
|
+
z_pos_or_error=z_pos,
|
|
191
|
+
state_update=move_result.state_update,
|
|
192
|
+
deck_point=move_result.public.position,
|
|
176
193
|
)
|
|
177
194
|
|
|
178
195
|
|
|
@@ -210,9 +227,16 @@ class LiquidProbeImplementation(
|
|
|
210
227
|
MustHomeError: as an undefined error, if the plunger is not in a valid
|
|
211
228
|
position.
|
|
212
229
|
"""
|
|
213
|
-
|
|
214
|
-
self._state_view,
|
|
230
|
+
result = await _execute_common(
|
|
231
|
+
state_view=self._state_view,
|
|
232
|
+
movement=self._movement,
|
|
233
|
+
pipetting=self._pipetting,
|
|
234
|
+
model_utils=self._model_utils,
|
|
235
|
+
params=params,
|
|
215
236
|
)
|
|
237
|
+
if isinstance(result, DefinedErrorData):
|
|
238
|
+
return result
|
|
239
|
+
z_pos_or_error, state_update, deck_point = result
|
|
216
240
|
if isinstance(z_pos_or_error, PipetteLiquidNotFoundError):
|
|
217
241
|
state_update.set_liquid_probed(
|
|
218
242
|
labware_id=params.labwareId,
|
|
@@ -286,9 +310,16 @@ class TryLiquidProbeImplementation(
|
|
|
286
310
|
found, `tryLiquidProbe` returns a success result with `z_position=null` instead
|
|
287
311
|
of a defined error.
|
|
288
312
|
"""
|
|
289
|
-
|
|
290
|
-
self._state_view,
|
|
313
|
+
result = await _execute_common(
|
|
314
|
+
state_view=self._state_view,
|
|
315
|
+
movement=self._movement,
|
|
316
|
+
pipetting=self._pipetting,
|
|
317
|
+
model_utils=self._model_utils,
|
|
318
|
+
params=params,
|
|
291
319
|
)
|
|
320
|
+
if isinstance(result, DefinedErrorData):
|
|
321
|
+
return result
|
|
322
|
+
z_pos_or_error, state_update, deck_point = result
|
|
292
323
|
|
|
293
324
|
if isinstance(z_pos_or_error, PipetteLiquidNotFoundError):
|
|
294
325
|
z_pos = None
|
|
@@ -320,7 +351,11 @@ class TryLiquidProbeImplementation(
|
|
|
320
351
|
|
|
321
352
|
|
|
322
353
|
class LiquidProbe(
|
|
323
|
-
BaseCommand[
|
|
354
|
+
BaseCommand[
|
|
355
|
+
LiquidProbeParams,
|
|
356
|
+
LiquidProbeResult,
|
|
357
|
+
LiquidNotFoundError | StallOrCollisionError,
|
|
358
|
+
]
|
|
324
359
|
):
|
|
325
360
|
"""The model for a full `liquidProbe` command."""
|
|
326
361
|
|
|
@@ -332,7 +367,7 @@ class LiquidProbe(
|
|
|
332
367
|
|
|
333
368
|
|
|
334
369
|
class TryLiquidProbe(
|
|
335
|
-
BaseCommand[TryLiquidProbeParams, TryLiquidProbeResult,
|
|
370
|
+
BaseCommand[TryLiquidProbeParams, TryLiquidProbeResult, StallOrCollisionError]
|
|
336
371
|
):
|
|
337
372
|
"""The model for a full `tryLiquidProbe` command."""
|
|
338
373
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"""Load labware command request, result, and implementation models."""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
+
from typing import TYPE_CHECKING, Optional, Type, Any
|
|
4
|
+
|
|
3
5
|
from pydantic import BaseModel, Field
|
|
4
|
-
from
|
|
6
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
5
7
|
from typing_extensions import Literal
|
|
6
8
|
|
|
7
9
|
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
@@ -29,6 +31,10 @@ if TYPE_CHECKING:
|
|
|
29
31
|
LoadLabwareCommandType = Literal["loadLabware"]
|
|
30
32
|
|
|
31
33
|
|
|
34
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
35
|
+
s.pop("default", None)
|
|
36
|
+
|
|
37
|
+
|
|
32
38
|
class LoadLabwareParams(BaseModel):
|
|
33
39
|
"""Payload required to load a labware into a slot."""
|
|
34
40
|
|
|
@@ -48,18 +54,20 @@ class LoadLabwareParams(BaseModel):
|
|
|
48
54
|
...,
|
|
49
55
|
description="The labware definition version.",
|
|
50
56
|
)
|
|
51
|
-
labwareId:
|
|
57
|
+
labwareId: str | SkipJsonSchema[None] = Field(
|
|
52
58
|
None,
|
|
53
59
|
description="An optional ID to assign to this labware. If None, an ID "
|
|
54
60
|
"will be generated.",
|
|
61
|
+
json_schema_extra=_remove_default,
|
|
55
62
|
)
|
|
56
|
-
displayName:
|
|
63
|
+
displayName: str | SkipJsonSchema[None] = Field(
|
|
57
64
|
None,
|
|
58
65
|
description="An optional user-specified display name "
|
|
59
66
|
"or label for this labware.",
|
|
60
67
|
# NOTE: v4/5 JSON protocols will always have a displayName which will be the
|
|
61
68
|
# user-specified label OR the displayName property of the labware's definition.
|
|
62
69
|
# TODO: Make sure v6 JSON protocols don't do that.
|
|
70
|
+
json_schema_extra=_remove_default,
|
|
63
71
|
)
|
|
64
72
|
|
|
65
73
|
|
|
@@ -104,6 +112,8 @@ class LoadLabwareImplementation(
|
|
|
104
112
|
self, params: LoadLabwareParams
|
|
105
113
|
) -> SuccessData[LoadLabwareResult]:
|
|
106
114
|
"""Load definition and calibration data necessary for a labware."""
|
|
115
|
+
state_update = StateUpdate()
|
|
116
|
+
|
|
107
117
|
# TODO (tz, 8-15-2023): extend column validation to column 1 when working
|
|
108
118
|
# on https://opentrons.atlassian.net/browse/RSS-258 and completing
|
|
109
119
|
# https://opentrons.atlassian.net/browse/RSS-255
|
|
@@ -128,10 +138,12 @@ class LoadLabwareImplementation(
|
|
|
128
138
|
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
129
139
|
area_name
|
|
130
140
|
)
|
|
141
|
+
state_update.set_addressable_area_used(area_name)
|
|
131
142
|
elif isinstance(params.location, DeckSlotLocation):
|
|
132
143
|
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
133
144
|
params.location.slotName.id
|
|
134
145
|
)
|
|
146
|
+
state_update.set_addressable_area_used(params.location.slotName.id)
|
|
135
147
|
|
|
136
148
|
verified_location = self._state_view.geometry.ensure_location_not_occupied(
|
|
137
149
|
params.location
|
|
@@ -144,8 +156,6 @@ class LoadLabwareImplementation(
|
|
|
144
156
|
labware_id=params.labwareId,
|
|
145
157
|
)
|
|
146
158
|
|
|
147
|
-
state_update = StateUpdate()
|
|
148
|
-
|
|
149
159
|
state_update.set_loaded_labware(
|
|
150
160
|
labware_id=loaded_labware.labware_id,
|
|
151
161
|
offset_id=loaded_labware.offsetId,
|
|
@@ -162,6 +172,19 @@ class LoadLabwareImplementation(
|
|
|
162
172
|
top_labware_definition=loaded_labware.definition,
|
|
163
173
|
bottom_labware_id=verified_location.labwareId,
|
|
164
174
|
)
|
|
175
|
+
# Validate load location is valid for lids
|
|
176
|
+
if (
|
|
177
|
+
labware_validation.validate_definition_is_lid(
|
|
178
|
+
definition=loaded_labware.definition
|
|
179
|
+
)
|
|
180
|
+
and loaded_labware.definition.compatibleParentLabware is not None
|
|
181
|
+
and self._state_view.labware.get_load_name(verified_location.labwareId)
|
|
182
|
+
not in loaded_labware.definition.compatibleParentLabware
|
|
183
|
+
):
|
|
184
|
+
raise ValueError(
|
|
185
|
+
f"Labware Lid {params.loadName} may not be loaded on parent labware {self._state_view.labware.get_display_name(verified_location.labwareId)}."
|
|
186
|
+
)
|
|
187
|
+
|
|
165
188
|
# Validate labware for the absorbance reader
|
|
166
189
|
elif isinstance(params.location, ModuleLocation):
|
|
167
190
|
module = self._state_view.modules.get(params.location.moduleId)
|
|
@@ -169,7 +192,6 @@ class LoadLabwareImplementation(
|
|
|
169
192
|
self._state_view.labware.raise_if_labware_incompatible_with_plate_reader(
|
|
170
193
|
loaded_labware.definition
|
|
171
194
|
)
|
|
172
|
-
|
|
173
195
|
return SuccessData(
|
|
174
196
|
public=LoadLabwareResult(
|
|
175
197
|
labwareId=loaded_labware.labware_id,
|
|
@@ -185,7 +207,7 @@ class LoadLabware(BaseCommand[LoadLabwareParams, LoadLabwareResult, ErrorOccurre
|
|
|
185
207
|
|
|
186
208
|
commandType: LoadLabwareCommandType = "loadLabware"
|
|
187
209
|
params: LoadLabwareParams
|
|
188
|
-
result: Optional[LoadLabwareResult]
|
|
210
|
+
result: Optional[LoadLabwareResult] = None
|
|
189
211
|
|
|
190
212
|
_ImplementationCls: Type[LoadLabwareImplementation] = LoadLabwareImplementation
|
|
191
213
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""Load lid command request, result, and implementation models."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
from typing import TYPE_CHECKING, Optional, Type
|
|
5
|
+
from typing_extensions import Literal
|
|
6
|
+
|
|
7
|
+
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
8
|
+
|
|
9
|
+
from ..errors import LabwareCannotBeStackedError, LabwareIsNotAllowedInLocationError
|
|
10
|
+
from ..resources import labware_validation
|
|
11
|
+
from ..types import (
|
|
12
|
+
LabwareLocation,
|
|
13
|
+
OnLabwareLocation,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
17
|
+
from ..errors.error_occurrence import ErrorOccurrence
|
|
18
|
+
from ..state.update_types import StateUpdate
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from ..state.state import StateView
|
|
22
|
+
from ..execution import EquipmentHandler
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
LoadLidCommandType = Literal["loadLid"]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class LoadLidParams(BaseModel):
|
|
29
|
+
"""Payload required to load a lid onto a labware."""
|
|
30
|
+
|
|
31
|
+
location: LabwareLocation = Field(
|
|
32
|
+
...,
|
|
33
|
+
description="Labware the lid should be loaded onto.",
|
|
34
|
+
)
|
|
35
|
+
loadName: str = Field(
|
|
36
|
+
...,
|
|
37
|
+
description="Name used to reference a lid labware definition.",
|
|
38
|
+
)
|
|
39
|
+
namespace: str = Field(
|
|
40
|
+
...,
|
|
41
|
+
description="The namespace the lid labware definition belongs to.",
|
|
42
|
+
)
|
|
43
|
+
version: int = Field(
|
|
44
|
+
...,
|
|
45
|
+
description="The lid labware definition version.",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class LoadLidResult(BaseModel):
|
|
50
|
+
"""Result data from the execution of a LoadLabware command."""
|
|
51
|
+
|
|
52
|
+
labwareId: str = Field(
|
|
53
|
+
...,
|
|
54
|
+
description="An ID to reference this lid labware in subsequent commands.",
|
|
55
|
+
)
|
|
56
|
+
definition: LabwareDefinition = Field(
|
|
57
|
+
...,
|
|
58
|
+
description="The full definition data for this lid labware.",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class LoadLidImplementation(
|
|
63
|
+
AbstractCommandImpl[LoadLidParams, SuccessData[LoadLidResult]]
|
|
64
|
+
):
|
|
65
|
+
"""Load lid command implementation."""
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self, equipment: EquipmentHandler, state_view: StateView, **kwargs: object
|
|
69
|
+
) -> None:
|
|
70
|
+
self._equipment = equipment
|
|
71
|
+
self._state_view = state_view
|
|
72
|
+
|
|
73
|
+
async def execute(self, params: LoadLidParams) -> SuccessData[LoadLidResult]:
|
|
74
|
+
"""Load definition and calibration data necessary for a lid."""
|
|
75
|
+
if not isinstance(params.location, OnLabwareLocation):
|
|
76
|
+
raise LabwareIsNotAllowedInLocationError(
|
|
77
|
+
"Lid Labware is only allowed to be loaded on top of a labware. Try `load_lid_stack(...)` to load lids without parent labware."
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
verified_location = self._state_view.geometry.ensure_location_not_occupied(
|
|
81
|
+
params.location
|
|
82
|
+
)
|
|
83
|
+
loaded_labware = await self._equipment.load_labware(
|
|
84
|
+
load_name=params.loadName,
|
|
85
|
+
namespace=params.namespace,
|
|
86
|
+
version=params.version,
|
|
87
|
+
location=verified_location,
|
|
88
|
+
labware_id=None,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# TODO(chb 2024-12-12) these validation checks happen after the labware is loaded, because they rely on
|
|
92
|
+
# on the definition. In practice this will not cause any issues since they will raise protocol ending
|
|
93
|
+
# exception, but for correctness should be refactored to do this check beforehand.
|
|
94
|
+
if not labware_validation.validate_definition_is_lid(loaded_labware.definition):
|
|
95
|
+
raise LabwareCannotBeStackedError(
|
|
96
|
+
f"Labware {params.loadName} is not a Lid and cannot be loaded onto {self._state_view.labware.get_display_name(params.location.labwareId)}."
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
state_update = StateUpdate()
|
|
100
|
+
|
|
101
|
+
# In the case of lids being loaded on top of other labware, set the parent labware's lid
|
|
102
|
+
state_update.set_lid(
|
|
103
|
+
parent_labware_id=params.location.labwareId,
|
|
104
|
+
lid_id=loaded_labware.labware_id,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
state_update.set_loaded_labware(
|
|
108
|
+
labware_id=loaded_labware.labware_id,
|
|
109
|
+
offset_id=loaded_labware.offsetId,
|
|
110
|
+
definition=loaded_labware.definition,
|
|
111
|
+
location=verified_location,
|
|
112
|
+
display_name=None,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if isinstance(verified_location, OnLabwareLocation):
|
|
116
|
+
self._state_view.labware.raise_if_labware_cannot_be_stacked(
|
|
117
|
+
top_labware_definition=loaded_labware.definition,
|
|
118
|
+
bottom_labware_id=verified_location.labwareId,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
return SuccessData(
|
|
122
|
+
public=LoadLidResult(
|
|
123
|
+
labwareId=loaded_labware.labware_id,
|
|
124
|
+
definition=loaded_labware.definition,
|
|
125
|
+
),
|
|
126
|
+
state_update=state_update,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class LoadLid(BaseCommand[LoadLidParams, LoadLidResult, ErrorOccurrence]):
|
|
131
|
+
"""Load lid command resource model."""
|
|
132
|
+
|
|
133
|
+
commandType: LoadLidCommandType = "loadLid"
|
|
134
|
+
params: LoadLidParams
|
|
135
|
+
result: Optional[LoadLidResult]
|
|
136
|
+
|
|
137
|
+
_ImplementationCls: Type[LoadLidImplementation] = LoadLidImplementation
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class LoadLidCreate(BaseCommandCreate[LoadLidParams]):
|
|
141
|
+
"""Load lid command creation request."""
|
|
142
|
+
|
|
143
|
+
commandType: LoadLidCommandType = "loadLid"
|
|
144
|
+
params: LoadLidParams
|
|
145
|
+
|
|
146
|
+
_CommandCls: Type[LoadLid] = LoadLid
|