opentrons 8.7.0a7__py3-none-any.whl → 8.7.0a9__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.

Potentially problematic release.


This version of opentrons might be problematic. Click here for more details.

Files changed (147) hide show
  1. opentrons/_version.py +2 -2
  2. opentrons/drivers/asyncio/communication/serial_connection.py +55 -129
  3. opentrons/drivers/flex_stacker/driver.py +6 -1
  4. opentrons/drivers/heater_shaker/abstract.py +0 -5
  5. opentrons/drivers/heater_shaker/driver.py +0 -10
  6. opentrons/drivers/heater_shaker/simulator.py +0 -4
  7. opentrons/drivers/thermocycler/abstract.py +0 -6
  8. opentrons/drivers/thermocycler/driver.py +10 -61
  9. opentrons/drivers/thermocycler/simulator.py +0 -6
  10. opentrons/hardware_control/api.py +5 -24
  11. opentrons/hardware_control/backends/controller.py +2 -8
  12. opentrons/hardware_control/backends/flex_protocol.py +1 -0
  13. opentrons/hardware_control/backends/ot3controller.py +3 -3
  14. opentrons/hardware_control/backends/ot3simulator.py +2 -2
  15. opentrons/hardware_control/backends/simulator.py +1 -2
  16. opentrons/hardware_control/backends/subsystem_manager.py +2 -5
  17. opentrons/hardware_control/emulation/abstract_emulator.py +4 -6
  18. opentrons/hardware_control/emulation/connection_handler.py +5 -8
  19. opentrons/hardware_control/emulation/heater_shaker.py +3 -12
  20. opentrons/hardware_control/emulation/settings.py +1 -1
  21. opentrons/hardware_control/emulation/thermocycler.py +15 -67
  22. opentrons/hardware_control/module_control.py +8 -82
  23. opentrons/hardware_control/modules/__init__.py +0 -3
  24. opentrons/hardware_control/modules/absorbance_reader.py +4 -11
  25. opentrons/hardware_control/modules/flex_stacker.py +9 -38
  26. opentrons/hardware_control/modules/heater_shaker.py +5 -42
  27. opentrons/hardware_control/modules/magdeck.py +4 -8
  28. opentrons/hardware_control/modules/mod_abc.py +5 -13
  29. opentrons/hardware_control/modules/tempdeck.py +5 -25
  30. opentrons/hardware_control/modules/thermocycler.py +11 -68
  31. opentrons/hardware_control/modules/types.py +1 -20
  32. opentrons/hardware_control/modules/utils.py +4 -11
  33. opentrons/hardware_control/nozzle_manager.py +0 -3
  34. opentrons/hardware_control/ot3api.py +7 -26
  35. opentrons/hardware_control/poller.py +8 -22
  36. opentrons/hardware_control/protocols/gripper_controller.py +1 -0
  37. opentrons/hardware_control/scripts/update_module_fw.py +0 -5
  38. opentrons/hardware_control/types.py +2 -31
  39. opentrons/legacy_commands/module_commands.py +0 -23
  40. opentrons/legacy_commands/protocol_commands.py +0 -20
  41. opentrons/legacy_commands/types.py +0 -80
  42. opentrons/motion_planning/deck_conflict.py +12 -17
  43. opentrons/motion_planning/waypoints.py +29 -15
  44. opentrons/protocol_api/__init__.py +1 -5
  45. opentrons/protocol_api/_types.py +1 -6
  46. opentrons/protocol_api/core/common.py +1 -3
  47. opentrons/protocol_api/core/engine/_default_labware_versions.py +11 -32
  48. opentrons/protocol_api/core/engine/labware.py +1 -8
  49. opentrons/protocol_api/core/engine/module_core.py +8 -75
  50. opentrons/protocol_api/core/engine/protocol.py +1 -18
  51. opentrons/protocol_api/core/engine/well.py +0 -8
  52. opentrons/protocol_api/core/legacy/legacy_module_core.py +4 -24
  53. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +1 -11
  54. opentrons/protocol_api/core/legacy/legacy_well_core.py +0 -4
  55. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +2 -14
  56. opentrons/protocol_api/core/module.py +4 -37
  57. opentrons/protocol_api/core/protocol.py +2 -11
  58. opentrons/protocol_api/core/well.py +0 -4
  59. opentrons/protocol_api/labware.py +0 -5
  60. opentrons/protocol_api/module_contexts.py +61 -122
  61. opentrons/protocol_api/protocol_context.py +4 -26
  62. opentrons/protocol_api/robot_context.py +21 -38
  63. opentrons/protocol_api/validation.py +1 -6
  64. opentrons/protocol_engine/actions/__init__.py +2 -4
  65. opentrons/protocol_engine/actions/actions.py +9 -22
  66. opentrons/protocol_engine/clients/sync_client.py +7 -42
  67. opentrons/protocol_engine/commands/__init__.py +0 -42
  68. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +15 -2
  69. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +15 -2
  70. opentrons/protocol_engine/commands/aspirate.py +0 -1
  71. opentrons/protocol_engine/commands/command.py +0 -1
  72. opentrons/protocol_engine/commands/command_unions.py +0 -49
  73. opentrons/protocol_engine/commands/dispense.py +0 -1
  74. opentrons/protocol_engine/commands/drop_tip.py +8 -32
  75. opentrons/protocol_engine/commands/heater_shaker/__init__.py +0 -14
  76. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +4 -5
  77. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +5 -31
  78. opentrons/protocol_engine/commands/movement_common.py +0 -2
  79. opentrons/protocol_engine/commands/pick_up_tip.py +11 -21
  80. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +7 -38
  81. opentrons/protocol_engine/commands/thermocycler/__init__.py +0 -16
  82. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +0 -6
  83. opentrons/protocol_engine/commands/thermocycler/run_profile.py +0 -8
  84. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +6 -40
  85. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +5 -29
  86. opentrons/protocol_engine/commands/touch_tip.py +1 -1
  87. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +22 -6
  88. opentrons/protocol_engine/errors/__init__.py +0 -4
  89. opentrons/protocol_engine/errors/exceptions.py +0 -55
  90. opentrons/protocol_engine/execution/__init__.py +0 -2
  91. opentrons/protocol_engine/execution/command_executor.py +0 -8
  92. opentrons/protocol_engine/execution/create_queue_worker.py +1 -5
  93. opentrons/protocol_engine/execution/labware_movement.py +21 -10
  94. opentrons/protocol_engine/execution/movement.py +0 -2
  95. opentrons/protocol_engine/execution/queue_worker.py +0 -4
  96. opentrons/protocol_engine/execution/run_control.py +0 -8
  97. opentrons/protocol_engine/protocol_engine.py +34 -75
  98. opentrons/protocol_engine/resources/__init__.py +0 -2
  99. opentrons/protocol_engine/resources/deck_configuration_provider.py +0 -7
  100. opentrons/protocol_engine/resources/labware_validation.py +6 -10
  101. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  102. opentrons/protocol_engine/state/_well_math.py +18 -60
  103. opentrons/protocol_engine/state/addressable_areas.py +0 -2
  104. opentrons/protocol_engine/state/commands.py +11 -14
  105. opentrons/protocol_engine/state/geometry.py +374 -213
  106. opentrons/protocol_engine/state/labware.py +102 -52
  107. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +0 -37
  108. opentrons/protocol_engine/state/modules.py +8 -21
  109. opentrons/protocol_engine/state/motion.py +0 -44
  110. opentrons/protocol_engine/state/state.py +0 -14
  111. opentrons/protocol_engine/state/state_summary.py +0 -2
  112. opentrons/protocol_engine/state/tips.py +258 -177
  113. opentrons/protocol_engine/state/update_types.py +9 -16
  114. opentrons/protocol_engine/types/__init__.py +3 -9
  115. opentrons/protocol_engine/types/deck_configuration.py +1 -5
  116. opentrons/protocol_engine/types/instrument.py +1 -8
  117. opentrons/protocol_engine/types/labware.py +13 -1
  118. opentrons/protocol_engine/types/module.py +0 -10
  119. opentrons/protocol_engine/types/tip.py +0 -9
  120. opentrons/protocol_runner/create_simulating_orchestrator.py +2 -29
  121. opentrons/protocol_runner/run_orchestrator.py +2 -18
  122. opentrons/protocols/api_support/definitions.py +1 -1
  123. opentrons/protocols/api_support/types.py +1 -2
  124. opentrons/simulate.py +15 -48
  125. opentrons/system/camera.py +1 -1
  126. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/METADATA +4 -4
  127. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/RECORD +130 -146
  128. opentrons/protocol_api/core/engine/tasks.py +0 -48
  129. opentrons/protocol_api/core/legacy/tasks.py +0 -19
  130. opentrons/protocol_api/core/legacy_simulator/tasks.py +0 -19
  131. opentrons/protocol_api/core/tasks.py +0 -31
  132. opentrons/protocol_api/tasks.py +0 -48
  133. opentrons/protocol_engine/commands/create_timer.py +0 -83
  134. opentrons/protocol_engine/commands/heater_shaker/common.py +0 -20
  135. opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +0 -136
  136. opentrons/protocol_engine/commands/set_tip_state.py +0 -97
  137. opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +0 -191
  138. opentrons/protocol_engine/commands/wait_for_tasks.py +0 -98
  139. opentrons/protocol_engine/execution/task_handler.py +0 -157
  140. opentrons/protocol_engine/resources/concurrency_provider.py +0 -27
  141. opentrons/protocol_engine/state/labware_origin_math/errors.py +0 -94
  142. opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +0 -1331
  143. opentrons/protocol_engine/state/tasks.py +0 -139
  144. opentrons/protocol_engine/types/tasks.py +0 -38
  145. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/WHEEL +0 -0
  146. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/entry_points.txt +0 -0
  147. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/licenses/LICENSE +0 -0
