opentrons 8.1.0__py2.py3-none-any.whl → 8.2.0__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 (238) hide show
  1. opentrons/cli/analyze.py +71 -7
  2. opentrons/config/__init__.py +9 -0
  3. opentrons/config/advanced_settings.py +22 -0
  4. opentrons/config/defaults_ot3.py +14 -36
  5. opentrons/config/feature_flags.py +4 -0
  6. opentrons/config/types.py +6 -17
  7. opentrons/drivers/absorbance_reader/abstract.py +27 -3
  8. opentrons/drivers/absorbance_reader/async_byonoy.py +208 -154
  9. opentrons/drivers/absorbance_reader/driver.py +24 -15
  10. opentrons/drivers/absorbance_reader/hid_protocol.py +79 -50
  11. opentrons/drivers/absorbance_reader/simulator.py +32 -6
  12. opentrons/drivers/types.py +23 -1
  13. opentrons/execute.py +2 -2
  14. opentrons/hardware_control/api.py +18 -10
  15. opentrons/hardware_control/backends/controller.py +3 -2
  16. opentrons/hardware_control/backends/flex_protocol.py +11 -5
  17. opentrons/hardware_control/backends/ot3controller.py +18 -50
  18. opentrons/hardware_control/backends/ot3simulator.py +7 -6
  19. opentrons/hardware_control/backends/ot3utils.py +1 -0
  20. opentrons/hardware_control/instruments/ot2/pipette_handler.py +22 -82
  21. opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -2
  22. opentrons/hardware_control/module_control.py +43 -2
  23. opentrons/hardware_control/modules/__init__.py +7 -1
  24. opentrons/hardware_control/modules/absorbance_reader.py +232 -83
  25. opentrons/hardware_control/modules/errors.py +7 -0
  26. opentrons/hardware_control/modules/heater_shaker.py +8 -3
  27. opentrons/hardware_control/modules/magdeck.py +12 -3
  28. opentrons/hardware_control/modules/mod_abc.py +27 -2
  29. opentrons/hardware_control/modules/tempdeck.py +15 -7
  30. opentrons/hardware_control/modules/thermocycler.py +69 -3
  31. opentrons/hardware_control/modules/types.py +11 -5
  32. opentrons/hardware_control/modules/update.py +11 -5
  33. opentrons/hardware_control/modules/utils.py +3 -1
  34. opentrons/hardware_control/ot3_calibration.py +6 -6
  35. opentrons/hardware_control/ot3api.py +131 -94
  36. opentrons/hardware_control/poller.py +15 -11
  37. opentrons/hardware_control/protocols/__init__.py +1 -7
  38. opentrons/hardware_control/protocols/instrument_configurer.py +14 -2
  39. opentrons/hardware_control/protocols/liquid_handler.py +5 -0
  40. opentrons/hardware_control/protocols/position_estimator.py +3 -1
  41. opentrons/hardware_control/types.py +2 -0
  42. opentrons/legacy_commands/helpers.py +8 -2
  43. opentrons/motion_planning/__init__.py +2 -0
  44. opentrons/motion_planning/waypoints.py +32 -0
  45. opentrons/protocol_api/__init__.py +2 -1
  46. opentrons/protocol_api/_liquid.py +87 -1
  47. opentrons/protocol_api/_parameter_context.py +10 -1
  48. opentrons/protocol_api/core/engine/deck_conflict.py +0 -297
  49. opentrons/protocol_api/core/engine/instrument.py +29 -25
  50. opentrons/protocol_api/core/engine/labware.py +20 -4
  51. opentrons/protocol_api/core/engine/module_core.py +166 -17
  52. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +362 -0
  53. opentrons/protocol_api/core/engine/protocol.py +30 -2
  54. opentrons/protocol_api/core/instrument.py +2 -0
  55. opentrons/protocol_api/core/labware.py +4 -0
  56. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +2 -0
  57. opentrons/protocol_api/core/legacy/legacy_labware_core.py +5 -0
  58. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +6 -2
  59. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +2 -0
  60. opentrons/protocol_api/core/module.py +22 -4
  61. opentrons/protocol_api/core/protocol.py +6 -2
  62. opentrons/protocol_api/instrument_context.py +52 -20
  63. opentrons/protocol_api/labware.py +13 -1
  64. opentrons/protocol_api/module_contexts.py +115 -17
  65. opentrons/protocol_api/protocol_context.py +49 -5
  66. opentrons/protocol_api/validation.py +5 -3
  67. opentrons/protocol_engine/__init__.py +10 -9
  68. opentrons/protocol_engine/actions/__init__.py +3 -0
  69. opentrons/protocol_engine/actions/actions.py +30 -25
  70. opentrons/protocol_engine/actions/get_state_update.py +38 -0
  71. opentrons/protocol_engine/clients/sync_client.py +1 -1
  72. opentrons/protocol_engine/clients/transports.py +1 -1
  73. opentrons/protocol_engine/commands/__init__.py +0 -4
  74. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +41 -11
  75. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +148 -0
  76. opentrons/protocol_engine/commands/absorbance_reader/initialize.py +65 -9
  77. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +148 -0
  78. opentrons/protocol_engine/commands/absorbance_reader/read.py +200 -0
  79. opentrons/protocol_engine/commands/aspirate.py +29 -16
  80. opentrons/protocol_engine/commands/aspirate_in_place.py +33 -16
  81. opentrons/protocol_engine/commands/blow_out.py +63 -14
  82. opentrons/protocol_engine/commands/blow_out_in_place.py +55 -13
  83. opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +2 -5
  84. opentrons/protocol_engine/commands/calibration/calibrate_module.py +3 -4
  85. opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +2 -5
  86. opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +6 -4
  87. opentrons/protocol_engine/commands/command.py +31 -18
  88. opentrons/protocol_engine/commands/command_unions.py +37 -24
  89. opentrons/protocol_engine/commands/comment.py +5 -3
  90. opentrons/protocol_engine/commands/configure_for_volume.py +11 -14
  91. opentrons/protocol_engine/commands/configure_nozzle_layout.py +9 -15
  92. opentrons/protocol_engine/commands/custom.py +5 -3
  93. opentrons/protocol_engine/commands/dispense.py +42 -20
  94. opentrons/protocol_engine/commands/dispense_in_place.py +32 -14
  95. opentrons/protocol_engine/commands/drop_tip.py +70 -16
  96. opentrons/protocol_engine/commands/drop_tip_in_place.py +59 -13
  97. opentrons/protocol_engine/commands/get_tip_presence.py +5 -3
  98. opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +6 -6
  99. opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +6 -6
  100. opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +6 -6
  101. opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +8 -6
  102. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +8 -4
  103. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +6 -4
  104. opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +6 -6
  105. opentrons/protocol_engine/commands/home.py +11 -5
  106. opentrons/protocol_engine/commands/liquid_probe.py +146 -88
  107. opentrons/protocol_engine/commands/load_labware.py +28 -5
  108. opentrons/protocol_engine/commands/load_liquid.py +18 -7
  109. opentrons/protocol_engine/commands/load_module.py +4 -6
  110. opentrons/protocol_engine/commands/load_pipette.py +18 -17
  111. opentrons/protocol_engine/commands/magnetic_module/disengage.py +6 -6
  112. opentrons/protocol_engine/commands/magnetic_module/engage.py +6 -4
  113. opentrons/protocol_engine/commands/move_labware.py +155 -23
  114. opentrons/protocol_engine/commands/move_relative.py +15 -3
  115. opentrons/protocol_engine/commands/move_to_addressable_area.py +29 -4
  116. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +13 -4
  117. opentrons/protocol_engine/commands/move_to_coordinates.py +11 -5
  118. opentrons/protocol_engine/commands/move_to_well.py +37 -10
  119. opentrons/protocol_engine/commands/pick_up_tip.py +51 -30
  120. opentrons/protocol_engine/commands/pipetting_common.py +47 -16
  121. opentrons/protocol_engine/commands/prepare_to_aspirate.py +62 -15
  122. opentrons/protocol_engine/commands/reload_labware.py +13 -4
  123. opentrons/protocol_engine/commands/retract_axis.py +6 -3
  124. opentrons/protocol_engine/commands/save_position.py +2 -3
  125. opentrons/protocol_engine/commands/set_rail_lights.py +5 -3
  126. opentrons/protocol_engine/commands/set_status_bar.py +5 -3
  127. opentrons/protocol_engine/commands/temperature_module/deactivate.py +6 -4
  128. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +3 -4
  129. opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +6 -6
  130. opentrons/protocol_engine/commands/thermocycler/__init__.py +19 -0
  131. opentrons/protocol_engine/commands/thermocycler/close_lid.py +8 -8
  132. opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +6 -4
  133. opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +6 -4
  134. opentrons/protocol_engine/commands/thermocycler/open_lid.py +8 -4
  135. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +165 -0
  136. opentrons/protocol_engine/commands/thermocycler/run_profile.py +6 -6
  137. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +3 -4
  138. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +3 -4
  139. opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +6 -4
  140. opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +6 -4
  141. opentrons/protocol_engine/commands/touch_tip.py +19 -7
  142. opentrons/protocol_engine/commands/unsafe/__init__.py +30 -0
  143. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +6 -4
  144. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -4
  145. opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +5 -3
  146. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
  147. opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
  148. opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +10 -4
  149. opentrons/protocol_engine/commands/verify_tip_presence.py +5 -5
  150. opentrons/protocol_engine/commands/wait_for_duration.py +5 -3
  151. opentrons/protocol_engine/commands/wait_for_resume.py +5 -3
  152. opentrons/protocol_engine/create_protocol_engine.py +60 -10
  153. opentrons/protocol_engine/engine_support.py +2 -1
  154. opentrons/protocol_engine/error_recovery_policy.py +14 -3
  155. opentrons/protocol_engine/errors/__init__.py +20 -0
  156. opentrons/protocol_engine/errors/error_occurrence.py +8 -3
  157. opentrons/protocol_engine/errors/exceptions.py +127 -2
  158. opentrons/protocol_engine/execution/__init__.py +2 -0
  159. opentrons/protocol_engine/execution/command_executor.py +22 -13
  160. opentrons/protocol_engine/execution/create_queue_worker.py +5 -1
  161. opentrons/protocol_engine/execution/door_watcher.py +1 -1
  162. opentrons/protocol_engine/execution/equipment.py +2 -1
  163. opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
  164. opentrons/protocol_engine/execution/gantry_mover.py +4 -2
  165. opentrons/protocol_engine/execution/hardware_stopper.py +3 -3
  166. opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +1 -4
  167. opentrons/protocol_engine/execution/labware_movement.py +73 -22
  168. opentrons/protocol_engine/execution/movement.py +17 -7
  169. opentrons/protocol_engine/execution/pipetting.py +7 -4
  170. opentrons/protocol_engine/execution/queue_worker.py +6 -2
  171. opentrons/protocol_engine/execution/run_control.py +1 -1
  172. opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +1 -1
  173. opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +2 -1
  174. opentrons/protocol_engine/execution/tip_handler.py +77 -43
  175. opentrons/protocol_engine/notes/__init__.py +14 -2
  176. opentrons/protocol_engine/notes/notes.py +18 -1
  177. opentrons/protocol_engine/plugins.py +1 -1
  178. opentrons/protocol_engine/protocol_engine.py +47 -31
  179. opentrons/protocol_engine/resources/__init__.py +2 -0
  180. opentrons/protocol_engine/resources/deck_data_provider.py +19 -5
  181. opentrons/protocol_engine/resources/file_provider.py +161 -0
  182. opentrons/protocol_engine/resources/fixture_validation.py +11 -1
  183. opentrons/protocol_engine/resources/labware_validation.py +10 -0
  184. opentrons/protocol_engine/state/__init__.py +0 -70
  185. opentrons/protocol_engine/state/addressable_areas.py +1 -1
  186. opentrons/protocol_engine/state/command_history.py +21 -2
  187. opentrons/protocol_engine/state/commands.py +110 -31
  188. opentrons/protocol_engine/state/files.py +59 -0
  189. opentrons/protocol_engine/state/frustum_helpers.py +440 -0
  190. opentrons/protocol_engine/state/geometry.py +445 -59
  191. opentrons/protocol_engine/state/labware.py +264 -84
  192. opentrons/protocol_engine/state/liquids.py +1 -1
  193. opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +21 -3
  194. opentrons/protocol_engine/state/modules.py +145 -90
  195. opentrons/protocol_engine/state/motion.py +33 -14
  196. opentrons/protocol_engine/state/pipettes.py +157 -317
  197. opentrons/protocol_engine/state/state.py +30 -1
  198. opentrons/protocol_engine/state/state_summary.py +3 -0
  199. opentrons/protocol_engine/state/tips.py +69 -114
  200. opentrons/protocol_engine/state/update_types.py +424 -0
  201. opentrons/protocol_engine/state/wells.py +236 -0
  202. opentrons/protocol_engine/types.py +90 -0
  203. opentrons/protocol_reader/file_format_validator.py +83 -15
  204. opentrons/protocol_runner/json_translator.py +21 -5
  205. opentrons/protocol_runner/legacy_command_mapper.py +27 -6
  206. opentrons/protocol_runner/legacy_context_plugin.py +27 -71
  207. opentrons/protocol_runner/protocol_runner.py +6 -3
  208. opentrons/protocol_runner/run_orchestrator.py +41 -6
  209. opentrons/protocols/advanced_control/mix.py +3 -5
  210. opentrons/protocols/advanced_control/transfers.py +125 -56
  211. opentrons/protocols/api_support/constants.py +1 -1
  212. opentrons/protocols/api_support/definitions.py +1 -1
  213. opentrons/protocols/api_support/labware_like.py +4 -4
  214. opentrons/protocols/api_support/tip_tracker.py +2 -2
  215. opentrons/protocols/api_support/types.py +15 -2
  216. opentrons/protocols/api_support/util.py +30 -42
  217. opentrons/protocols/duration/errors.py +1 -1
  218. opentrons/protocols/duration/estimator.py +50 -29
  219. opentrons/protocols/execution/dev_types.py +2 -2
  220. opentrons/protocols/execution/execute_json_v4.py +15 -10
  221. opentrons/protocols/execution/execute_python.py +8 -3
  222. opentrons/protocols/geometry/planning.py +12 -12
  223. opentrons/protocols/labware.py +17 -33
  224. opentrons/protocols/parameters/csv_parameter_interface.py +3 -1
  225. opentrons/simulate.py +3 -3
  226. opentrons/types.py +30 -3
  227. opentrons/util/logging_config.py +34 -0
  228. {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/METADATA +5 -4
  229. {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/RECORD +235 -223
  230. opentrons/protocol_engine/commands/absorbance_reader/measure.py +0 -94
  231. opentrons/protocol_engine/commands/configuring_common.py +0 -26
  232. opentrons/protocol_runner/thread_async_queue.py +0 -174
  233. /opentrons/protocol_engine/state/{abstract_store.py → _abstract_store.py} +0 -0
  234. /opentrons/protocol_engine/state/{move_types.py → _move_types.py} +0 -0
  235. {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/LICENSE +0 -0
  236. {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/WHEEL +0 -0
  237. {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/entry_points.txt +0 -0
  238. {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/top_level.txt +0 -0
@@ -3,8 +3,8 @@
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
+ import dataclasses
6
7
  from abc import ABC, abstractmethod
7
- from dataclasses import dataclass
8
8
  from datetime import datetime
9
9
  from enum import Enum
10
10
  from typing import (
@@ -21,6 +21,7 @@ from pydantic import BaseModel, Field
21
21
  from pydantic.generics import GenericModel
22
22
 
23
23
  from opentrons.hardware_control import HardwareControlAPI
24
+ from opentrons.protocol_engine.state.update_types import StateUpdate
24
25
 
25
26
  from ..resources import ModelUtils
26
27
  from ..errors import ErrorOccurrence
@@ -29,7 +30,7 @@ from ..notes import CommandNote, CommandNoteAdder
29
30
  # Work around type-only circular dependencies.
30
31
  if TYPE_CHECKING:
31
32
  from .. import execution
32
- from ..state import StateView
33
+ from ..state.state import StateView
33
34
 
34
35
 
35
36
  _ParamsT = TypeVar("_ParamsT", bound=BaseModel)
@@ -38,7 +39,6 @@ _ResultT = TypeVar("_ResultT", bound=BaseModel)
38
39
  _ResultT_co = TypeVar("_ResultT_co", bound=BaseModel, covariant=True)
39
40
  _ErrorT = TypeVar("_ErrorT", bound=ErrorOccurrence)
40
41
  _ErrorT_co = TypeVar("_ErrorT_co", bound=ErrorOccurrence, covariant=True)
41
- _PrivateResultT_co = TypeVar("_PrivateResultT_co", covariant=True)
42
42
 
43
43
 
44
44
  class CommandStatus(str, Enum):
@@ -106,19 +106,23 @@ class BaseCommandCreate(
106
106
  )
107
107
 
108
108
 
109
- @dataclass(frozen=True)
110
- class SuccessData(Generic[_ResultT_co, _PrivateResultT_co]):
109
+ @dataclasses.dataclass(frozen=True)
110
+ class SuccessData(Generic[_ResultT_co]):
111
111
  """Data from the successful completion of a command."""
112
112
 
113
113
  public: _ResultT_co
114
114
  """Public result data. Exposed over HTTP and stored in databases."""
115
115
 
116
- private: _PrivateResultT_co
117
- """Additional result data, only given to `opentrons.protocol_engine` internals."""
116
+ state_update: StateUpdate = dataclasses.field(
117
+ # todo(mm, 2024-08-22): Remove the default once all command implementations
118
+ # use this, to make it harder to forget in new command implementations.
119
+ default_factory=StateUpdate
120
+ )
121
+ """How the engine state should be updated to reflect this command success."""
118
122
 
119
123
 
120
- @dataclass(frozen=True)
121
- class DefinedErrorData(Generic[_ErrorT_co, _PrivateResultT_co]):
124
+ @dataclasses.dataclass(frozen=True)
125
+ class DefinedErrorData(Generic[_ErrorT_co]):
122
126
  """Data from a command that failed with a defined error.
123
127
 
124
128
  This should only be used for "defined" errors, not any error.
@@ -128,8 +132,16 @@ class DefinedErrorData(Generic[_ErrorT_co, _PrivateResultT_co]):
128
132
  public: _ErrorT_co
129
133
  """Public error data. Exposed over HTTP and stored in databases."""
130
134
 
131
- private: _PrivateResultT_co
132
- """Additional error data, only given to `opentrons.protocol_engine` internals."""
135
+ state_update: StateUpdate = dataclasses.field(
136
+ # todo(mm, 2024-08-22): Remove the default once all command implementations
137
+ # use this, to make it harder to forget in new command implementations.
138
+ default_factory=StateUpdate
139
+ )
140
+ """How the engine state should be updated to reflect this command failure."""
141
+
142
+ state_update_if_false_positive: StateUpdate = dataclasses.field(
143
+ default_factory=StateUpdate
144
+ )
133
145
 
134
146
 
135
147
  class BaseCommand(
@@ -173,7 +185,9 @@ class BaseCommand(
173
185
  )
174
186
  error: Union[
175
187
  _ErrorT,
176
- # ErrorOccurrence here is for undefined errors not captured by _ErrorT.
188
+ # ErrorOccurrence here is a catch-all for undefined errors not captured by
189
+ # _ErrorT, or defined errors that don't parse into _ErrorT because, for example,
190
+ # they are from an older software version that was missing some fields.
177
191
  ErrorOccurrence,
178
192
  None,
179
193
  ] = Field(
@@ -219,13 +233,11 @@ class BaseCommand(
219
233
  # Our _ImplementationCls must return public result data that can fit
220
234
  # in our `result` field:
221
235
  _ResultT,
222
- # But we don't care (here) what kind of private result data it returns:
223
- object,
224
236
  ],
225
237
  DefinedErrorData[
226
- # Likewise, for our `error` field:
238
+ # Our _ImplementationCls must return public error data that can fit
239
+ # in our `error` field:
227
240
  _ErrorT,
228
- object,
229
241
  ],
230
242
  ],
231
243
  ]
@@ -235,8 +247,8 @@ class BaseCommand(
235
247
  _ExecuteReturnT_co = TypeVar(
236
248
  "_ExecuteReturnT_co",
237
249
  bound=Union[
238
- SuccessData[BaseModel, object],
239
- DefinedErrorData[ErrorOccurrence, object],
250
+ SuccessData[BaseModel],
251
+ DefinedErrorData[ErrorOccurrence],
240
252
  ],
241
253
  covariant=True,
242
254
  )
@@ -258,6 +270,7 @@ class AbstractCommandImpl(
258
270
  state_view: StateView,
259
271
  hardware_api: HardwareControlAPI,
260
272
  equipment: execution.EquipmentHandler,
273
+ file_provider: execution.FileProvider,
261
274
  movement: execution.MovementHandler,
262
275
  gantry_mover: execution.GantryMover,
263
276
  labware_movement: execution.LabwareMovementHandler,
@@ -10,9 +10,8 @@ from opentrons.util.get_union_elements import get_union_elements
10
10
  from .command import DefinedErrorData
11
11
  from .pipetting_common import (
12
12
  OverpressureError,
13
- OverpressureErrorInternalData,
14
13
  LiquidNotFoundError,
15
- LiquidNotFoundErrorInternalData,
14
+ TipPhysicallyAttachedError,
16
15
  )
17
16
 
18
17
  from . import absorbance_reader
@@ -142,10 +141,10 @@ from .load_pipette import (
142
141
  LoadPipetteCreate,
143
142
  LoadPipetteResult,
144
143
  LoadPipetteCommandType,
145
- LoadPipettePrivateResult,
146
144
  )
147
145
 
148
146
  from .move_labware import (
147
+ GripperMovementError,
149
148
  MoveLabware,
150
149
  MoveLabwareParams,
151
150
  MoveLabwareCreate,
@@ -216,7 +215,6 @@ from .pick_up_tip import (
216
215
  PickUpTipResult,
217
216
  PickUpTipCommandType,
218
217
  TipPhysicallyMissingError,
219
- TipPhysicallyMissingErrorInternalData,
220
218
  )
221
219
 
222
220
  from .touch_tip import (
@@ -273,7 +271,6 @@ from .configure_for_volume import (
273
271
  ConfigureForVolumeCreate,
274
272
  ConfigureForVolumeResult,
275
273
  ConfigureForVolumeCommandType,
276
- ConfigureForVolumePrivateResult,
277
274
  )
278
275
 
279
276
  from .prepare_to_aspirate import (
@@ -290,7 +287,6 @@ from .configure_nozzle_layout import (
290
287
  ConfigureNozzleLayoutParams,
291
288
  ConfigureNozzleLayoutResult,
292
289
  ConfigureNozzleLayoutCommandType,
293
- ConfigureNozzleLayoutPrivateResult,
294
290
  )
295
291
 
296
292
  from .verify_tip_presence import (
@@ -382,8 +378,11 @@ Command = Annotated[
382
378
  thermocycler.OpenLid,
383
379
  thermocycler.CloseLid,
384
380
  thermocycler.RunProfile,
381
+ thermocycler.RunExtendedProfile,
382
+ absorbance_reader.CloseLid,
383
+ absorbance_reader.OpenLid,
385
384
  absorbance_reader.Initialize,
386
- absorbance_reader.MeasureAbsorbance,
385
+ absorbance_reader.ReadAbsorbance,
387
386
  calibration.CalibrateGripper,
388
387
  calibration.CalibratePipette,
389
388
  calibration.CalibrateModule,
@@ -392,6 +391,8 @@ Command = Annotated[
392
391
  unsafe.UnsafeDropTipInPlace,
393
392
  unsafe.UpdatePositionEstimators,
394
393
  unsafe.UnsafeEngageAxes,
394
+ unsafe.UnsafeUngripLabware,
395
+ unsafe.UnsafePlaceLabware,
395
396
  ],
396
397
  Field(discriminator="commandType"),
397
398
  ]
@@ -455,8 +456,11 @@ CommandParams = Union[
455
456
  thermocycler.OpenLidParams,
456
457
  thermocycler.CloseLidParams,
457
458
  thermocycler.RunProfileParams,
459
+ thermocycler.RunExtendedProfileParams,
460
+ absorbance_reader.CloseLidParams,
461
+ absorbance_reader.OpenLidParams,
458
462
  absorbance_reader.InitializeParams,
459
- absorbance_reader.MeasureAbsorbanceParams,
463
+ absorbance_reader.ReadAbsorbanceParams,
460
464
  calibration.CalibrateGripperParams,
461
465
  calibration.CalibratePipetteParams,
462
466
  calibration.CalibrateModuleParams,
@@ -465,6 +469,8 @@ CommandParams = Union[
465
469
  unsafe.UnsafeDropTipInPlaceParams,
466
470
  unsafe.UpdatePositionEstimatorsParams,
467
471
  unsafe.UnsafeEngageAxesParams,
472
+ unsafe.UnsafeUngripLabwareParams,
473
+ unsafe.UnsafePlaceLabwareParams,
468
474
  ]
469
475
 
470
476
  CommandType = Union[
@@ -526,8 +532,11 @@ CommandType = Union[
526
532
  thermocycler.OpenLidCommandType,
527
533
  thermocycler.CloseLidCommandType,
528
534
  thermocycler.RunProfileCommandType,
535
+ thermocycler.RunExtendedProfileCommandType,
536
+ absorbance_reader.CloseLidCommandType,
537
+ absorbance_reader.OpenLidCommandType,
529
538
  absorbance_reader.InitializeCommandType,
530
- absorbance_reader.MeasureAbsorbanceCommandType,
539
+ absorbance_reader.ReadAbsorbanceCommandType,
531
540
  calibration.CalibrateGripperCommandType,
532
541
  calibration.CalibratePipetteCommandType,
533
542
  calibration.CalibrateModuleCommandType,
@@ -536,6 +545,8 @@ CommandType = Union[
536
545
  unsafe.UnsafeDropTipInPlaceCommandType,
537
546
  unsafe.UpdatePositionEstimatorsCommandType,
538
547
  unsafe.UnsafeEngageAxesCommandType,
548
+ unsafe.UnsafeUngripLabwareCommandType,
549
+ unsafe.UnsafePlaceLabwareCommandType,
539
550
  ]
540
551
 
541
552
  CommandCreate = Annotated[
@@ -598,8 +609,11 @@ CommandCreate = Annotated[
598
609
  thermocycler.OpenLidCreate,
599
610
  thermocycler.CloseLidCreate,
600
611
  thermocycler.RunProfileCreate,
612
+ thermocycler.RunExtendedProfileCreate,
613
+ absorbance_reader.CloseLidCreate,
614
+ absorbance_reader.OpenLidCreate,
601
615
  absorbance_reader.InitializeCreate,
602
- absorbance_reader.MeasureAbsorbanceCreate,
616
+ absorbance_reader.ReadAbsorbanceCreate,
603
617
  calibration.CalibrateGripperCreate,
604
618
  calibration.CalibratePipetteCreate,
605
619
  calibration.CalibrateModuleCreate,
@@ -608,6 +622,8 @@ CommandCreate = Annotated[
608
622
  unsafe.UnsafeDropTipInPlaceCreate,
609
623
  unsafe.UpdatePositionEstimatorsCreate,
610
624
  unsafe.UnsafeEngageAxesCreate,
625
+ unsafe.UnsafeUngripLabwareCreate,
626
+ unsafe.UnsafePlaceLabwareCreate,
611
627
  ],
612
628
  Field(discriminator="commandType"),
613
629
  ]
@@ -671,8 +687,11 @@ CommandResult = Union[
671
687
  thermocycler.OpenLidResult,
672
688
  thermocycler.CloseLidResult,
673
689
  thermocycler.RunProfileResult,
690
+ thermocycler.RunExtendedProfileResult,
691
+ absorbance_reader.CloseLidResult,
692
+ absorbance_reader.OpenLidResult,
674
693
  absorbance_reader.InitializeResult,
675
- absorbance_reader.MeasureAbsorbanceResult,
694
+ absorbance_reader.ReadAbsorbanceResult,
676
695
  calibration.CalibrateGripperResult,
677
696
  calibration.CalibratePipetteResult,
678
697
  calibration.CalibrateModuleResult,
@@ -681,24 +700,18 @@ CommandResult = Union[
681
700
  unsafe.UnsafeDropTipInPlaceResult,
682
701
  unsafe.UpdatePositionEstimatorsResult,
683
702
  unsafe.UnsafeEngageAxesResult,
703
+ unsafe.UnsafeUngripLabwareResult,
704
+ unsafe.UnsafePlaceLabwareResult,
684
705
  ]
685
706
 
686
- # todo(mm, 2024-06-12): Ideally, command return types would have specific
687
- # CommandPrivateResults paired with specific CommandResults. For example,
688
- # a TouchTipResult can never be paired with a LoadPipettePrivateResult in practice,
689
- # and ideally our types would reflect that.
690
- CommandPrivateResult = Union[
691
- None,
692
- LoadPipettePrivateResult,
693
- ConfigureForVolumePrivateResult,
694
- ConfigureNozzleLayoutPrivateResult,
695
- ]
696
707
 
697
708
  # All `DefinedErrorData`s that implementations will actually return in practice.
698
709
  CommandDefinedErrorData = Union[
699
- DefinedErrorData[TipPhysicallyMissingError, TipPhysicallyMissingErrorInternalData],
700
- DefinedErrorData[OverpressureError, OverpressureErrorInternalData],
701
- DefinedErrorData[LiquidNotFoundError, LiquidNotFoundErrorInternalData],
710
+ DefinedErrorData[TipPhysicallyMissingError],
711
+ DefinedErrorData[TipPhysicallyAttachedError],
712
+ DefinedErrorData[OverpressureError],
713
+ DefinedErrorData[LiquidNotFoundError],
714
+ DefinedErrorData[GripperMovementError],
702
715
  ]
703
716
 
704
717
 
@@ -24,16 +24,18 @@ class CommentResult(BaseModel):
24
24
 
25
25
 
26
26
  class CommentImplementation(
27
- AbstractCommandImpl[CommentParams, SuccessData[CommentResult, None]]
27
+ AbstractCommandImpl[CommentParams, SuccessData[CommentResult]]
28
28
  ):
29
29
  """Comment command implementation."""
30
30
 
31
31
  def __init__(self, **kwargs: object) -> None:
32
32
  pass
33
33
 
34
- async def execute(self, params: CommentParams) -> SuccessData[CommentResult, None]:
34
+ async def execute(self, params: CommentParams) -> SuccessData[CommentResult]:
35
35
  """No operation taken other than capturing message in command."""
36
- return SuccessData(public=CommentResult(), private=None)
36
+ return SuccessData(
37
+ public=CommentResult(),
38
+ )
37
39
 
38
40
 
39
41
  class Comment(BaseCommand[CommentParams, CommentResult, ErrorOccurrence]):
@@ -7,7 +7,7 @@ from typing_extensions import Literal
7
7
  from .pipetting_common import PipetteIdMixin
8
8
  from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
9
9
  from ..errors.error_occurrence import ErrorOccurrence
10
- from .configuring_common import PipetteConfigUpdateResultMixin
10
+ from ..state.update_types import StateUpdate
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from ..execution import EquipmentHandler
@@ -34,12 +34,6 @@ class ConfigureForVolumeParams(PipetteIdMixin):
34
34
  )
35
35
 
36
36
 
37
- class ConfigureForVolumePrivateResult(PipetteConfigUpdateResultMixin):
38
- """Result sent to the store but not serialized."""
39
-
40
- pass
41
-
42
-
43
37
  class ConfigureForVolumeResult(BaseModel):
44
38
  """Result data from execution of an ConfigureForVolume command."""
45
39
 
@@ -49,7 +43,7 @@ class ConfigureForVolumeResult(BaseModel):
49
43
  class ConfigureForVolumeImplementation(
50
44
  AbstractCommandImpl[
51
45
  ConfigureForVolumeParams,
52
- SuccessData[ConfigureForVolumeResult, ConfigureForVolumePrivateResult],
46
+ SuccessData[ConfigureForVolumeResult],
53
47
  ]
54
48
  ):
55
49
  """Configure for volume command implementation."""
@@ -59,7 +53,7 @@ class ConfigureForVolumeImplementation(
59
53
 
60
54
  async def execute(
61
55
  self, params: ConfigureForVolumeParams
62
- ) -> SuccessData[ConfigureForVolumeResult, ConfigureForVolumePrivateResult]:
56
+ ) -> SuccessData[ConfigureForVolumeResult]:
63
57
  """Check that requested pipette can be configured for the given volume."""
64
58
  pipette_result = await self._equipment.configure_for_volume(
65
59
  pipette_id=params.pipetteId,
@@ -67,13 +61,16 @@ class ConfigureForVolumeImplementation(
67
61
  tip_overlap_version=params.tipOverlapNotAfterVersion,
68
62
  )
69
63
 
64
+ state_update = StateUpdate()
65
+ state_update.update_pipette_config(
66
+ pipette_id=pipette_result.pipette_id,
67
+ config=pipette_result.static_config,
68
+ serial_number=pipette_result.serial_number,
69
+ )
70
+
70
71
  return SuccessData(
71
72
  public=ConfigureForVolumeResult(),
72
- private=ConfigureForVolumePrivateResult(
73
- pipette_id=pipette_result.pipette_id,
74
- serial_number=pipette_result.serial_number,
75
- config=pipette_result.static_config,
76
- ),
73
+ state_update=state_update,
77
74
  )
78
75
 
79
76
 
@@ -1,5 +1,6 @@
1
1
  """Configure nozzle layout command request, result, and implementation models."""
2
2
  from __future__ import annotations
3
+ from opentrons.protocol_engine.state.update_types import StateUpdate
3
4
  from pydantic import BaseModel
4
5
  from typing import TYPE_CHECKING, Optional, Type, Union
5
6
  from typing_extensions import Literal
@@ -9,9 +10,6 @@ from .pipetting_common import (
9
10
  )
10
11
  from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
11
12
  from ..errors.error_occurrence import ErrorOccurrence
12
- from .configuring_common import (
13
- PipetteNozzleLayoutResultMixin,
14
- )
15
13
  from ..types import (
16
14
  AllNozzleLayoutConfiguration,
17
15
  SingleNozzleLayoutConfiguration,
@@ -39,12 +37,6 @@ class ConfigureNozzleLayoutParams(PipetteIdMixin):
39
37
  ]
40
38
 
41
39
 
42
- class ConfigureNozzleLayoutPrivateResult(PipetteNozzleLayoutResultMixin):
43
- """Result sent to the store but not serialized."""
44
-
45
- pass
46
-
47
-
48
40
  class ConfigureNozzleLayoutResult(BaseModel):
49
41
  """Result data from execution of an configureNozzleLayout command."""
50
42
 
@@ -54,7 +46,7 @@ class ConfigureNozzleLayoutResult(BaseModel):
54
46
  class ConfigureNozzleLayoutImplementation(
55
47
  AbstractCommandImpl[
56
48
  ConfigureNozzleLayoutParams,
57
- SuccessData[ConfigureNozzleLayoutResult, ConfigureNozzleLayoutPrivateResult],
49
+ SuccessData[ConfigureNozzleLayoutResult],
58
50
  ]
59
51
  ):
60
52
  """Configure nozzle layout command implementation."""
@@ -67,7 +59,7 @@ class ConfigureNozzleLayoutImplementation(
67
59
 
68
60
  async def execute(
69
61
  self, params: ConfigureNozzleLayoutParams
70
- ) -> SuccessData[ConfigureNozzleLayoutResult, ConfigureNozzleLayoutPrivateResult]:
62
+ ) -> SuccessData[ConfigureNozzleLayoutResult]:
71
63
  """Check that requested pipette can support the requested nozzle layout."""
72
64
  primary_nozzle = params.configurationParams.dict().get("primaryNozzle")
73
65
  front_right_nozzle = params.configurationParams.dict().get("frontRightNozzle")
@@ -85,12 +77,14 @@ class ConfigureNozzleLayoutImplementation(
85
77
  **nozzle_params,
86
78
  )
87
79
 
80
+ update_state = StateUpdate()
81
+ update_state.update_pipette_nozzle(
82
+ pipette_id=params.pipetteId, nozzle_map=nozzle_map
83
+ )
84
+
88
85
  return SuccessData(
89
86
  public=ConfigureNozzleLayoutResult(),
90
- private=ConfigureNozzleLayoutPrivateResult(
91
- pipette_id=params.pipetteId,
92
- nozzle_map=nozzle_map,
93
- ),
87
+ state_update=update_state,
94
88
  )
95
89
 
96
90
 
@@ -40,16 +40,18 @@ class CustomResult(BaseModel):
40
40
 
41
41
 
42
42
  class CustomImplementation(
43
- AbstractCommandImpl[CustomParams, SuccessData[CustomResult, None]]
43
+ AbstractCommandImpl[CustomParams, SuccessData[CustomResult]]
44
44
  ):
45
45
  """Custom command implementation."""
46
46
 
47
47
  # TODO(mm, 2022-11-09): figure out how a plugin can specify a custom command
48
48
  # implementation. For now, always no-op, so we can use custom commands as containers
49
49
  # for legacy RPC (pre-ProtocolEngine) payloads.
50
- async def execute(self, params: CustomParams) -> SuccessData[CustomResult, None]:
50
+ async def execute(self, params: CustomParams) -> SuccessData[CustomResult]:
51
51
  """A custom command does nothing when executed directly."""
52
- return SuccessData(public=CustomResult.construct(), private=None)
52
+ return SuccessData(
53
+ public=CustomResult.construct(),
54
+ )
53
55
 
54
56
 
55
57
  class Custom(BaseCommand[CustomParams, CustomResult, ErrorOccurrence]):
@@ -8,15 +8,15 @@ from opentrons_shared_data.errors.exceptions import PipetteOverpressureError
8
8
  from pydantic import Field
9
9
 
10
10
  from ..types import DeckPoint
11
+ from ..state.update_types import StateUpdate, CLEAR
11
12
  from .pipetting_common import (
12
13
  PipetteIdMixin,
13
14
  DispenseVolumeMixin,
14
15
  FlowRateMixin,
15
- WellLocationMixin,
16
+ LiquidHandlingWellLocationMixin,
16
17
  BaseLiquidHandlingResult,
17
18
  DestinationPositionResult,
18
19
  OverpressureError,
19
- OverpressureErrorInternalData,
20
20
  )
21
21
  from .command import (
22
22
  AbstractCommandImpl,
@@ -30,13 +30,14 @@ from ..errors.error_occurrence import ErrorOccurrence
30
30
  if TYPE_CHECKING:
31
31
  from ..execution import MovementHandler, PipettingHandler
32
32
  from ..resources import ModelUtils
33
+ from ..state.state import StateView
33
34
 
34
35
 
35
36
  DispenseCommandType = Literal["dispense"]
36
37
 
37
38
 
38
39
  class DispenseParams(
39
- PipetteIdMixin, DispenseVolumeMixin, FlowRateMixin, WellLocationMixin
40
+ PipetteIdMixin, DispenseVolumeMixin, FlowRateMixin, LiquidHandlingWellLocationMixin
40
41
  ):
41
42
  """Payload required to dispense to a specific well."""
42
43
 
@@ -53,8 +54,8 @@ class DispenseResult(BaseLiquidHandlingResult, DestinationPositionResult):
53
54
 
54
55
 
55
56
  _ExecuteReturn = Union[
56
- SuccessData[DispenseResult, None],
57
- DefinedErrorData[OverpressureError, OverpressureErrorInternalData],
57
+ SuccessData[DispenseResult],
58
+ DefinedErrorData[OverpressureError],
58
59
  ]
59
60
 
60
61
 
@@ -63,31 +64,54 @@ class DispenseImplementation(AbstractCommandImpl[DispenseParams, _ExecuteReturn]
63
64
 
64
65
  def __init__(
65
66
  self,
67
+ state_view: StateView,
66
68
  movement: MovementHandler,
67
69
  pipetting: PipettingHandler,
68
70
  model_utils: ModelUtils,
69
71
  **kwargs: object,
70
72
  ) -> None:
73
+ self._state_view = state_view
71
74
  self._movement = movement
72
75
  self._pipetting = pipetting
73
76
  self._model_utils = model_utils
74
77
 
75
78
  async def execute(self, params: DispenseParams) -> _ExecuteReturn:
76
79
  """Move to and dispense to the requested well."""
80
+ state_update = StateUpdate()
81
+ well_location = params.wellLocation
82
+ labware_id = params.labwareId
83
+ well_name = params.wellName
84
+ volume = params.volume
85
+
86
+ # TODO(pbm, 10-15-24): call self._state_view.geometry.validate_dispense_volume_into_well()
87
+
77
88
  position = await self._movement.move_to_well(
78
89
  pipette_id=params.pipetteId,
79
- labware_id=params.labwareId,
80
- well_name=params.wellName,
81
- well_location=params.wellLocation,
90
+ labware_id=labware_id,
91
+ well_name=well_name,
92
+ well_location=well_location,
82
93
  )
94
+ deck_point = DeckPoint.construct(x=position.x, y=position.y, z=position.z)
95
+ state_update.set_pipette_location(
96
+ pipette_id=params.pipetteId,
97
+ new_labware_id=labware_id,
98
+ new_well_name=well_name,
99
+ new_deck_point=deck_point,
100
+ )
101
+
83
102
  try:
84
103
  volume = await self._pipetting.dispense_in_place(
85
104
  pipette_id=params.pipetteId,
86
- volume=params.volume,
105
+ volume=volume,
87
106
  flow_rate=params.flowRate,
88
107
  push_out=params.pushOut,
89
108
  )
90
109
  except PipetteOverpressureError as e:
110
+ state_update.set_liquid_operated(
111
+ labware_id=labware_id,
112
+ well_name=well_name,
113
+ volume_added=CLEAR,
114
+ )
91
115
  return DefinedErrorData(
92
116
  public=OverpressureError(
93
117
  id=self._model_utils.generate_id(),
@@ -101,23 +125,21 @@ class DispenseImplementation(AbstractCommandImpl[DispenseParams, _ExecuteReturn]
101
125
  ],
102
126
  errorInfo={"retryLocation": (position.x, position.y, position.z)},
103
127
  ),
104
- private=OverpressureErrorInternalData(
105
- position=DeckPoint.construct(
106
- x=position.x, y=position.y, z=position.z
107
- )
108
- ),
128
+ state_update=state_update,
109
129
  )
110
130
  else:
131
+ state_update.set_liquid_operated(
132
+ labware_id=labware_id,
133
+ well_name=well_name,
134
+ volume_added=volume,
135
+ )
111
136
  return SuccessData(
112
- public=DispenseResult(
113
- volume=volume,
114
- position=DeckPoint(x=position.x, y=position.y, z=position.z),
115
- ),
116
- private=None,
137
+ public=DispenseResult(volume=volume, position=deck_point),
138
+ state_update=state_update,
117
139
  )
118
140
 
119
141
 
120
- class Dispense(BaseCommand[DispenseParams, DispenseResult, ErrorOccurrence]):
142
+ class Dispense(BaseCommand[DispenseParams, DispenseResult, OverpressureError]):
121
143
  """Dispense command model."""
122
144
 
123
145
  commandType: DispenseCommandType = "dispense"