opentrons 8.7.0a2__py3-none-any.whl → 8.7.0a4__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 (119) hide show
  1. opentrons/_version.py +2 -2
  2. opentrons/drivers/thermocycler/abstract.py +0 -1
  3. opentrons/drivers/thermocycler/driver.py +4 -33
  4. opentrons/drivers/thermocycler/simulator.py +0 -2
  5. opentrons/hardware_control/api.py +5 -24
  6. opentrons/hardware_control/backends/controller.py +2 -8
  7. opentrons/hardware_control/backends/ot3controller.py +0 -3
  8. opentrons/hardware_control/backends/ot3simulator.py +1 -2
  9. opentrons/hardware_control/backends/simulator.py +1 -2
  10. opentrons/hardware_control/backends/subsystem_manager.py +2 -5
  11. opentrons/hardware_control/module_control.py +8 -82
  12. opentrons/hardware_control/modules/__init__.py +0 -3
  13. opentrons/hardware_control/modules/absorbance_reader.py +4 -11
  14. opentrons/hardware_control/modules/flex_stacker.py +9 -38
  15. opentrons/hardware_control/modules/heater_shaker.py +5 -30
  16. opentrons/hardware_control/modules/magdeck.py +4 -8
  17. opentrons/hardware_control/modules/mod_abc.py +5 -13
  18. opentrons/hardware_control/modules/tempdeck.py +5 -25
  19. opentrons/hardware_control/modules/thermocycler.py +10 -56
  20. opentrons/hardware_control/modules/types.py +1 -20
  21. opentrons/hardware_control/modules/utils.py +4 -11
  22. opentrons/hardware_control/nozzle_manager.py +0 -3
  23. opentrons/hardware_control/ot3api.py +5 -26
  24. opentrons/hardware_control/scripts/update_module_fw.py +0 -5
  25. opentrons/hardware_control/types.py +2 -31
  26. opentrons/legacy_commands/protocol_commands.py +0 -20
  27. opentrons/legacy_commands/types.py +0 -42
  28. opentrons/motion_planning/waypoints.py +29 -15
  29. opentrons/protocol_api/__init__.py +0 -5
  30. opentrons/protocol_api/_types.py +1 -6
  31. opentrons/protocol_api/core/common.py +1 -3
  32. opentrons/protocol_api/core/engine/_default_labware_versions.py +11 -32
  33. opentrons/protocol_api/core/engine/labware.py +1 -8
  34. opentrons/protocol_api/core/engine/module_core.py +0 -4
  35. opentrons/protocol_api/core/engine/protocol.py +43 -23
  36. opentrons/protocol_api/core/legacy/legacy_module_core.py +0 -2
  37. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +1 -11
  38. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +2 -14
  39. opentrons/protocol_api/core/module.py +0 -1
  40. opentrons/protocol_api/core/protocol.py +2 -11
  41. opentrons/protocol_api/module_contexts.py +0 -1
  42. opentrons/protocol_api/protocol_context.py +4 -26
  43. opentrons/protocol_api/robot_context.py +21 -38
  44. opentrons/protocol_api/validation.py +1 -6
  45. opentrons/protocol_engine/actions/__init__.py +2 -4
  46. opentrons/protocol_engine/actions/actions.py +9 -22
  47. opentrons/protocol_engine/clients/sync_client.py +7 -6
  48. opentrons/protocol_engine/commands/__init__.py +0 -42
  49. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +15 -2
  50. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +15 -2
  51. opentrons/protocol_engine/commands/aspirate.py +0 -1
  52. opentrons/protocol_engine/commands/command.py +0 -1
  53. opentrons/protocol_engine/commands/command_unions.py +0 -39
  54. opentrons/protocol_engine/commands/dispense.py +0 -1
  55. opentrons/protocol_engine/commands/drop_tip.py +8 -32
  56. opentrons/protocol_engine/commands/movement_common.py +0 -2
  57. opentrons/protocol_engine/commands/pick_up_tip.py +11 -21
  58. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +0 -6
  59. opentrons/protocol_engine/commands/thermocycler/run_profile.py +0 -8
  60. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +1 -17
  61. opentrons/protocol_engine/commands/touch_tip.py +1 -1
  62. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +22 -6
  63. opentrons/protocol_engine/errors/__init__.py +0 -4
  64. opentrons/protocol_engine/errors/exceptions.py +0 -55
  65. opentrons/protocol_engine/execution/__init__.py +0 -2
  66. opentrons/protocol_engine/execution/command_executor.py +0 -8
  67. opentrons/protocol_engine/execution/create_queue_worker.py +1 -5
  68. opentrons/protocol_engine/execution/labware_movement.py +12 -9
  69. opentrons/protocol_engine/execution/movement.py +0 -2
  70. opentrons/protocol_engine/execution/queue_worker.py +0 -4
  71. opentrons/protocol_engine/execution/run_control.py +0 -8
  72. opentrons/protocol_engine/protocol_engine.py +33 -67
  73. opentrons/protocol_engine/resources/__init__.py +0 -2
  74. opentrons/protocol_engine/resources/deck_configuration_provider.py +0 -7
  75. opentrons/protocol_engine/resources/labware_validation.py +6 -10
  76. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  77. opentrons/protocol_engine/state/_well_math.py +18 -60
  78. opentrons/protocol_engine/state/addressable_areas.py +0 -2
  79. opentrons/protocol_engine/state/commands.py +7 -7
  80. opentrons/protocol_engine/state/geometry.py +374 -204
  81. opentrons/protocol_engine/state/labware.py +102 -52
  82. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +0 -37
  83. opentrons/protocol_engine/state/modules.py +8 -21
  84. opentrons/protocol_engine/state/motion.py +0 -44
  85. opentrons/protocol_engine/state/state.py +0 -14
  86. opentrons/protocol_engine/state/state_summary.py +0 -2
  87. opentrons/protocol_engine/state/tips.py +258 -177
  88. opentrons/protocol_engine/state/update_types.py +9 -16
  89. opentrons/protocol_engine/types/__init__.py +3 -9
  90. opentrons/protocol_engine/types/deck_configuration.py +1 -5
  91. opentrons/protocol_engine/types/instrument.py +1 -8
  92. opentrons/protocol_engine/types/labware.py +13 -1
  93. opentrons/protocol_engine/types/module.py +0 -10
  94. opentrons/protocol_engine/types/tip.py +0 -9
  95. opentrons/protocol_runner/create_simulating_orchestrator.py +2 -29
  96. opentrons/protocol_runner/run_orchestrator.py +2 -18
  97. opentrons/protocols/api_support/definitions.py +1 -1
  98. opentrons/protocols/api_support/types.py +1 -2
  99. opentrons/simulate.py +15 -48
  100. opentrons/system/camera.py +1 -1
  101. {opentrons-8.7.0a2.dist-info → opentrons-8.7.0a4.dist-info}/METADATA +4 -4
  102. {opentrons-8.7.0a2.dist-info → opentrons-8.7.0a4.dist-info}/RECORD +105 -118
  103. opentrons/protocol_api/core/engine/tasks.py +0 -35
  104. opentrons/protocol_api/core/legacy/tasks.py +0 -19
  105. opentrons/protocol_api/core/legacy_simulator/tasks.py +0 -19
  106. opentrons/protocol_api/core/tasks.py +0 -31
  107. opentrons/protocol_api/tasks.py +0 -48
  108. opentrons/protocol_engine/commands/create_timer.py +0 -83
  109. opentrons/protocol_engine/commands/set_tip_state.py +0 -97
  110. opentrons/protocol_engine/commands/wait_for_tasks.py +0 -98
  111. opentrons/protocol_engine/execution/task_handler.py +0 -157
  112. opentrons/protocol_engine/resources/concurrency_provider.py +0 -27
  113. opentrons/protocol_engine/state/labware_origin_math/errors.py +0 -94
  114. opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +0 -1331
  115. opentrons/protocol_engine/state/tasks.py +0 -139
  116. opentrons/protocol_engine/types/tasks.py +0 -38
  117. {opentrons-8.7.0a2.dist-info → opentrons-8.7.0a4.dist-info}/WHEEL +0 -0
  118. {opentrons-8.7.0a2.dist-info → opentrons-8.7.0a4.dist-info}/entry_points.txt +0 -0
  119. {opentrons-8.7.0a2.dist-info → opentrons-8.7.0a4.dist-info}/licenses/LICENSE +0 -0
