opentrons 8.2.0a4__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.
Files changed (229) hide show
  1. opentrons/calibration_storage/deck_configuration.py +3 -3
  2. opentrons/calibration_storage/file_operators.py +3 -3
  3. opentrons/calibration_storage/helpers.py +3 -1
  4. opentrons/calibration_storage/ot2/models/v1.py +16 -29
  5. opentrons/calibration_storage/ot2/tip_length.py +7 -4
  6. opentrons/calibration_storage/ot3/models/v1.py +14 -23
  7. opentrons/cli/analyze.py +18 -6
  8. opentrons/config/defaults_ot3.py +1 -0
  9. opentrons/drivers/asyncio/communication/__init__.py +2 -0
  10. opentrons/drivers/asyncio/communication/errors.py +16 -3
  11. opentrons/drivers/asyncio/communication/serial_connection.py +24 -9
  12. opentrons/drivers/command_builder.py +2 -2
  13. opentrons/drivers/flex_stacker/__init__.py +9 -0
  14. opentrons/drivers/flex_stacker/abstract.py +89 -0
  15. opentrons/drivers/flex_stacker/driver.py +260 -0
  16. opentrons/drivers/flex_stacker/simulator.py +109 -0
  17. opentrons/drivers/flex_stacker/types.py +138 -0
  18. opentrons/drivers/heater_shaker/driver.py +18 -3
  19. opentrons/drivers/temp_deck/driver.py +13 -3
  20. opentrons/drivers/thermocycler/driver.py +17 -3
  21. opentrons/execute.py +3 -1
  22. opentrons/hardware_control/__init__.py +1 -2
  23. opentrons/hardware_control/api.py +28 -20
  24. opentrons/hardware_control/backends/flex_protocol.py +17 -7
  25. opentrons/hardware_control/backends/ot3controller.py +213 -63
  26. opentrons/hardware_control/backends/ot3simulator.py +18 -9
  27. opentrons/hardware_control/backends/ot3utils.py +43 -15
  28. opentrons/hardware_control/dev_types.py +4 -0
  29. opentrons/hardware_control/emulation/heater_shaker.py +4 -0
  30. opentrons/hardware_control/emulation/module_server/client.py +1 -1
  31. opentrons/hardware_control/emulation/module_server/server.py +5 -3
  32. opentrons/hardware_control/emulation/settings.py +3 -4
  33. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +2 -1
  34. opentrons/hardware_control/instruments/ot2/pipette.py +15 -22
  35. opentrons/hardware_control/instruments/ot2/pipette_handler.py +8 -1
  36. opentrons/hardware_control/instruments/ot3/gripper.py +2 -2
  37. opentrons/hardware_control/instruments/ot3/pipette.py +23 -22
  38. opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -1
  39. opentrons/hardware_control/modules/mod_abc.py +2 -2
  40. opentrons/hardware_control/motion_utilities.py +68 -0
  41. opentrons/hardware_control/nozzle_manager.py +39 -41
  42. opentrons/hardware_control/ot3_calibration.py +1 -1
  43. opentrons/hardware_control/ot3api.py +60 -23
  44. opentrons/hardware_control/protocols/gripper_controller.py +3 -0
  45. opentrons/hardware_control/protocols/hardware_manager.py +5 -1
  46. opentrons/hardware_control/protocols/liquid_handler.py +18 -0
  47. opentrons/hardware_control/protocols/motion_controller.py +6 -0
  48. opentrons/hardware_control/robot_calibration.py +1 -1
  49. opentrons/hardware_control/types.py +61 -0
  50. opentrons/protocol_api/__init__.py +20 -1
  51. opentrons/protocol_api/_liquid.py +24 -49
  52. opentrons/protocol_api/_liquid_properties.py +754 -0
  53. opentrons/protocol_api/_types.py +24 -0
  54. opentrons/protocol_api/core/common.py +2 -0
  55. opentrons/protocol_api/core/engine/instrument.py +82 -10
  56. opentrons/protocol_api/core/engine/labware.py +29 -7
  57. opentrons/protocol_api/core/engine/protocol.py +130 -5
  58. opentrons/protocol_api/core/engine/robot.py +139 -0
  59. opentrons/protocol_api/core/engine/well.py +4 -1
  60. opentrons/protocol_api/core/instrument.py +46 -4
  61. opentrons/protocol_api/core/labware.py +13 -4
  62. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +37 -3
  63. opentrons/protocol_api/core/legacy/legacy_labware_core.py +13 -4
  64. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +32 -1
  65. opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
  66. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +37 -3
  67. opentrons/protocol_api/core/protocol.py +34 -1
  68. opentrons/protocol_api/core/robot.py +51 -0
  69. opentrons/protocol_api/instrument_context.py +158 -44
  70. opentrons/protocol_api/labware.py +231 -7
  71. opentrons/protocol_api/module_contexts.py +21 -17
  72. opentrons/protocol_api/protocol_context.py +125 -4
  73. opentrons/protocol_api/robot_context.py +204 -32
  74. opentrons/protocol_api/validation.py +262 -3
  75. opentrons/protocol_engine/__init__.py +4 -0
  76. opentrons/protocol_engine/actions/actions.py +2 -3
  77. opentrons/protocol_engine/clients/sync_client.py +18 -0
  78. opentrons/protocol_engine/commands/__init__.py +81 -0
  79. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +0 -2
  80. opentrons/protocol_engine/commands/absorbance_reader/initialize.py +19 -5
  81. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +0 -1
  82. opentrons/protocol_engine/commands/absorbance_reader/read.py +32 -9
  83. opentrons/protocol_engine/commands/air_gap_in_place.py +160 -0
  84. opentrons/protocol_engine/commands/aspirate.py +103 -53
  85. opentrons/protocol_engine/commands/aspirate_in_place.py +55 -51
  86. opentrons/protocol_engine/commands/blow_out.py +44 -39
  87. opentrons/protocol_engine/commands/blow_out_in_place.py +21 -32
  88. opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +13 -6
  89. opentrons/protocol_engine/commands/calibration/calibrate_module.py +1 -1
  90. opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +3 -3
  91. opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +1 -1
  92. opentrons/protocol_engine/commands/command.py +73 -66
  93. opentrons/protocol_engine/commands/command_unions.py +101 -1
  94. opentrons/protocol_engine/commands/comment.py +1 -1
  95. opentrons/protocol_engine/commands/configure_for_volume.py +10 -3
  96. opentrons/protocol_engine/commands/configure_nozzle_layout.py +6 -4
  97. opentrons/protocol_engine/commands/custom.py +6 -12
  98. opentrons/protocol_engine/commands/dispense.py +82 -48
  99. opentrons/protocol_engine/commands/dispense_in_place.py +71 -51
  100. opentrons/protocol_engine/commands/drop_tip.py +52 -31
  101. opentrons/protocol_engine/commands/drop_tip_in_place.py +13 -3
  102. opentrons/protocol_engine/commands/generate_command_schema.py +4 -11
  103. opentrons/protocol_engine/commands/get_next_tip.py +134 -0
  104. opentrons/protocol_engine/commands/get_tip_presence.py +1 -1
  105. opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +1 -1
  106. opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +1 -1
  107. opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +1 -1
  108. opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +1 -1
  109. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +1 -1
  110. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
  111. opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +10 -4
  112. opentrons/protocol_engine/commands/home.py +13 -4
  113. opentrons/protocol_engine/commands/liquid_probe.py +67 -24
  114. opentrons/protocol_engine/commands/load_labware.py +29 -7
  115. opentrons/protocol_engine/commands/load_lid.py +146 -0
  116. opentrons/protocol_engine/commands/load_lid_stack.py +189 -0
  117. opentrons/protocol_engine/commands/load_liquid.py +12 -4
  118. opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
  119. opentrons/protocol_engine/commands/load_module.py +31 -10
  120. opentrons/protocol_engine/commands/load_pipette.py +19 -8
  121. opentrons/protocol_engine/commands/magnetic_module/disengage.py +1 -1
  122. opentrons/protocol_engine/commands/magnetic_module/engage.py +1 -1
  123. opentrons/protocol_engine/commands/move_labware.py +19 -6
  124. opentrons/protocol_engine/commands/move_relative.py +35 -25
  125. opentrons/protocol_engine/commands/move_to_addressable_area.py +40 -27
  126. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +53 -32
  127. opentrons/protocol_engine/commands/move_to_coordinates.py +36 -22
  128. opentrons/protocol_engine/commands/move_to_well.py +40 -24
  129. opentrons/protocol_engine/commands/movement_common.py +338 -0
  130. opentrons/protocol_engine/commands/pick_up_tip.py +49 -27
  131. opentrons/protocol_engine/commands/pipetting_common.py +169 -87
  132. opentrons/protocol_engine/commands/prepare_to_aspirate.py +24 -33
  133. opentrons/protocol_engine/commands/reload_labware.py +1 -1
  134. opentrons/protocol_engine/commands/retract_axis.py +1 -1
  135. opentrons/protocol_engine/commands/robot/__init__.py +69 -0
  136. opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +86 -0
  137. opentrons/protocol_engine/commands/robot/common.py +18 -0
  138. opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
  139. opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
  140. opentrons/protocol_engine/commands/robot/move_to.py +94 -0
  141. opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +77 -0
  142. opentrons/protocol_engine/commands/save_position.py +14 -5
  143. opentrons/protocol_engine/commands/set_rail_lights.py +1 -1
  144. opentrons/protocol_engine/commands/set_status_bar.py +1 -1
  145. opentrons/protocol_engine/commands/temperature_module/deactivate.py +1 -1
  146. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +1 -1
  147. opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +10 -4
  148. opentrons/protocol_engine/commands/thermocycler/close_lid.py +1 -1
  149. opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +1 -1
  150. opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +1 -1
  151. opentrons/protocol_engine/commands/thermocycler/open_lid.py +1 -1
  152. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +8 -2
  153. opentrons/protocol_engine/commands/thermocycler/run_profile.py +9 -3
  154. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +11 -4
  155. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +1 -1
  156. opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +1 -1
  157. opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +1 -1
  158. opentrons/protocol_engine/commands/touch_tip.py +65 -16
  159. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +4 -1
  160. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -3
  161. opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +1 -4
  162. opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -4
  163. opentrons/protocol_engine/commands/verify_tip_presence.py +11 -4
  164. opentrons/protocol_engine/commands/wait_for_duration.py +10 -3
  165. opentrons/protocol_engine/commands/wait_for_resume.py +10 -3
  166. opentrons/protocol_engine/errors/__init__.py +8 -0
  167. opentrons/protocol_engine/errors/error_occurrence.py +19 -20
  168. opentrons/protocol_engine/errors/exceptions.py +50 -0
  169. opentrons/protocol_engine/execution/command_executor.py +1 -1
  170. opentrons/protocol_engine/execution/equipment.py +73 -5
  171. opentrons/protocol_engine/execution/gantry_mover.py +364 -8
  172. opentrons/protocol_engine/execution/movement.py +27 -0
  173. opentrons/protocol_engine/execution/pipetting.py +5 -1
  174. opentrons/protocol_engine/execution/tip_handler.py +4 -6
  175. opentrons/protocol_engine/notes/notes.py +1 -1
  176. opentrons/protocol_engine/protocol_engine.py +7 -6
  177. opentrons/protocol_engine/resources/labware_data_provider.py +1 -1
  178. opentrons/protocol_engine/resources/labware_validation.py +5 -0
  179. opentrons/protocol_engine/resources/module_data_provider.py +1 -1
  180. opentrons/protocol_engine/resources/pipette_data_provider.py +26 -0
  181. opentrons/protocol_engine/slot_standardization.py +9 -9
  182. opentrons/protocol_engine/state/_move_types.py +9 -5
  183. opentrons/protocol_engine/state/_well_math.py +193 -0
  184. opentrons/protocol_engine/state/addressable_areas.py +25 -61
  185. opentrons/protocol_engine/state/command_history.py +12 -0
  186. opentrons/protocol_engine/state/commands.py +17 -13
  187. opentrons/protocol_engine/state/files.py +10 -12
  188. opentrons/protocol_engine/state/fluid_stack.py +138 -0
  189. opentrons/protocol_engine/state/frustum_helpers.py +57 -32
  190. opentrons/protocol_engine/state/geometry.py +47 -1
  191. opentrons/protocol_engine/state/labware.py +79 -25
  192. opentrons/protocol_engine/state/liquid_classes.py +82 -0
  193. opentrons/protocol_engine/state/liquids.py +16 -4
  194. opentrons/protocol_engine/state/modules.py +52 -70
  195. opentrons/protocol_engine/state/motion.py +6 -1
  196. opentrons/protocol_engine/state/pipettes.py +144 -58
  197. opentrons/protocol_engine/state/state.py +21 -2
  198. opentrons/protocol_engine/state/state_summary.py +4 -2
  199. opentrons/protocol_engine/state/tips.py +11 -44
  200. opentrons/protocol_engine/state/update_types.py +343 -48
  201. opentrons/protocol_engine/state/wells.py +19 -11
  202. opentrons/protocol_engine/types.py +176 -28
  203. opentrons/protocol_reader/extract_labware_definitions.py +5 -2
  204. opentrons/protocol_reader/file_format_validator.py +5 -5
  205. opentrons/protocol_runner/json_file_reader.py +9 -3
  206. opentrons/protocol_runner/json_translator.py +51 -25
  207. opentrons/protocol_runner/legacy_command_mapper.py +66 -64
  208. opentrons/protocol_runner/protocol_runner.py +35 -4
  209. opentrons/protocol_runner/python_protocol_wrappers.py +1 -1
  210. opentrons/protocol_runner/run_orchestrator.py +13 -3
  211. opentrons/protocols/advanced_control/common.py +38 -0
  212. opentrons/protocols/advanced_control/mix.py +1 -1
  213. opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
  214. opentrons/protocols/advanced_control/transfers/common.py +56 -0
  215. opentrons/protocols/advanced_control/{transfers.py → transfers/transfer.py} +10 -85
  216. opentrons/protocols/api_support/definitions.py +1 -1
  217. opentrons/protocols/api_support/instrument.py +1 -1
  218. opentrons/protocols/api_support/util.py +10 -0
  219. opentrons/protocols/labware.py +39 -6
  220. opentrons/protocols/models/json_protocol.py +5 -9
  221. opentrons/simulate.py +3 -1
  222. opentrons/types.py +162 -2
  223. opentrons/util/logging_config.py +1 -1
  224. {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/METADATA +16 -15
  225. {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/RECORD +229 -202
  226. {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/WHEEL +1 -1
  227. {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/LICENSE +0 -0
  228. {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/entry_points.txt +0 -0
  229. {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/top_level.txt +0 -0
@@ -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 WellLocation, WellOrigin, CurrentWell, DeckPoint
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 self._movement.move_to_well(
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 self._pipetting.prepare_for_aspirate(pipette_id=pipette_id)
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
- position = await self._movement.move_to_well(
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=params.wellLocation,
158
+ well_location=well_location,
120
159
  current_well=current_well,
121
160
  operation_volume=-params.volume,
122
161
  )
123
- deck_point = DeckPoint.construct(x=position.x, y=position.y, z=position.z)
124
- state_update.set_pipette_location(
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
- new_labware_id=labware_id,
127
- new_well_name=well_name,
128
- new_deck_point=deck_point,
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
- try:
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
- well_name=well_name,
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=OverpressureError(
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
- class Aspirate(BaseCommand[AspirateParams, AspirateResult, OverpressureError]):
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 StateUpdate, CLEAR
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
- try:
102
- volume = await self._pipetting.aspirate_in_place(
103
- pipette_id=params.pipetteId,
104
- volume=params.volume,
105
- flow_rate=params.flowRate,
106
- command_note_adder=self._command_note_adder,
107
- )
108
- except PipetteOverpressureError as e:
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
- state_update.set_liquid_operated(
114
- labware_id=current_location.labware_id,
115
- well_name=current_location.well_name,
116
- volume_added=CLEAR,
117
- )
118
- return DefinedErrorData(
119
- public=OverpressureError(
120
- id=self._model_utils.generate_id(),
121
- createdAt=self._model_utils.get_timestamp(),
122
- wrappedErrors=[
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
- state_update=state_update,
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
- state_update.set_liquid_operated(
147
- labware_id=current_location.labware_id,
148
- well_name=current_location.well_name,
149
- volume_added=-volume,
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
@@ -1,18 +1,21 @@
1
1
  """Blow-out 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
 
8
- from ..state.update_types import StateUpdate
9
- from ..types import DeckPoint
10
8
  from .pipetting_common import (
11
9
  OverpressureError,
12
10
  PipetteIdMixin,
13
11
  FlowRateMixin,
12
+ blow_out_in_place,
13
+ )
14
+ from .movement_common import (
14
15
  WellLocationMixin,
15
16
  DestinationPositionResult,
17
+ move_to_well,
18
+ StallOrCollisionError,
16
19
  )
17
20
  from .command import (
18
21
  AbstractCommandImpl,
@@ -21,7 +24,7 @@ from .command import (
21
24
  DefinedErrorData,
22
25
  SuccessData,
23
26
  )
24
- from ..errors.error_occurrence import ErrorOccurrence
27
+ from ..state.update_types import StateUpdate
25
28
 
26
29
  from opentrons.hardware_control import HardwareControlAPI
27
30
 
@@ -49,7 +52,7 @@ class BlowOutResult(DestinationPositionResult):
49
52
 
50
53
  _ExecuteReturn = Union[
51
54
  SuccessData[BlowOutResult],
52
- DefinedErrorData[OverpressureError],
55
+ DefinedErrorData[OverpressureError] | DefinedErrorData[StallOrCollisionError],
53
56
  ]
54
57
 
55
58
 
@@ -73,59 +76,61 @@ class BlowOutImplementation(AbstractCommandImpl[BlowOutParams, _ExecuteReturn]):
73
76
 
74
77
  async def execute(self, params: BlowOutParams) -> _ExecuteReturn:
75
78
  """Move to and blow-out the requested well."""
76
- state_update = StateUpdate()
77
-
78
- x, y, z = await self._movement.move_to_well(
79
+ move_result = await move_to_well(
80
+ movement=self._movement,
81
+ model_utils=self._model_utils,
79
82
  pipette_id=params.pipetteId,
80
83
  labware_id=params.labwareId,
81
84
  well_name=params.wellName,
82
85
  well_location=params.wellLocation,
83
86
  )
84
- deck_point = DeckPoint.construct(x=x, y=y, z=z)
85
- state_update.set_pipette_location(
87
+ if isinstance(move_result, DefinedErrorData):
88
+ return move_result
89
+ blow_out_result = await blow_out_in_place(
86
90
  pipette_id=params.pipetteId,
87
- new_labware_id=params.labwareId,
88
- new_well_name=params.wellName,
89
- new_deck_point=deck_point,
91
+ flow_rate=params.flowRate,
92
+ location_if_error={
93
+ "retryLocation": (
94
+ move_result.public.position.x,
95
+ move_result.public.position.y,
96
+ move_result.public.position.z,
97
+ )
98
+ },
99
+ pipetting=self._pipetting,
100
+ model_utils=self._model_utils,
90
101
  )
91
- try:
92
- await self._pipetting.blow_out_in_place(
93
- pipette_id=params.pipetteId, flow_rate=params.flowRate
94
- )
95
- except PipetteOverpressureError as e:
102
+ if isinstance(blow_out_result, DefinedErrorData):
96
103
  return DefinedErrorData(
97
- public=OverpressureError(
98
- id=self._model_utils.generate_id(),
99
- createdAt=self._model_utils.get_timestamp(),
100
- wrappedErrors=[
101
- ErrorOccurrence.from_failed(
102
- id=self._model_utils.generate_id(),
103
- createdAt=self._model_utils.get_timestamp(),
104
- error=e,
105
- )
106
- ],
107
- errorInfo={
108
- "retryLocation": (
109
- x,
110
- y,
111
- z,
112
- )
113
- },
104
+ public=blow_out_result.public,
105
+ state_update=StateUpdate.reduce(
106
+ move_result.state_update, blow_out_result.state_update
107
+ ),
108
+ state_update_if_false_positive=StateUpdate.reduce(
109
+ move_result.state_update,
110
+ blow_out_result.state_update_if_false_positive,
114
111
  ),
115
112
  )
116
113
  else:
117
114
  return SuccessData(
118
- public=BlowOutResult(position=deck_point),
119
- state_update=state_update,
115
+ public=BlowOutResult(position=move_result.public.position),
116
+ state_update=StateUpdate.reduce(
117
+ move_result.state_update, blow_out_result.state_update
118
+ ),
120
119
  )
121
120
 
122
121
 
123
- class BlowOut(BaseCommand[BlowOutParams, BlowOutResult, ErrorOccurrence]):
122
+ class BlowOut(
123
+ BaseCommand[
124
+ BlowOutParams,
125
+ BlowOutResult,
126
+ OverpressureError | StallOrCollisionError,
127
+ ]
128
+ ):
124
129
  """Blow-out command model."""
125
130
 
126
131
  commandType: BlowOutCommandType = "blowout"
127
132
  params: BlowOutParams
128
- result: Optional[BlowOutResult]
133
+ result: Optional[BlowOutResult] = None
129
134
 
130
135
  _ImplementationCls: Type[BlowOutImplementation] = BlowOutImplementation
131
136
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
  from typing import TYPE_CHECKING, Optional, Type, Union
5
- from opentrons_shared_data.errors.exceptions import PipetteOverpressureError
6
5
  from typing_extensions import Literal
7
6
  from pydantic import BaseModel
8
7
 
@@ -10,6 +9,7 @@ from .pipetting_common import (
10
9
  OverpressureError,
11
10
  PipetteIdMixin,
12
11
  FlowRateMixin,
12
+ blow_out_in_place,
13
13
  )
14
14
  from .command import (
15
15
  AbstractCommandImpl,
@@ -72,36 +72,25 @@ class BlowOutInPlaceImplementation(
72
72
 
73
73
  async def execute(self, params: BlowOutInPlaceParams) -> _ExecuteReturn:
74
74
  """Blow-out without moving the pipette."""
75
- try:
76
- current_position = await self._gantry_mover.get_position(params.pipetteId)
77
- await self._pipetting.blow_out_in_place(
78
- pipette_id=params.pipetteId, flow_rate=params.flowRate
79
- )
80
- except PipetteOverpressureError as e:
81
- return DefinedErrorData(
82
- public=OverpressureError(
83
- id=self._model_utils.generate_id(),
84
- createdAt=self._model_utils.get_timestamp(),
85
- wrappedErrors=[
86
- ErrorOccurrence.from_failed(
87
- id=self._model_utils.generate_id(),
88
- createdAt=self._model_utils.get_timestamp(),
89
- error=e,
90
- )
91
- ],
92
- errorInfo={
93
- "retryLocation": (
94
- current_position.x,
95
- current_position.y,
96
- current_position.z,
97
- )
98
- },
99
- ),
100
- )
101
- else:
102
- return SuccessData(
103
- public=BlowOutInPlaceResult(),
104
- )
75
+ current_position = await self._gantry_mover.get_position(params.pipetteId)
76
+ result = await blow_out_in_place(
77
+ pipette_id=params.pipetteId,
78
+ flow_rate=params.flowRate,
79
+ location_if_error={
80
+ "retryLocation": (
81
+ current_position.x,
82
+ current_position.y,
83
+ current_position.z,
84
+ )
85
+ },
86
+ pipetting=self._pipetting,
87
+ model_utils=self._model_utils,
88
+ )
89
+ if isinstance(result, DefinedErrorData):
90
+ return result
91
+ return SuccessData(
92
+ public=BlowOutInPlaceResult(), state_update=result.state_update
93
+ )
105
94
 
106
95
 
107
96
  class BlowOutInPlace(
@@ -111,7 +100,7 @@ class BlowOutInPlace(
111
100
 
112
101
  commandType: BlowOutInPlaceCommandType = "blowOutInPlace"
113
102
  params: BlowOutInPlaceParams
114
- result: Optional[BlowOutInPlaceResult]
103
+ result: Optional[BlowOutInPlaceResult] = None
115
104
 
116
105
  _ImplementationCls: Type[
117
106
  BlowOutInPlaceImplementation