@@ -413,36 +413,6 @@ class WellDoesNotExistError(ProtocolEngineError):
413
413
  super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping)
414
414
 
415
415
 
416
- class NoTaskFoundError(ProtocolEngineError):
417
- """Raised when referencing a task that does not exist.
418
-
419
- This error could be raised if a protocol references a task before it
420
- has been created.
421
- """
422
-
423
- def __init__(
424
- self,
425
- message: Optional[str] = None,
426
- details: Optional[Dict[str, Any]] = None,
427
- wrapping: Optional[Sequence[EnumeratedError]] = None,
428
- ) -> None:
429
- """Build a NoTaskFoundError."""
430
- super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping)
431
-
432
-
433
- class TaskFailedError(ProtocolEngineError):
434
- """Raised when waiting on a task that failed."""
435
-
436
- def __init__(
437
- self,
438
- message: Optional[str] = None,
439
- details: Optional[Dict[str, Any]] = None,
440
- wrapping: Optional[Sequence[EnumeratedError]] = None,
441
- ) -> None:
442
- """Build a TaskFailedError."""
443
- super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping)
444
-
445
-
446
416
  class PipetteNotLoadedError(ProtocolEngineError):
447
417
  """Raised when referencing a pipette that has not been loaded."""
448
418
 