opentrons/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '8.7.0a2'
32
- __version_tuple__ = version_tuple = (8, 7, 0, 'a2')
31
+ __version__ = version = '8.7.0a4'
32
+ __version_tuple__ = version_tuple = (8, 7, 0, 'a4')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -55,7 +55,6 @@ class AbstractThermocyclerDriver(ABC):
55
55
  temp: float,
56
56
  hold_time: Optional[float] = None,
57
57
  volume: Optional[float] = None,
58
- ramp_rate: Optional[float] = None,
59
58
  ) -> None:
60
59
  """Send set plate temperature command"""
61
60
  ...
@@ -226,7 +226,6 @@ class ThermocyclerDriver(AbstractThermocyclerDriver):
226
226
  temp: float,
227
227
  hold_time: Optional[float] = None,
228
228
  volume: Optional[float] = None,
229
- ramp_rate: Optional[float] = None,
230
229
  ) -> None:
231
230
  """Send set plate temperature command"""
232
231
  temp = min(BLOCK_TARGET_MAX, max(BLOCK_TARGET_MIN, temp))
@@ -344,38 +343,10 @@ class ThermocyclerDriverV2(ThermocyclerDriver):
344
343
  """
345
344
  super().__init__(connection)
346
345
 
347
- async def set_plate_temperature(
348
- self,
349
- temp: float,
350
- hold_time: Optional[float] = None,
351
- volume: Optional[float] = None,
352
- ramp_rate: Optional[float] = None,
353
- ) -> None:
354
- """Send set plate temperature command"""
355
- temp = min(BLOCK_TARGET_MAX, max(BLOCK_TARGET_MIN, temp))
356
-
357
- c = (
358
- CommandBuilder(terminator=TC_COMMAND_TERMINATOR)
359
- .add_gcode(gcode=GCODE.SET_PLATE_TEMP)
360
- .add_float(
361
- prefix="S", value=temp, precision=utils.TC_GCODE_ROUNDING_PRECISION
362
- )
363
- )
364
- if hold_time is not None:
365
- c = c.add_float(
366
- prefix="H", value=hold_time, precision=utils.TC_GCODE_ROUNDING_PRECISION
367
- )
368
- if volume is not None:
369
- c = c.add_float(
370
- prefix="V", value=volume, precision=utils.TC_GCODE_ROUNDING_PRECISION
371
- )
372
-
373
- if ramp_rate is not None:
374
- c = c.add_float(
375
- prefix="R", value=ramp_rate, precision=utils.TC_GCODE_ROUNDING_PRECISION
376
- )
377
-
378
- await self._connection.send_command(command=c, retries=DEFAULT_COMMAND_RETRIES)
346
+ async def set_ramp_rate(self, ramp_rate: float) -> None:
347
+ """Send a set ramp rate command"""
348
+ # This command is fully unsupported on TC Gen2
349
+ return None
379
350
 
380
351
  async def get_device_info(self) -> Dict[str, str]:
381
352
  """Send get device info command"""
@@ -67,12 +67,10 @@ class SimulatingDriver(AbstractThermocyclerDriver):
67
67
  temp: float,
68
68
  hold_time: Optional[float] = None,
69
69
  volume: Optional[float] = None,
70
- ramp_rate: Optional[float] = None,
71
70
  ) -> None:
72
71
  self._plate_temperature.target = temp
73
72
  self._plate_temperature.current = temp
74
73
  self._plate_temperature.hold = 0
75
- self._ramp_rate = ramp_rate
76
74
 
77
75
  @ensure_yield
78
76
  async def get_plate_temperature(self) -> PlateTemperature:
@@ -44,7 +44,6 @@ from .execution_manager import ExecutionManagerProvider
44
44
  from .pause_manager import PauseManager
45
45
  from .module_control import AttachedModulesControl
46
46
  from .types import (
47
- AsynchronousModuleErrorNotification,
48
47
  Axis,
49
48
  CriticalPoint,
50
49
  DoorState,
@@ -52,7 +51,6 @@ from .types import (
52
51
  ErrorMessageNotification,
53
52
  HardwareEventHandler,
54
53
  HardwareAction,
55
- HardwareEvent,
56
54
  MotionChecks,
57
55
  PauseType,
58
56
  StatusBarState,
@@ -169,18 +167,6 @@ class API(
169
167
  except Exception:
170
168
  mod_log.exception("Errored during door state event callback")
171
169
 
172
- def _send_module_notification(self, event: HardwareEvent) -> None:
173
- if not isinstance(event, AsynchronousModuleErrorNotification):
174
- return
175
- mod_log.info(
176
- f"Forwarding module event {event.event} for {event.module_model} {event.module_serial} at {event.port}"
177
- )
178
- for cb in self._callbacks:
179
- try:
180
- cb(event)
181
- except Exception:
182
- mod_log.exception("Errored during module asynchronous callback")
183
-
184
170
  def _reset_last_mount(self) -> None:
185
171
  self._last_moved_mount = None
186
172
 
@@ -261,9 +247,7 @@ class API(
261
247
  )
262
248
  await api_instance.cache_instruments()
263
249
  module_controls = await AttachedModulesControl.build(
264
- api_instance,
265
- board_revision=backend.board_revision,
266
- event_callback=api_instance._send_module_notification,
250
+ api_instance, board_revision=backend.board_revision
267
251
  )
268
252
  backend.module_controls = module_controls
269
253
  checked_loop.create_task(backend.watch(loop=checked_loop))
@@ -322,9 +306,7 @@ class API(
322
306
  )
323
307
  await api_instance.cache_instruments()
324
308
  module_controls = await AttachedModulesControl.build(
325
- api_instance,
326
- board_revision=backend.board_revision,
327
- event_callback=api_instance._send_module_notification,
309
+ api_instance, board_revision=backend.board_revision
328
310
  )
329
311
  backend.module_controls = module_controls
330
312
  await backend.watch()
@@ -1330,10 +1312,9 @@ class API(
1330
1312
  self.is_simulator
1331
1313
  ), "Cannot build simulating module from non-simulating hardware control API"
1332
1314
 
1333
- return await self._backend.module_controls.register_simulated_module(
1334
- simulated_usb_port=USBPort(
1335
- name="", port_number=1, port_group=PortGroup.MAIN
1336
- ),
1315
+ return await self._backend.module_controls.build_module(
1316
+ port="",
1317
+ usb_port=USBPort(name="", port_number=1, port_group=PortGroup.MAIN),
1337
1318
  type=modules.ModuleType.from_model(model),
1338
1319
  sim_model=model.value,
1339
1320
  )
@@ -360,19 +360,13 @@ class Controller:
360
360
  """Run a probe and return the new position dict"""
361
361
  return await self._smoothie_driver.probe_axis(axis, distance)
362
362
 
363
- async def clean_up(self) -> None: # noqa: C901
363
+ async def clean_up(self) -> None:
364
364
  try:
365
365
  loop = asyncio.get_event_loop()
366
366
  except RuntimeError:
367
367
  return
368
- if hasattr(self, "_module_controls") and self._module_controls is not None:
369
- await self._module_controls.clean_up()
370
368
  if hasattr(self, "_event_watcher"):
371
- if (
372
- loop.is_running()
373
- and self._event_watcher
374
- and not self._event_watcher.closed
375
- ):
369
+ if loop.is_running() and self._event_watcher:
376
370
  self._event_watcher.close()
377
371
  if hasattr(self, "gpio_chardev"):
378
372
  try:
@@ -1398,9 +1398,6 @@ class OT3Controller(FlexBackend):
1398
1398
  except RuntimeError:
1399
1399
  return
1400
1400
 
1401
- if hasattr(self, "_module_controls") and self._module_controls is not None:
1402
- await self._module_controls.clean_up()
1403
-
1404
1401
  if hasattr(self, "_event_watcher"):
1405
1402
  if (
1406
1403
  loop.is_running()
@@ -728,8 +728,7 @@ class OT3Simulator(FlexBackend):
728
728
  @ensure_yield
729
729
  async def clean_up(self) -> None:
730
730
  """Clean up."""
731
- if hasattr(self, "_module_controls") and self._module_controls is not None:
732
- await self._module_controls.clean_up()
731
+ pass
733
732
 
734
733
  @staticmethod
735
734
  def _get_home_position() -> Dict[Axis, float]:
@@ -414,8 +414,7 @@ class Simulator:
414
414
 
415
415
  @ensure_yield
416
416
  async def clean_up(self) -> None:
417
- if hasattr(self, "_module_controls") and self._module_controls is not None:
418
- await self._module_controls.clean_up()
417
+ pass
419
418
 
420
419
  @ensure_yield
421
420
  async def configure_mount(
@@ -91,8 +91,6 @@ class SubsystemManager:
91
91
  self._present_tools = tools.types.ToolSummary(
92
92
  left=None, right=None, gripper=None
93
93
  )
94
- # This is intended to be an internal variable but is modified in unit tests to avoid long timeouts
95
- self._check_device_update_timeout = 10.0
96
94
 
97
95
  @property
98
96
  def ok(self) -> bool:
@@ -185,12 +183,11 @@ class SubsystemManager:
185
183
  return self._tool_task_state is True
186
184
 
187
185
  async def _check_devices_after_update(
188
- self, devices: Set[SubSystem], timeout_sec: Optional[float] = None
186
+ self, devices: Set[SubSystem], timeout_sec: float = 10.0
189
187
  ) -> None:
190
188
  try:
191
189
  await asyncio.wait_for(
192
- self._do_check_devices_after_update(devices),
193
- timeout=timeout_sec or self._check_device_update_timeout,
190
+ self._do_check_devices_after_update(devices), timeout=timeout_sec
194
191
  )
195
192
  except asyncio.TimeoutError:
196
193
  raise RuntimeError("Device failed to come back after firmware update")
@@ -2,11 +2,9 @@ from __future__ import annotations
2
2
  import asyncio
3
3
  import logging
4
4
  import re
5
- from typing import TYPE_CHECKING, List, Optional, Union, Callable
5
+ from typing import TYPE_CHECKING, List, Optional, Union
6
6
  from glob import glob
7
7
 
8
- from opentrons_shared_data.errors.exceptions import EnumeratedError
9
-
10
8
  from opentrons.config import IS_ROBOT, IS_LINUX
11
9
  from opentrons.drivers.rpi_drivers import types, interfaces, usb, usb_simulator
12
10
  from opentrons.hardware_control.emulation.module_server.helpers import (
@@ -21,16 +19,8 @@ from opentrons.hardware_control.modules.module_calibration import (
21
19
  from opentrons.hardware_control.modules.types import ModuleAtPort, ModuleType
22
20
  from opentrons.hardware_control.modules import SimulatingModuleAtPort
23
21
 
24
-
25
22
  from opentrons.types import Point
26
- from .types import (
27
- AionotifyEvent,
28
- BoardRevision,
29
- OT3Mount,
30
- StatusBarUpdateEvent,
31
- HardwareEvent,
32
- AsynchronousModuleErrorNotification,
33
- )
23
+ from .types import AionotifyEvent, BoardRevision, OT3Mount, StatusBarUpdateEvent
34
24
  from . import modules
35
25
 
36
26
  if TYPE_CHECKING:
@@ -61,21 +51,10 @@ class AttachedModulesControl:
61
51
  self,
62
52
  api: Union["API", "OT3API"],
63
53
  usb: interfaces.USBDriverInterface,
64
- event_callback: Callable[[HardwareEvent], None],
65
54
  ) -> None:
66
55
  self._available_modules: List[modules.AbstractModule] = []
67
56
  self._api = api
68
57
  self._usb = usb
69
- self._event_callback = event_callback
70
- if not IS_ROBOT and not api.is_simulator:
71
- # Start task that registers emulated modules.
72
- self._emulation_listen_task: asyncio.Task[
73
- None
74
- ] | None = api.loop.create_task(
75
- listen_module_connection(self.register_modules)
76
- )
77
- else:
78
- self._emulation_listen_task = None
79
58
 
80
59
  def subscribe_to_api_event(self, module: modules.AbstractModule) -> None:
81
60
  self._api.add_status_bar_listener(module.event_listener)
@@ -85,20 +64,22 @@ class AttachedModulesControl:
85
64
  cls,
86
65
  api_instance: Union["API", "OT3API"],
87
66
  board_revision: BoardRevision,
88
- event_callback: Callable[[HardwareEvent], None],
89
67
  ) -> AttachedModulesControl:
90
68
  usb_instance = (
91
69
  usb.USBBus(board_revision)
92
70
  if not api_instance.is_simulator and IS_ROBOT
93
71
  else usb_simulator.USBBusSimulator()
94
72
  )
95
- mc_instance = cls(
96
- api=api_instance, usb=usb_instance, event_callback=event_callback
97
- )
73
+ mc_instance = cls(api=api_instance, usb=usb_instance)
98
74
 
99
75
  if not api_instance.is_simulator:
100
76
  # Do an initial scan of modules.
101
77
  await mc_instance.register_modules(mc_instance.scan())
78
+ if not IS_ROBOT:
79
+ # Start task that registers emulated modules.
80
+ api_instance.loop.create_task(
81
+ listen_module_connection(mc_instance.register_modules)
82
+ )
102
83
 
103
84
  return mc_instance
104
85
 
@@ -106,37 +87,6 @@ class AttachedModulesControl:
106
87
  def available_modules(self) -> List[modules.AbstractModule]:
107
88
  return self._available_modules
108
89
 
109
- async def clean_up(self) -> None:
110
- """Clean up all registered modules and emulator scanning tasks (if any)."""
111
- for module in self._available_modules:
112
- await module.cleanup()
113
- if self._emulation_listen_task is not None:
114
- self._emulation_listen_task.cancel("cleanup")
115
- try:
116
- await self._emulation_listen_task
117
- except asyncio.CancelledError:
118
- pass
119
- except Exception:
120
- log.exception("Exception cleaning up emulation listen task")
121
- finally:
122
- self._emulation_listen_task = None
123
-
124
- async def register_simulated_module(
125
- self,
126
- simulated_usb_port: types.USBPort,
127
- type: modules.ModuleType,
128
- sim_model: str,
129
- ) -> modules.AbstractModule:
130
- """Register a simulated module."""
131
- module = await self.build_module(
132
- "", simulated_usb_port, type, sim_model, sim_serial_number=None
133
- )
134
- self._available_modules.append(module)
135
- self._available_modules = sorted(
136
- self._available_modules, key=modules.AbstractModule.sort_key
137
- )
138
- return module
139
-
140
90
  async def build_module(
141
91
  self,
142
92
  port: str,
@@ -155,7 +105,6 @@ class AttachedModulesControl:
155
105
  sim_model=sim_model,
156
106
  sim_serial_number=sim_serial_number,
157
107
  disconnected_callback=self._disconnected_callback,
158
- error_callback=self._async_error_callback,
159
108
  )
160
109
  last_event = StatusBarUpdateEvent(
161
110
  self._api.get_status_bar_state(), self._api.get_status_bar_enabled()
@@ -172,29 +121,6 @@ class AttachedModulesControl:
172
121
  self._api.loop,
173
122
  )
174
123
 
175
- def _async_error_callback(
176
- self,
177
- exc: Exception,
178
- model: str,
179
- port: str,
180
- serial: str | None,
181
- ) -> None:
182
- """Used by the module to indicate it saw an error from its data poller."""
183
- try:
184
- self._api.loop.call_soon(
185
- self._event_callback,
186
- AsynchronousModuleErrorNotification(
187
- exception=EnumeratedError.ensure(exc),
188
- module_serial=serial,
189
- module_model=modules.module_model_from_string(model),
190
- port=port,
191
- ),
192
- )
193
- except Exception:
194
- log.exception(
195
- f"Async error callback for module {model} {serial} at {port} for exc {exc} failed"
196
- )
197
-
198
124
  async def unregister_modules(
199
125
  self,
200
126
  mods_at_ports: Union[
@@ -27,9 +27,7 @@ from .types import (
27
27
  LiveData,
28
28
  ModuleData,
29
29
  ModuleDataValidator,
30
- module_model_from_string,
31
30
  )
32
-
33
31
  from .errors import (
34
32
  UpdateError,
35
33
  AbsorbanceReaderDisconnectedError,
@@ -68,5 +66,4 @@ __all__ = [
68
66
  "FlexStackerStatus",
69
67
  "PlatformState",
70
68
  "StackerAxisState",
71
- "module_model_from_string",
72
69
  ]
@@ -21,7 +21,6 @@ from opentrons.hardware_control.poller import Poller, Reader
21
21
  from opentrons.hardware_control.modules import mod_abc
22
22
  from opentrons.hardware_control.modules.types import (
23
23
  ModuleDisconnectedCallback,
24
- ModuleErrorCallback,
25
24
  ModuleType,
26
25
  AbsorbanceReaderStatus,
27
26
  LiveData,
@@ -105,13 +104,12 @@ class AbsorbanceReader(mod_abc.AbstractModule):
105
104
  port: str,
106
105
  usb_port: USBPort,
107
106
  hw_control_loop: asyncio.AbstractEventLoop,
108
- execution_manager: ExecutionManager,
109
- disconnected_callback: ModuleDisconnectedCallback,
110
- error_callback: ModuleErrorCallback,
107
+ execution_manager: Optional[ExecutionManager] = None,
111
108
  poll_interval_seconds: Optional[float] = None,
112
109
  simulating: bool = False,
113
110
  sim_model: Optional[str] = None,
114
111
  sim_serial_number: Optional[str] = None,
112
+ disconnected_callback: ModuleDisconnectedCallback = None,
115
113
  ) -> "AbsorbanceReader":
116
114
  """
117
115
  Build and connect to an AbsorbanceReader
@@ -154,7 +152,6 @@ class AbsorbanceReader(mod_abc.AbstractModule):
154
152
  hw_control_loop=hw_control_loop,
155
153
  execution_manager=execution_manager,
156
154
  disconnected_callback=disconnected_callback,
157
- error_callback=error_callback,
158
155
  )
159
156
 
160
157
  try:
@@ -173,9 +170,8 @@ class AbsorbanceReader(mod_abc.AbstractModule):
173
170
  poller: Poller,
174
171
  device_info: Mapping[str, str],
175
172
  hw_control_loop: asyncio.AbstractEventLoop,
176
- execution_manager: ExecutionManager,
177
- disconnected_callback: ModuleDisconnectedCallback,
178
- error_callback: ModuleErrorCallback,
173
+ execution_manager: Optional[ExecutionManager] = None,
174
+ disconnected_callback: ModuleDisconnectedCallback = None,
179
175
  ) -> None:
180
176
  """
181
177
  Constructor
@@ -197,7 +193,6 @@ class AbsorbanceReader(mod_abc.AbstractModule):
197
193
  hw_control_loop=hw_control_loop,
198
194
  execution_manager=execution_manager,
199
195
  disconnected_callback=disconnected_callback,
200
- error_callback=error_callback,
201
196
  )
202
197
  self._device_info = device_info
203
198
  self._reader = reader
@@ -376,5 +371,3 @@ class AbsorbanceReader(mod_abc.AbstractModule):
376
371
  self._error = str(error)
377
372
  if isinstance(error, AbsorbanceReaderDisconnectedError):
378
373
  self.disconnected_callback()
379
- else:
380
- self.error_callback(error)
@@ -44,7 +44,6 @@ from opentrons.hardware_control.modules.types import (
44
44
  FlexStackerStatus,
45
45
  HopperDoorState,
46
46
  LatchState,
47
- ModuleErrorCallback,
48
47
  ModuleDisconnectedCallback,
49
48
  ModuleType,
50
49
  PlatformState,
@@ -216,13 +215,12 @@ class FlexStacker(mod_abc.AbstractModule):
216
215
  port: str,
217
216
  usb_port: USBPort,
218
217
  hw_control_loop: asyncio.AbstractEventLoop,
219
- execution_manager: ExecutionManager,
220
- disconnected_callback: ModuleDisconnectedCallback,
221
- error_callback: ModuleErrorCallback,
222
- poll_interval_seconds: float | None = None,
218
+ execution_manager: Optional[ExecutionManager] = None,
219
+ poll_interval_seconds: Optional[float] = None,
223
220
  simulating: bool = False,
224
221
  sim_model: Optional[str] = None,
225
222
  sim_serial_number: Optional[str] = None,
223
+ disconnected_callback: ModuleDisconnectedCallback = None,
226
224
  ) -> "FlexStacker":
227
225
  """