@@ -855,19 +825,6 @@ class InvalidTargetTemperatureError(ProtocolEngineError):
855
825
  super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping)
856
826
 
857
827
 
858
- class InvalidRampRateError(ProtocolEngineError):
859
- """Raised when attempting to set an invalid ramp rate."""
860
-
861
- def __init__(
862
- self,
863
- message: Optional[str] = None,
864
- details: Optional[Dict[str, Any]] = None,
865
- wrapping: Optional[Sequence[EnumeratedError]] = None,
866
- ) -> None:
867
- """Build a InvalidRampRateError."""
868
- super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping)
869
-
870
-
871
828
  class InvalidBlockVolumeError(ProtocolEngineError):
872
829
  """Raised when attempting to set an invalid block max volume."""
873
830
 
@@ -1349,15 +1306,3 @@ class InvalidLabwarePositionError(ProtocolEngineError):
1349
1306
  wrapping: Optional[Sequence[EnumeratedError]] = None,
1350
1307
  ) -> None:
1351
1308
  super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping)
1352
-
1353
-
1354
- class InvalidModuleOrientation(ProtocolEngineError):
1355
- """Raised when a module orientation is invalid for a slot id."""
1356
-
1357
- def __init__(
1358
- self,
1359
- message: Optional[str] = None,
1360
- details: Optional[dict[str, Any]] = None,
1361
- wrapping: Optional[Sequence[EnumeratedError]] = None,
1362
- ) -> None:
1363
- super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping)
@@ -21,7 +21,6 @@ from .run_control import RunControlHandler
21
21
  from .hardware_stopper import HardwareStopper