228
226
  Build a FlexStacker
@@ -261,9 +259,11 @@ class FlexStacker(mod_abc.AbstractModule):
261
259
  hw_control_loop=hw_control_loop,
262
260
  execution_manager=execution_manager,
263
261
  disconnected_callback=disconnected_callback,
264
- error_callback=error_callback,
265
262
  )
266
263
 
264
+ # Set initialized callback
265
+ reader.set_initialized_callback(module._initialized_callback)
266
+
267
267
  # Enable stallguard
268
268
  for axis, config in STALLGUARD_CONFIG.items():
269
269
  await driver.set_stallguard_threshold(
@@ -286,9 +286,8 @@ class FlexStacker(mod_abc.AbstractModule):
286
286
  poller: Poller,
287
287
  device_info: Mapping[str, str],
288
288
  hw_control_loop: asyncio.AbstractEventLoop,
289
- execution_manager: ExecutionManager,
290
- disconnected_callback: ModuleDisconnectedCallback,
291
- error_callback: ModuleErrorCallback,
289
+ execution_manager: Optional[ExecutionManager] = None,
290
+ disconnected_callback: ModuleDisconnectedCallback = None,
292
291
  ):
293
292
  super().__init__(
294
293
  port=port,
@@ -296,7 +295,6 @@ class FlexStacker(mod_abc.AbstractModule):
296
295
  hw_control_loop=hw_control_loop,
297
296
  execution_manager=execution_manager,
298
297
  disconnected_callback=disconnected_callback,
299
- error_callback=error_callback,
300
298
  )
301
299
  self._device_info = device_info
302
300
  self._driver = driver
@@ -306,20 +304,12 @@ class FlexStacker(mod_abc.AbstractModule):
306
304
  self._stacker_status = FlexStackerStatus.IDLE
307
305
  self._last_status_bar_event: Optional[StatusBarUpdateEvent] = None
308
306
  self._should_identify = False
309
- # Set initialized callback
310
- self._unsubscribe_init = reader.set_initialized_callback(
311
- self._initialized_callback
312
- )
313
- self._unsubscribe_error = reader.set_error_callback(self._async_error_callback)
314
307
 
315
308
  async def _initialized_callback(self) -> None:
316
309
  """Called by the reader once the module is initialized."""
317
310
  if self._last_status_bar_event:
318
311
  await self._handle_status_bar_event(self._last_status_bar_event)
319
312
 
320
- def _async_error_callback(self, exception: Exception) -> None:
321
- self.error_callback(exception)
322
-
323
313
  async def cleanup(self) -> None:
324
314
  """Stop the poller task"""
325
315
  await self._poller.stop()
@@ -874,27 +864,10 @@ class FlexStackerReader(Reader):
874
864
  self.installation_detected = False
875
865
  self._refresh_state = False
876
866
  self._initialized_callback: Optional[Callable[[], Awaitable[None]]] = None