22
22
  from .door_watcher import DoorWatcher
23
23
  from .status_bar import StatusBarHandler
24
- from .task_handler import TaskHandler
25
24
  from ..resources.file_provider import FileProvider
26
25
 
27
26
  # .thermocycler_movement_flagger omitted from package's public interface.
@@ -47,6 +46,5 @@ __all__ = [
47
46
  "DoorWatcher",
48
47
  "RailLightsHandler",
49
48
  "StatusBarHandler",
50
- "TaskHandler",
51
49
  "FileProvider",
52
50
  ]
@@ -35,7 +35,6 @@ from .tip_handler import TipHandler
35
35
  from .run_control import RunControlHandler
36
36
  from .rail_lights import RailLightsHandler
37
37
  from .status_bar import StatusBarHandler
38
- from .task_handler import TaskHandler
39
38
 
40
39
 
41
40
  log = getLogger(__name__)
@@ -86,7 +85,6 @@ class CommandExecutor:
86
85
  run_control: RunControlHandler,
87
86
  rail_lights: RailLightsHandler,
88
87
  status_bar: StatusBarHandler,
89
- task_handler: TaskHandler,
90
88
  model_utils: Optional[ModelUtils] = None,
91
89
  command_note_tracker_provider: Optional[CommandNoteTrackerProvider] = None,
92
90
  ) -> None:
@@ -108,7 +106,6 @@ class CommandExecutor:
108
106
  self._command_note_tracker_provider = (
109
107
  command_note_tracker_provider or _NoteTracker
110
108
  )
111
- self._task_handler = task_handler
112
109
 
113
110
  async def execute(self, command_id: str) -> None:
114
111
  """Run a given command's execution procedure.
@@ -134,7 +131,6 @@ class CommandExecutor:
134
131
  model_utils=self._model_utils,
135
132
  status_bar=self._status_bar,
136
133
  command_note_adder=note_tracker,
137
- task_handler=self._task_handler,
138
134
  )
139
135
 
140
136
  started_at = self._model_utils.get_timestamp()
@@ -218,7 +214,3 @@ class CommandExecutor:
218
214
  type=error_recovery_type,
219
215
  )
220
216
  )
221
-
222
- def cancel_tasks(self, message: str | None = None) -> None:
223
- """Cancel all concurrent tasks."""
224
- self._task_handler.cancel_all(message=message)
@@ -17,7 +17,6 @@ from .run_control import RunControlHandler
17
17
  from .command_executor import CommandExecutor
18
18
  from .queue_worker import QueueWorker
19
19
  from .status_bar import StatusBarHandler
20
- from .task_handler import TaskHandler
21
20
 
22
21
 
23
22
  def create_queue_worker(
@@ -77,9 +76,7 @@ def create_queue_worker(
77
76
  rail_lights_handler = RailLightsHandler(
78
77
  hardware_api=hardware_api,
79
78
  )
80
- task_handler = TaskHandler(
81
- state_store=state_store, action_dispatcher=action_dispatcher
82
- )
79
+
83
80
  status_bar_handler = StatusBarHandler(hardware_api=hardware_api)
84
81
 
85
82
  command_executor = CommandExecutor(
@@ -96,7 +93,6 @@ def create_queue_worker(
96
93
  run_control=run_control_handler,
97
94
  rail_lights=rail_lights_handler,
98
95
  status_bar=status_bar_handler,
99
- task_handler=task_handler,
100
96
  )
101
97
 
102
98
  return QueueWorker(
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Optional, TYPE_CHECKING, overload
6
6
 
7
- from opentrons_shared_data.labware.labware_definition import LabwareDefinition
7
+ from opentrons_shared_data.labware.labware_definition import LabwareDefinition, Quirks
8
8
 
9
9
  from opentrons.types import Point
10
10
 
@@ -31,7 +31,6 @@ from ..types import (
31
31
  OnLabwareLocation,
32
32
  LabwareLocation,
33
33
  OnDeckLabwareLocation,
34
- GripperMoveType,
35
34
  )
36
35
 
37
36
  if TYPE_CHECKING:
@@ -142,16 +141,10 @@ class LabwareMovementHandler:
142
141
  labware_definition = self._state_store.labware.get_definition(labware_id)
143
142
 
144
143
  from_labware_center = self._state_store.geometry.get_labware_grip_point(
145
- labware_definition=labware_definition,
146
- location=current_location,
147
- move_type=GripperMoveType.PICK_UP_LABWARE,
148
- user_additional_offset=user_pick_up_offset,
144
+ labware_definition=labware_definition, location=current_location
149
145
  )
150
146
  to_labware_center = self._state_store.geometry.get_labware_grip_point(
151
- labware_definition=labware_definition,
152
- location=new_location,
153
- move_type=GripperMoveType.DROP_LABWARE,
154
- user_additional_offset=user_drop_offset,
147
+ labware_definition=labware_definition, location=new_location
155
148
  )
156
149
 
157
150
  if use_virtual_gripper:
@@ -200,10 +193,20 @@ class LabwareMovementHandler:
200
193
  async with self._thermocycler_plate_lifter.lift_plate_for_labware_movement(
201
194
  labware_location=current_location
202
195
  ):
196
+ final_offsets = (
197
+ self._state_store.geometry.get_final_labware_movement_offset_vectors(
198
+ from_location=current_location,
199
+ to_location=new_location,
200
+ additional_pick_up_offset=user_pick_up_offset,
201
+ additional_drop_offset=user_drop_offset,
202
+ current_labware=labware_definition,
203
+ )
204
+ )
203
205
  movement_waypoints = get_gripper_labware_movement_waypoints(
204
206
  from_labware_center=from_labware_center,
205
207
  to_labware_center=to_labware_center,
206
208
  gripper_home_z=gripper_homed_position.z,
209
+ offset_data=final_offsets,
207
210
  post_drop_slide_offset=post_drop_slide_offset,
208
211
  gripper_home_z_offset=gripper_z_offset,
209
212
  )
@@ -235,6 +238,13 @@ class LabwareMovementHandler:
235
238
  labware_definition=labware_definition
236
239
  )
237
240
 
241
+ disable_geometry_grip_check = False
242
+ if labware_definition.parameters.quirks is not None:
243
+ disable_geometry_grip_check = (
244
+ Quirks.disableGeometryBasedGripCheck.value
245
+ in labware_definition.parameters.quirks
246
+ )
247
+
238
248
  # todo(mm, 2024-09-26): This currently raises a lower-level 2015 FailedGripperPickupError.
239
249
  # Convert this to a higher-level 3001 LabwareDroppedError or 3002 LabwareNotPickedUpError,
240
250
  # depending on what waypoint we're at, to propagate a more specific error code to users.
@@ -242,6 +252,7 @@ class LabwareMovementHandler:
242
252
  expected_grip_width=grip_specs.targetY,
243
253
  grip_width_uncertainty_wider=grip_specs.uncertaintyWider,
244
254
  grip_width_uncertainty_narrower=grip_specs.uncertaintyNarrower,
255
+ disable_geometry_grip_check=disable_geometry_grip_check,
245
256
  )
246
257
  await ot3api.move_to(
247
258
  mount=gripper_mount, abs_position=waypoint_data.position
@@ -83,7 +83,6 @@ class MovementHandler:
83
83
  minimum_z_height: Optional[float] = None,
84
84
  speed: Optional[float] = None,
85
85
  operation_volume: Optional[float] = None,
86
- offset_pipette_for_reservoir_subwells: bool = False,
87
86
  ) -> Point:
88
87
  """Move to a specific well."""
89
88
  self._state_store.geometry.raise_if_labware_inaccessible_by_pipette(
@@ -144,7 +143,6 @@ class MovementHandler:
144
143
  force_direct=force_direct,
145
144
  minimum_z_height=minimum_z_height,
146
145
  operation_volume=operation_volume,
147
- offset_pipette_for_reservoir_subwells=offset_pipette_for_reservoir_subwells,
148
146
  )
149
147
 
150
148
  speed = self._state_store.pipettes.get_movement_speed(
@@ -51,7 +51,6 @@ class QueueWorker:
51
51
  """
52
52
  if self._worker_task:
53
53
  self._worker_task.cancel()
54
- self._command_executor.cancel_tasks("Engine cancelled")
55
54
 
56
55
  async def join(self) -> None:
57
56
  """Wait for the worker to finish, propagating any errors."""
@@ -66,10 +65,7 @@ class QueueWorker:
66
65
  pass
67
66
  except Exception as e:
68
67
  log.error("Unhandled exception in QueueWorker job", exc_info=e)
69
- self._command_executor.cancel_tasks("Engine failed")
70
68
  raise e
71
- else:
72
- self._command_executor.cancel_tasks("Engine commands complete")
73
69
 
74
70
  async def _run_commands(self) -> None:
75
71
  async for command_id in self._command_generator():
@@ -31,11 +31,3 @@ class RunControlHandler:
31
31
  """Delay protocol execution for a duration."""
32
32
  if not self._state_store.config.ignore_pause:
33
33
  await asyncio.sleep(seconds)
34
-
35
- async def wait_for_tasks(self, tasks: list[str]) -> None:
36
- """Wait for concurrent tasks to complete."""
37
- await self._state_store.wait_for(
38
- condition=lambda: self._state_store.tasks.all_tasks_finished_or_any_task_failed(
39
- task_ids=tasks
40
- )
41
- )
@@ -59,6 +59,7 @@ from .actions import (
59
59
  AddAddressableAreaAction,
60
60
  AddModuleAction,
61
61
  HardwareStoppedAction,
62
+ ResetTipsAction,
62
63
  SetPipetteMovementSpeedAction,
63
64
  )
64
65
 
@@ -321,10 +322,24 @@ class ProtocolEngine:
321
322
  )
322
323
  return completed_command
323
324
 
324
- def _stop_from_asynchronous_error(self) -> None:
325
+ def estop(self) -> None:
326
+ """Signal to the engine that an E-stop event occurred.
327
+
328
+ If an estop happens while the robot is moving, lower layers physically stop
329
+ motion and raise the event as an exception, which fails the Protocol Engine
330
+ command. No action from the `ProtocolEngine` caller is needed to handle that.
331
+
332
+ However, if an estop happens in between commands, or in the middle of
333
+ a command like `comment` or `waitForDuration` that doesn't access the hardware,
334
+ `ProtocolEngine` needs to be told about it so it can interrupt the command
335
+ and stop executing any more. This method is how to do that.
336
+
337
+ This acts roughly like `request_stop()`. After calling this, you should call
338
+ `finish()` with an EStopActivatedError.
339
+ """
325
340
  try:
326
341
  action = self._state_store.commands.validate_action_allowed(
327
- StopAction(from_asynchronous_error=True)
342
+ StopAction(from_estop=True)
328
343
  )
329
344
  except Exception: # todo(mm, 2024-04-16): Catch a more specific type.
330
345
  # This is likely called from some hardware API callback that doesn't care
@@ -343,79 +358,9 @@ class ProtocolEngine:
343
358
  # do this because we want to make sure non-hardware commands, like
344
359
  # `waitForDuration`, are also interrupted.
345
360
  self._get_queue_worker.cancel()
346
-
347
- def estop(self) -> None:
348
- """Signal to the engine that an E-stop event occurred.
349
-
350
- If an estop happens while the robot is moving, lower layers physically stop
351
- motion and raise the event as an exception, which fails the Protocol Engine
352
- command. No action from the `ProtocolEngine` caller is needed to handle that.
353
-
354
- However, if an estop happens in between commands, or in the middle of
355
- a command like `comment` or `waitForDuration` that doesn't access the hardware,
356
- `ProtocolEngine` needs to be told about it so it can interrupt the command
357
- and stop executing any more. This method is how to do that.
358
-
359
- This acts roughly like `request_stop()`. After calling this, you should call
360
- `finish()` with an EStopActivatedError.
361
- """
362
361
  # Unlike self.request_stop(), we don't need to do
363
362
  # self._hardware_api.cancel_execution_and_running_tasks(). Since this was an
364
363
  # E-stop event, the hardware API already knows.
365
- self._stop_from_asynchronous_error()
366
-
367
- async def async_module_error(
368
- self, module_model: ModuleModel, serial: str | None
369
- ) -> bool:
370
- """Signal to the engine that an asynchronous module error occured.
371
-
372
- The return value of this function signals whether the error is relevant to the protocol
373
- or not. If the function returns True, the error is relevant. The engine will stop, and
374
- the caller should call `finish()` with the error object that signaled the error. If
375
- the function returns False, the error is not relevant. The engine will not stop, and the
376
- caller should not call `finish()`.
377
-
378
- Asynchronous module errors are signaled when a module enters a hardware error state
379
- - for instance, a thermocycler's thermistors fail because of condensation, or a
380
- heater-shaker's wires fray and snap, or a module is accidentally disconnected. These
381
- errors are not related to a particular command, even a currently-happening module
382
- control command for the module in the error state.
383
-
384
- Similar to an estop error, the error can occur at any time relative to the lifecycle
385
- of the engine run or of any particular command.
386
-
387
- Unlike an estop, the motion control hardware will not be raising an error and will not
388
- stop on its own; the stop action derived from this call will do that.
389
- """
390
- if not self._state_store.modules.get_has_module_probably_matching_hardware_details(
391
- module_model, serial
392
- ):
393
- return False
394
-
395
- if self._state_store.commands.get_is_terminal():
396
- # Do not stop multiple times; it will be common for this action to fire
397
- # many times when a module enters an error state, and we don't want to do
398
- # the stop behavior over and over
399
- return False
400
-
401
- self._stop_from_asynchronous_error()
402
- # like self.request_stop, and unlike self.estop(), we must explicitly request that the
403
- # hardware stops execution, since not all asynchronous errors will cause the hardware
404
- # to know that it should stop.
405
- await self._do_hardware_stop()
406
- return True
407
-
408
- async def _do_hardware_stop(self) -> None:
409
- """Make the hardware stop now."""
410
- if self._hardware_api.is_movement_execution_taskified():
411
- # We 'taskify' hardware controller movement functions when running protocols
412
- # that are not backed by the engine. Such runs cannot be stopped by cancelling
413
- # the queue worker and hence need to be stopped via the execution manager.
414
- # `cancel_execution_and_running_tasks()` sets the execution manager in a CANCELLED state
415
- # and cancels the running tasks, which raises an error and gets us out of the
416
- # run function execution, just like `_queue_worker.cancel()` does for
417
- # engine-backed runs.
418
- await self._hardware_api.cancel_execution_and_running_tasks()
419
364
 
420
365
  async def request_stop(self) -> None:
421
366
  """Make command execution stop soon.
@@ -433,7 +378,15 @@ class ProtocolEngine:
433
378
  action = self._state_store.commands.validate_action_allowed(StopAction())
434
379
  self._action_dispatcher.dispatch(action)
435
380
  self._get_queue_worker.cancel()
436
- await self._do_hardware_stop()
381
+ if self._hardware_api.is_movement_execution_taskified():
382
+ # We 'taskify' hardware controller movement functions when running protocols
383
+ # that are not backed by the engine. Such runs cannot be stopped by cancelling
384
+ # the queue worker and hence need to be stopped via the execution manager.
385
+ # `cancel_execution_and_running_tasks()` sets the execution manager in a CANCELLED state
386
+ # and cancels the running tasks, which raises an error and gets us out of the
387
+ # run function execution, just like `_queue_worker.cancel()` does for
388
+ # engine-backed runs.
389
+ await self._hardware_api.cancel_execution_and_running_tasks()
437
390
 
438
391
  async def wait_until_complete(self) -> None:
439
392
  """Wait until there are no more commands to execute.
@@ -476,13 +429,13 @@ class ProtocolEngine:
476
429
  post_run_hardware_state: The state in which to leave the gantry and motors in
477
430
  after the run is over.
478
431
  """
479
- if self._state_store.commands.get_is_stopped_by_async_error():
432
+ if self._state_store.commands.get_is_stopped_by_estop():
480
433
  # This handles the case where the E-stop was pressed while we were *not* in the middle
481
434
  # of some hardware interaction that would raise it as an exception. For example, imagine
482
435
  # we were paused between two commands, or imagine we were executing a waitForDuration.
483
436
  drop_tips_after_run = False
484
437
  post_run_hardware_state = PostRunHardwareState.DISENGAGE_IN_PLACE
485
- if error is None and self._state_store.commands.get_error() is None:
438
+ if error is None:
486
439
  error = EStopActivatedError()
487
440
 
488
441
  if error:
@@ -633,6 +586,12 @@ class ProtocolEngine:
633
586
  AddAddressableAreaAction(addressable_area_name)
634
587
  )
635
588
 
589
+ def reset_tips(self, labware_id: str) -> None:
590
+ """Reset the tip state of a given labware."""
591
+ # TODO(mm, 2023-03-10): Safely raise an error if the given labware isn't a
592
+ # tip rack?
593
+ self._action_dispatcher.dispatch(ResetTipsAction(labware_id=labware_id))
594
+
636
595
  # TODO(mm, 2022-11-10): This is a method on ProtocolEngine instead of a command
637
596
  # as a quick hack to support Python protocols. We should consider making this a
638
597
  # command, or adding speed parameters to existing commands.
@@ -11,7 +11,6 @@ from .labware_data_provider import LabwareDataProvider
11
11
  from .module_data_provider import ModuleDataProvider
12
12
  from .file_provider import FileProvider
13
13
  from .ot3_validation import ensure_ot3_hardware
14
- from .concurrency_provider import ConcurrencyProvider
15
14
 
16
15
 
17
16
  __all__ = [
@@ -19,7 +18,6 @@ __all__ = [
19
18
  "LabwareDataProvider",
20
19
  "DeckDataProvider",
21
20
  "DeckFixedLabware",
22
- "ConcurrencyProvider",
23
21
  "ModuleDataProvider",
24
22
  "FileProvider",
25
23
  "ensure_ot3_hardware",
@@ -2,7 +2,6 @@
2
2
 
3
3
  from typing import List, Set, Tuple
4
4
 
5
- from opentrons_shared_data.module.types import ModuleOrientation
6
5
  from opentrons_shared_data.deck.types import (
7
6
  DeckDefinitionV5,
8
7
  CutoutFixture,
@@ -125,11 +124,6 @@ def get_addressable_area_from_name(
125
124
  z=addressable_area["boundingBox"]["zDimension"],
126
125
  )
127
126
  features = addressable_area["features"]
128
- orientation = (
129
- addressable_area["orientation"]
130
- if addressable_area["orientation"]
131
- else ModuleOrientation.NOT_APPLICABLE
132
- )
133
127
  mating_surface_unit_vector = addressable_area.get("matingSurfaceUnitVector")
134
128
 
135
129
  return AddressableArea(
@@ -144,7 +138,6 @@ def get_addressable_area_from_name(
144
138
  "compatibleModuleTypes", []
145
139
  ),
146
140
  features=features,
147
- orientation=orientation,
148
141
  )
149
142
  raise AddressableAreaDoesNotExistError(
150
143
  f"Could not find addressable area with name {addressable_area_name}"
@@ -2,7 +2,6 @@
2
2
 
3
3
  from opentrons_shared_data.labware.labware_definition import (
4
4
  LabwareDefinition,
5
- LabwareDefinition2,
6
5
  LabwareRole,
7
6
  )
8
7
 
@@ -45,18 +44,15 @@ def validate_definition_is_system(definition: LabwareDefinition) -> bool:
45
44
  return LabwareRole.system in definition.allowedRoles
46
45
 
47
46
 
48
- def validate_legacy_labware_can_be_stacked(
49
- child_labware_definition: LabwareDefinition2, parent_labware_load_name: str
47
+ def validate_labware_can_be_stacked(
48
+ top_labware_definition: LabwareDefinition, below_labware_load_name: str
50
49
  ) -> bool:
51
- """Validate that the parent labware is in the child labware's stackingOffsetWithLabware definition.
52
-
53
- Schema 3 Labware stacking validation is handled in locating features.
54
- """
50
+ """Validate that the labware being loaded onto is in the above labware's stackingOffsetWithLabware definition."""
55
51
  return (
56
- parent_labware_load_name in child_labware_definition.stackingOffsetWithLabware
52
+ below_labware_load_name in top_labware_definition.stackingOffsetWithLabware
57
53
  or (
58
- "default" in child_labware_definition.stackingOffsetWithLabware
59
- and child_labware_definition.compatibleParentLabware is None
54
+ "default" in top_labware_definition.stackingOffsetWithLabware
55
+ and top_labware_definition.compatibleParentLabware is None
60
56
  )
61
57
  )
62
58