877
- self._error_callback: Optional[Callable[[Exception], None]] = None
878
867
 
879
- def set_initialized_callback(
880
- self, callback: Callable[[], Awaitable[None]]
881
- ) -> Callable[[], None]:
868
+ def set_initialized_callback(self, callback: Callable[[], Awaitable[None]]) -> None:
882
869
  """Sets the callback used when done initializing the module."""
883
870
  self._initialized_callback = callback
884
- return self._remove_init_callback
885
-
886
- def _remove_init_callback(self) -> None:
887
- self._initialized_callback = None
888
-
889
- def set_error_callback(
890
- self, error_callback: Callable[[Exception], None]
891
- ) -> Callable[[], None]:
892
- """Register a handler for asynchronous hardware errors."""
893
- self._error_callback = error_callback
894
- return self._remove_error_callback
895
-
896
- def _remove_error_callback(self) -> None:
897
- self._error_callback = None
898
871
 
899
872
  async def read(self) -> None:
900
873
  await self.get_door_closed()
@@ -969,8 +942,6 @@ class FlexStackerReader(Reader):
969
942
  if exception is None:
970
943
  self.error = None
971
944
  else:
972
- if self._error_callback:
973
- self._error_callback(exception)
974
945
  try:
975
946
  self.error = str(exception.args[0])
976
947
  except Exception: