opentrons 8.6.0a1__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 (600) hide show
  1. opentrons/__init__.py +150 -0
  2. opentrons/_version.py +34 -0
  3. opentrons/calibration_storage/__init__.py +54 -0
  4. opentrons/calibration_storage/deck_configuration.py +62 -0
  5. opentrons/calibration_storage/encoder_decoder.py +31 -0
  6. opentrons/calibration_storage/file_operators.py +142 -0
  7. opentrons/calibration_storage/helpers.py +103 -0
  8. opentrons/calibration_storage/ot2/__init__.py +34 -0
  9. opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
  10. opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
  11. opentrons/calibration_storage/ot2/models/__init__.py +0 -0
  12. opentrons/calibration_storage/ot2/models/v1.py +149 -0
  13. opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
  14. opentrons/calibration_storage/ot2/tip_length.py +281 -0
  15. opentrons/calibration_storage/ot3/__init__.py +31 -0
  16. opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
  17. opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
  18. opentrons/calibration_storage/ot3/models/__init__.py +0 -0
  19. opentrons/calibration_storage/ot3/models/v1.py +122 -0
  20. opentrons/calibration_storage/ot3/module_offset.py +138 -0
  21. opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
  22. opentrons/calibration_storage/types.py +45 -0
  23. opentrons/cli/__init__.py +21 -0
  24. opentrons/cli/__main__.py +5 -0
  25. opentrons/cli/analyze.py +501 -0
  26. opentrons/config/__init__.py +631 -0
  27. opentrons/config/advanced_settings.py +871 -0
  28. opentrons/config/defaults_ot2.py +214 -0
  29. opentrons/config/defaults_ot3.py +499 -0
  30. opentrons/config/feature_flags.py +86 -0
  31. opentrons/config/gripper_config.py +55 -0
  32. opentrons/config/reset.py +203 -0
  33. opentrons/config/robot_configs.py +187 -0
  34. opentrons/config/types.py +183 -0
  35. opentrons/drivers/__init__.py +0 -0
  36. opentrons/drivers/absorbance_reader/__init__.py +11 -0
  37. opentrons/drivers/absorbance_reader/abstract.py +72 -0
  38. opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
  39. opentrons/drivers/absorbance_reader/driver.py +81 -0
  40. opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
  41. opentrons/drivers/absorbance_reader/simulator.py +84 -0
  42. opentrons/drivers/asyncio/__init__.py +0 -0
  43. opentrons/drivers/asyncio/communication/__init__.py +22 -0
  44. opentrons/drivers/asyncio/communication/async_serial.py +183 -0
  45. opentrons/drivers/asyncio/communication/errors.py +88 -0
  46. opentrons/drivers/asyncio/communication/serial_connection.py +552 -0
  47. opentrons/drivers/command_builder.py +102 -0
  48. opentrons/drivers/flex_stacker/__init__.py +13 -0
  49. opentrons/drivers/flex_stacker/abstract.py +214 -0
  50. opentrons/drivers/flex_stacker/driver.py +768 -0
  51. opentrons/drivers/flex_stacker/errors.py +68 -0
  52. opentrons/drivers/flex_stacker/simulator.py +309 -0
  53. opentrons/drivers/flex_stacker/types.py +367 -0
  54. opentrons/drivers/flex_stacker/utils.py +19 -0
  55. opentrons/drivers/heater_shaker/__init__.py +5 -0
  56. opentrons/drivers/heater_shaker/abstract.py +76 -0
  57. opentrons/drivers/heater_shaker/driver.py +204 -0
  58. opentrons/drivers/heater_shaker/simulator.py +94 -0
  59. opentrons/drivers/mag_deck/__init__.py +6 -0
  60. opentrons/drivers/mag_deck/abstract.py +44 -0
  61. opentrons/drivers/mag_deck/driver.py +208 -0
  62. opentrons/drivers/mag_deck/simulator.py +63 -0
  63. opentrons/drivers/rpi_drivers/__init__.py +33 -0
  64. opentrons/drivers/rpi_drivers/dev_types.py +94 -0
  65. opentrons/drivers/rpi_drivers/gpio.py +282 -0
  66. opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
  67. opentrons/drivers/rpi_drivers/interfaces.py +15 -0
  68. opentrons/drivers/rpi_drivers/types.py +364 -0
  69. opentrons/drivers/rpi_drivers/usb.py +102 -0
  70. opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
  71. opentrons/drivers/serial_communication.py +151 -0
  72. opentrons/drivers/smoothie_drivers/__init__.py +4 -0
  73. opentrons/drivers/smoothie_drivers/connection.py +51 -0
  74. opentrons/drivers/smoothie_drivers/constants.py +121 -0
  75. opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
  76. opentrons/drivers/smoothie_drivers/errors.py +49 -0
  77. opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
  78. opentrons/drivers/smoothie_drivers/simulator.py +99 -0
  79. opentrons/drivers/smoothie_drivers/types.py +16 -0
  80. opentrons/drivers/temp_deck/__init__.py +10 -0
  81. opentrons/drivers/temp_deck/abstract.py +54 -0
  82. opentrons/drivers/temp_deck/driver.py +197 -0
  83. opentrons/drivers/temp_deck/simulator.py +57 -0
  84. opentrons/drivers/thermocycler/__init__.py +12 -0
  85. opentrons/drivers/thermocycler/abstract.py +99 -0
  86. opentrons/drivers/thermocycler/driver.py +395 -0
  87. opentrons/drivers/thermocycler/simulator.py +126 -0
  88. opentrons/drivers/types.py +107 -0
  89. opentrons/drivers/utils.py +222 -0
  90. opentrons/execute.py +742 -0
  91. opentrons/hardware_control/__init__.py +65 -0
  92. opentrons/hardware_control/__main__.py +77 -0
  93. opentrons/hardware_control/adapters.py +98 -0
  94. opentrons/hardware_control/api.py +1347 -0
  95. opentrons/hardware_control/backends/__init__.py +7 -0
  96. opentrons/hardware_control/backends/controller.py +400 -0
  97. opentrons/hardware_control/backends/errors.py +9 -0
  98. opentrons/hardware_control/backends/estop_state.py +164 -0
  99. opentrons/hardware_control/backends/flex_protocol.py +497 -0
  100. opentrons/hardware_control/backends/ot3controller.py +1930 -0
  101. opentrons/hardware_control/backends/ot3simulator.py +900 -0
  102. opentrons/hardware_control/backends/ot3utils.py +664 -0
  103. opentrons/hardware_control/backends/simulator.py +442 -0
  104. opentrons/hardware_control/backends/status_bar_state.py +240 -0
  105. opentrons/hardware_control/backends/subsystem_manager.py +431 -0
  106. opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
  107. opentrons/hardware_control/backends/types.py +14 -0
  108. opentrons/hardware_control/constants.py +6 -0
  109. opentrons/hardware_control/dev_types.py +125 -0
  110. opentrons/hardware_control/emulation/__init__.py +0 -0
  111. opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
  112. opentrons/hardware_control/emulation/app.py +56 -0
  113. opentrons/hardware_control/emulation/connection_handler.py +38 -0
  114. opentrons/hardware_control/emulation/heater_shaker.py +150 -0
  115. opentrons/hardware_control/emulation/magdeck.py +60 -0
  116. opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
  117. opentrons/hardware_control/emulation/module_server/client.py +78 -0
  118. opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
  119. opentrons/hardware_control/emulation/module_server/models.py +31 -0
  120. opentrons/hardware_control/emulation/module_server/server.py +110 -0
  121. opentrons/hardware_control/emulation/parser.py +74 -0
  122. opentrons/hardware_control/emulation/proxy.py +241 -0
  123. opentrons/hardware_control/emulation/run_emulator.py +68 -0
  124. opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
  125. opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
  126. opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
  127. opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
  128. opentrons/hardware_control/emulation/settings.py +119 -0
  129. opentrons/hardware_control/emulation/simulations.py +133 -0
  130. opentrons/hardware_control/emulation/smoothie.py +192 -0
  131. opentrons/hardware_control/emulation/tempdeck.py +69 -0
  132. opentrons/hardware_control/emulation/thermocycler.py +128 -0
  133. opentrons/hardware_control/emulation/types.py +10 -0
  134. opentrons/hardware_control/emulation/util.py +38 -0
  135. opentrons/hardware_control/errors.py +43 -0
  136. opentrons/hardware_control/execution_manager.py +164 -0
  137. opentrons/hardware_control/instruments/__init__.py +5 -0
  138. opentrons/hardware_control/instruments/instrument_abc.py +39 -0
  139. opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
  140. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
  141. opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
  142. opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
  143. opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
  144. opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
  145. opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
  146. opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
  147. opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
  148. opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
  149. opentrons/hardware_control/module_control.py +332 -0
  150. opentrons/hardware_control/modules/__init__.py +69 -0
  151. opentrons/hardware_control/modules/absorbance_reader.py +373 -0
  152. opentrons/hardware_control/modules/errors.py +7 -0
  153. opentrons/hardware_control/modules/flex_stacker.py +948 -0
  154. opentrons/hardware_control/modules/heater_shaker.py +426 -0
  155. opentrons/hardware_control/modules/lid_temp_status.py +35 -0
  156. opentrons/hardware_control/modules/magdeck.py +233 -0
  157. opentrons/hardware_control/modules/mod_abc.py +245 -0
  158. opentrons/hardware_control/modules/module_calibration.py +93 -0
  159. opentrons/hardware_control/modules/plate_temp_status.py +61 -0
  160. opentrons/hardware_control/modules/tempdeck.py +299 -0
  161. opentrons/hardware_control/modules/thermocycler.py +731 -0
  162. opentrons/hardware_control/modules/types.py +417 -0
  163. opentrons/hardware_control/modules/update.py +255 -0
  164. opentrons/hardware_control/modules/utils.py +73 -0
  165. opentrons/hardware_control/motion_utilities.py +318 -0
  166. opentrons/hardware_control/nozzle_manager.py +422 -0
  167. opentrons/hardware_control/ot3_calibration.py +1171 -0
  168. opentrons/hardware_control/ot3api.py +3227 -0
  169. opentrons/hardware_control/pause_manager.py +31 -0
  170. opentrons/hardware_control/poller.py +112 -0
  171. opentrons/hardware_control/protocols/__init__.py +106 -0
  172. opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
  173. opentrons/hardware_control/protocols/calibratable.py +45 -0
  174. opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
  175. opentrons/hardware_control/protocols/configurable.py +48 -0
  176. opentrons/hardware_control/protocols/event_sourcer.py +18 -0
  177. opentrons/hardware_control/protocols/execution_controllable.py +33 -0
  178. opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
  179. opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
  180. opentrons/hardware_control/protocols/gripper_controller.py +55 -0
  181. opentrons/hardware_control/protocols/hardware_manager.py +51 -0
  182. opentrons/hardware_control/protocols/identifiable.py +16 -0
  183. opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
  184. opentrons/hardware_control/protocols/liquid_handler.py +266 -0
  185. opentrons/hardware_control/protocols/module_provider.py +16 -0
  186. opentrons/hardware_control/protocols/motion_controller.py +243 -0
  187. opentrons/hardware_control/protocols/position_estimator.py +45 -0
  188. opentrons/hardware_control/protocols/simulatable.py +10 -0
  189. opentrons/hardware_control/protocols/stoppable.py +9 -0
  190. opentrons/hardware_control/protocols/types.py +27 -0
  191. opentrons/hardware_control/robot_calibration.py +224 -0
  192. opentrons/hardware_control/scripts/README.md +28 -0
  193. opentrons/hardware_control/scripts/__init__.py +1 -0
  194. opentrons/hardware_control/scripts/gripper_control.py +208 -0
  195. opentrons/hardware_control/scripts/ot3gripper +7 -0
  196. opentrons/hardware_control/scripts/ot3repl +7 -0
  197. opentrons/hardware_control/scripts/repl.py +187 -0
  198. opentrons/hardware_control/scripts/tc_control.py +97 -0
  199. opentrons/hardware_control/simulator_setup.py +260 -0
  200. opentrons/hardware_control/thread_manager.py +431 -0
  201. opentrons/hardware_control/threaded_async_lock.py +97 -0
  202. opentrons/hardware_control/types.py +792 -0
  203. opentrons/hardware_control/util.py +234 -0
  204. opentrons/legacy_broker.py +53 -0
  205. opentrons/legacy_commands/__init__.py +1 -0
  206. opentrons/legacy_commands/commands.py +483 -0
  207. opentrons/legacy_commands/helpers.py +153 -0
  208. opentrons/legacy_commands/module_commands.py +215 -0
  209. opentrons/legacy_commands/protocol_commands.py +54 -0
  210. opentrons/legacy_commands/publisher.py +155 -0
  211. opentrons/legacy_commands/robot_commands.py +51 -0
  212. opentrons/legacy_commands/types.py +1115 -0
  213. opentrons/motion_planning/__init__.py +32 -0
  214. opentrons/motion_planning/adjacent_slots_getters.py +168 -0
  215. opentrons/motion_planning/deck_conflict.py +396 -0
  216. opentrons/motion_planning/errors.py +35 -0
  217. opentrons/motion_planning/types.py +42 -0
  218. opentrons/motion_planning/waypoints.py +218 -0
  219. opentrons/ordered_set.py +138 -0
  220. opentrons/protocol_api/__init__.py +105 -0
  221. opentrons/protocol_api/_liquid.py +157 -0
  222. opentrons/protocol_api/_liquid_properties.py +814 -0
  223. opentrons/protocol_api/_nozzle_layout.py +31 -0
  224. opentrons/protocol_api/_parameter_context.py +300 -0
  225. opentrons/protocol_api/_parameters.py +31 -0
  226. opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
  227. opentrons/protocol_api/_types.py +43 -0
  228. opentrons/protocol_api/config.py +23 -0
  229. opentrons/protocol_api/core/__init__.py +23 -0
  230. opentrons/protocol_api/core/common.py +33 -0
  231. opentrons/protocol_api/core/core_map.py +74 -0
  232. opentrons/protocol_api/core/engine/__init__.py +22 -0
  233. opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
  234. opentrons/protocol_api/core/engine/deck_conflict.py +348 -0
  235. opentrons/protocol_api/core/engine/exceptions.py +19 -0
  236. opentrons/protocol_api/core/engine/instrument.py +2391 -0
  237. opentrons/protocol_api/core/engine/labware.py +238 -0
  238. opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
  239. opentrons/protocol_api/core/engine/module_core.py +1025 -0
  240. opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
  241. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
  242. opentrons/protocol_api/core/engine/point_calculations.py +64 -0
  243. opentrons/protocol_api/core/engine/protocol.py +1153 -0
  244. opentrons/protocol_api/core/engine/robot.py +139 -0
  245. opentrons/protocol_api/core/engine/stringify.py +74 -0
  246. opentrons/protocol_api/core/engine/transfer_components_executor.py +990 -0
  247. opentrons/protocol_api/core/engine/well.py +241 -0
  248. opentrons/protocol_api/core/instrument.py +459 -0
  249. opentrons/protocol_api/core/labware.py +151 -0
  250. opentrons/protocol_api/core/legacy/__init__.py +11 -0
  251. opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
  252. opentrons/protocol_api/core/legacy/deck.py +369 -0
  253. opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
  254. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
  255. opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
  256. opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
  257. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
  258. opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
  259. opentrons/protocol_api/core/legacy/load_info.py +67 -0
  260. opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
  261. opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
  262. opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
  263. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
  264. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
  265. opentrons/protocol_api/core/module.py +484 -0
  266. opentrons/protocol_api/core/protocol.py +311 -0
  267. opentrons/protocol_api/core/robot.py +51 -0
  268. opentrons/protocol_api/core/well.py +116 -0
  269. opentrons/protocol_api/core/well_grid.py +45 -0
  270. opentrons/protocol_api/create_protocol_context.py +177 -0
  271. opentrons/protocol_api/deck.py +223 -0
  272. opentrons/protocol_api/disposal_locations.py +244 -0
  273. opentrons/protocol_api/instrument_context.py +3212 -0
  274. opentrons/protocol_api/labware.py +1579 -0
  275. opentrons/protocol_api/module_contexts.py +1425 -0
  276. opentrons/protocol_api/module_validation_and_errors.py +61 -0
  277. opentrons/protocol_api/protocol_context.py +1688 -0
  278. opentrons/protocol_api/robot_context.py +303 -0
  279. opentrons/protocol_api/validation.py +761 -0
  280. opentrons/protocol_engine/__init__.py +155 -0
  281. opentrons/protocol_engine/actions/__init__.py +65 -0
  282. opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
  283. opentrons/protocol_engine/actions/action_handler.py +13 -0
  284. opentrons/protocol_engine/actions/actions.py +302 -0
  285. opentrons/protocol_engine/actions/get_state_update.py +38 -0
  286. opentrons/protocol_engine/clients/__init__.py +5 -0
  287. opentrons/protocol_engine/clients/sync_client.py +174 -0
  288. opentrons/protocol_engine/clients/transports.py +197 -0
  289. opentrons/protocol_engine/commands/__init__.py +757 -0
  290. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
  291. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
  292. opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
  293. opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
  294. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
  295. opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
  296. opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
  297. opentrons/protocol_engine/commands/aspirate.py +244 -0
  298. opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
  299. opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
  300. opentrons/protocol_engine/commands/blow_out.py +146 -0
  301. opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
  302. opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
  303. opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
  304. opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
  305. opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
  306. opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
  307. opentrons/protocol_engine/commands/command.py +308 -0
  308. opentrons/protocol_engine/commands/command_unions.py +974 -0
  309. opentrons/protocol_engine/commands/comment.py +57 -0
  310. opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
  311. opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
  312. opentrons/protocol_engine/commands/custom.py +67 -0
  313. opentrons/protocol_engine/commands/dispense.py +194 -0
  314. opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
  315. opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
  316. opentrons/protocol_engine/commands/drop_tip.py +232 -0
  317. opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
  318. opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
  319. opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
  320. opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
  321. opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
  322. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
  323. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
  324. opentrons/protocol_engine/commands/flex_stacker/store.py +326 -0
  325. opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
  326. opentrons/protocol_engine/commands/get_next_tip.py +134 -0
  327. opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
  328. opentrons/protocol_engine/commands/hash_command_params.py +38 -0
  329. opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
  330. opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
  331. opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
  332. opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
  333. opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
  334. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
  335. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
  336. opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
  337. opentrons/protocol_engine/commands/home.py +100 -0
  338. opentrons/protocol_engine/commands/identify_module.py +86 -0
  339. opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
  340. opentrons/protocol_engine/commands/liquid_probe.py +464 -0
  341. opentrons/protocol_engine/commands/load_labware.py +210 -0
  342. opentrons/protocol_engine/commands/load_lid.py +154 -0
  343. opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
  344. opentrons/protocol_engine/commands/load_liquid.py +95 -0
  345. opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
  346. opentrons/protocol_engine/commands/load_module.py +223 -0
  347. opentrons/protocol_engine/commands/load_pipette.py +167 -0
  348. opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
  349. opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
  350. opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
  351. opentrons/protocol_engine/commands/move_labware.py +546 -0
  352. opentrons/protocol_engine/commands/move_relative.py +102 -0
  353. opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
  354. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
  355. opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
  356. opentrons/protocol_engine/commands/move_to_well.py +119 -0
  357. opentrons/protocol_engine/commands/movement_common.py +338 -0
  358. opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
  359. opentrons/protocol_engine/commands/pipetting_common.py +443 -0
  360. opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
  361. opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
  362. opentrons/protocol_engine/commands/reload_labware.py +90 -0
  363. opentrons/protocol_engine/commands/retract_axis.py +75 -0
  364. opentrons/protocol_engine/commands/robot/__init__.py +70 -0
  365. opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -0
  366. opentrons/protocol_engine/commands/robot/common.py +18 -0
  367. opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
  368. opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
  369. opentrons/protocol_engine/commands/robot/move_to.py +94 -0
  370. opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +86 -0
  371. opentrons/protocol_engine/commands/save_position.py +109 -0
  372. opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
  373. opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
  374. opentrons/protocol_engine/commands/set_status_bar.py +89 -0
  375. opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
  376. opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
  377. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
  378. opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
  379. opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
  380. opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
  381. opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
  382. opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
  383. opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
  384. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
  385. opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
  386. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
  387. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
  388. opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
  389. opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
  390. opentrons/protocol_engine/commands/touch_tip.py +189 -0
  391. opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
  392. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
  393. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
  394. opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
  395. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
  396. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
  397. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
  398. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
  399. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
  400. opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
  401. opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
  402. opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
  403. opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
  404. opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
  405. opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
  406. opentrons/protocol_engine/create_protocol_engine.py +193 -0
  407. opentrons/protocol_engine/engine_support.py +28 -0
  408. opentrons/protocol_engine/error_recovery_policy.py +81 -0
  409. opentrons/protocol_engine/errors/__init__.py +191 -0
  410. opentrons/protocol_engine/errors/error_occurrence.py +182 -0
  411. opentrons/protocol_engine/errors/exceptions.py +1308 -0
  412. opentrons/protocol_engine/execution/__init__.py +50 -0
  413. opentrons/protocol_engine/execution/command_executor.py +216 -0
  414. opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
  415. opentrons/protocol_engine/execution/door_watcher.py +119 -0
  416. opentrons/protocol_engine/execution/equipment.py +819 -0
  417. opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
  418. opentrons/protocol_engine/execution/gantry_mover.py +686 -0
  419. opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
  420. opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
  421. opentrons/protocol_engine/execution/labware_movement.py +297 -0
  422. opentrons/protocol_engine/execution/movement.py +349 -0
  423. opentrons/protocol_engine/execution/pipetting.py +607 -0
  424. opentrons/protocol_engine/execution/queue_worker.py +86 -0
  425. opentrons/protocol_engine/execution/rail_lights.py +25 -0
  426. opentrons/protocol_engine/execution/run_control.py +33 -0
  427. opentrons/protocol_engine/execution/status_bar.py +34 -0
  428. opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
  429. opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
  430. opentrons/protocol_engine/execution/tip_handler.py +550 -0
  431. opentrons/protocol_engine/labware_offset_standardization.py +194 -0
  432. opentrons/protocol_engine/notes/__init__.py +17 -0
  433. opentrons/protocol_engine/notes/notes.py +59 -0
  434. opentrons/protocol_engine/plugins.py +104 -0
  435. opentrons/protocol_engine/protocol_engine.py +683 -0
  436. opentrons/protocol_engine/resources/__init__.py +26 -0
  437. opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
  438. opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
  439. opentrons/protocol_engine/resources/file_provider.py +161 -0
  440. opentrons/protocol_engine/resources/fixture_validation.py +58 -0
  441. opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
  442. opentrons/protocol_engine/resources/labware_validation.py +73 -0
  443. opentrons/protocol_engine/resources/model_utils.py +32 -0
  444. opentrons/protocol_engine/resources/module_data_provider.py +44 -0
  445. opentrons/protocol_engine/resources/ot3_validation.py +21 -0
  446. opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
  447. opentrons/protocol_engine/slot_standardization.py +128 -0
  448. opentrons/protocol_engine/state/__init__.py +1 -0
  449. opentrons/protocol_engine/state/_abstract_store.py +27 -0
  450. opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
  451. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  452. opentrons/protocol_engine/state/_move_types.py +83 -0
  453. opentrons/protocol_engine/state/_well_math.py +193 -0
  454. opentrons/protocol_engine/state/addressable_areas.py +699 -0
  455. opentrons/protocol_engine/state/command_history.py +309 -0
  456. opentrons/protocol_engine/state/commands.py +1158 -0
  457. opentrons/protocol_engine/state/config.py +39 -0
  458. opentrons/protocol_engine/state/files.py +57 -0
  459. opentrons/protocol_engine/state/fluid_stack.py +138 -0
  460. opentrons/protocol_engine/state/geometry.py +2359 -0
  461. opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
  462. opentrons/protocol_engine/state/labware.py +1459 -0
  463. opentrons/protocol_engine/state/liquid_classes.py +82 -0
  464. opentrons/protocol_engine/state/liquids.py +73 -0
  465. opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
  466. opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
  467. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
  468. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
  469. opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
  470. opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
  471. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
  472. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
  473. opentrons/protocol_engine/state/modules.py +1500 -0
  474. opentrons/protocol_engine/state/motion.py +373 -0
  475. opentrons/protocol_engine/state/pipettes.py +905 -0
  476. opentrons/protocol_engine/state/state.py +421 -0
  477. opentrons/protocol_engine/state/state_summary.py +36 -0
  478. opentrons/protocol_engine/state/tips.py +420 -0
  479. opentrons/protocol_engine/state/update_types.py +904 -0
  480. opentrons/protocol_engine/state/wells.py +290 -0
  481. opentrons/protocol_engine/types/__init__.py +308 -0
  482. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  483. opentrons/protocol_engine/types/command_annotations.py +53 -0
  484. opentrons/protocol_engine/types/deck_configuration.py +81 -0
  485. opentrons/protocol_engine/types/execution.py +96 -0
  486. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  487. opentrons/protocol_engine/types/instrument.py +47 -0
  488. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  489. opentrons/protocol_engine/types/labware.py +131 -0
  490. opentrons/protocol_engine/types/labware_movement.py +22 -0
  491. opentrons/protocol_engine/types/labware_offset_location.py +111 -0
  492. opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
  493. opentrons/protocol_engine/types/liquid.py +40 -0
  494. opentrons/protocol_engine/types/liquid_class.py +59 -0
  495. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  496. opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
  497. opentrons/protocol_engine/types/location.py +194 -0
  498. opentrons/protocol_engine/types/module.py +303 -0
  499. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  500. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  501. opentrons/protocol_engine/types/tip.py +18 -0
  502. opentrons/protocol_engine/types/util.py +21 -0
  503. opentrons/protocol_engine/types/well_position.py +124 -0
  504. opentrons/protocol_reader/__init__.py +37 -0
  505. opentrons/protocol_reader/extract_labware_definitions.py +66 -0
  506. opentrons/protocol_reader/file_format_validator.py +152 -0
  507. opentrons/protocol_reader/file_hasher.py +27 -0
  508. opentrons/protocol_reader/file_identifier.py +284 -0
  509. opentrons/protocol_reader/file_reader_writer.py +90 -0
  510. opentrons/protocol_reader/input_file.py +16 -0
  511. opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
  512. opentrons/protocol_reader/protocol_reader.py +188 -0
  513. opentrons/protocol_reader/protocol_source.py +124 -0
  514. opentrons/protocol_reader/role_analyzer.py +86 -0
  515. opentrons/protocol_runner/__init__.py +26 -0
  516. opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
  517. opentrons/protocol_runner/json_file_reader.py +55 -0
  518. opentrons/protocol_runner/json_translator.py +314 -0
  519. opentrons/protocol_runner/legacy_command_mapper.py +848 -0
  520. opentrons/protocol_runner/legacy_context_plugin.py +116 -0
  521. opentrons/protocol_runner/protocol_runner.py +530 -0
  522. opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
  523. opentrons/protocol_runner/run_orchestrator.py +496 -0
  524. opentrons/protocol_runner/task_queue.py +95 -0
  525. opentrons/protocols/__init__.py +6 -0
  526. opentrons/protocols/advanced_control/__init__.py +0 -0
  527. opentrons/protocols/advanced_control/common.py +38 -0
  528. opentrons/protocols/advanced_control/mix.py +60 -0
  529. opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
  530. opentrons/protocols/advanced_control/transfers/common.py +180 -0
  531. opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
  532. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
  533. opentrons/protocols/api_support/__init__.py +0 -0
  534. opentrons/protocols/api_support/constants.py +8 -0
  535. opentrons/protocols/api_support/deck_type.py +110 -0
  536. opentrons/protocols/api_support/definitions.py +18 -0
  537. opentrons/protocols/api_support/instrument.py +151 -0
  538. opentrons/protocols/api_support/labware_like.py +233 -0
  539. opentrons/protocols/api_support/tip_tracker.py +175 -0
  540. opentrons/protocols/api_support/types.py +32 -0
  541. opentrons/protocols/api_support/util.py +403 -0
  542. opentrons/protocols/bundle.py +89 -0
  543. opentrons/protocols/duration/__init__.py +4 -0
  544. opentrons/protocols/duration/errors.py +5 -0
  545. opentrons/protocols/duration/estimator.py +628 -0
  546. opentrons/protocols/execution/__init__.py +0 -0
  547. opentrons/protocols/execution/dev_types.py +181 -0
  548. opentrons/protocols/execution/errors.py +40 -0
  549. opentrons/protocols/execution/execute.py +84 -0
  550. opentrons/protocols/execution/execute_json_v3.py +275 -0
  551. opentrons/protocols/execution/execute_json_v4.py +359 -0
  552. opentrons/protocols/execution/execute_json_v5.py +28 -0
  553. opentrons/protocols/execution/execute_python.py +169 -0
  554. opentrons/protocols/execution/json_dispatchers.py +87 -0
  555. opentrons/protocols/execution/types.py +7 -0
  556. opentrons/protocols/geometry/__init__.py +0 -0
  557. opentrons/protocols/geometry/planning.py +297 -0
  558. opentrons/protocols/labware.py +312 -0
  559. opentrons/protocols/models/__init__.py +0 -0
  560. opentrons/protocols/models/json_protocol.py +679 -0
  561. opentrons/protocols/parameters/__init__.py +0 -0
  562. opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
  563. opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
  564. opentrons/protocols/parameters/exceptions.py +34 -0
  565. opentrons/protocols/parameters/parameter_definition.py +272 -0
  566. opentrons/protocols/parameters/types.py +17 -0
  567. opentrons/protocols/parameters/validation.py +267 -0
  568. opentrons/protocols/parse.py +671 -0
  569. opentrons/protocols/types.py +159 -0
  570. opentrons/py.typed +0 -0
  571. opentrons/resources/scripts/lpc21isp +0 -0
  572. opentrons/resources/smoothie-edge-8414642.hex +23010 -0
  573. opentrons/simulate.py +1065 -0
  574. opentrons/system/__init__.py +6 -0
  575. opentrons/system/camera.py +51 -0
  576. opentrons/system/log_control.py +59 -0
  577. opentrons/system/nmcli.py +856 -0
  578. opentrons/system/resin.py +24 -0
  579. opentrons/system/smoothie_update.py +15 -0
  580. opentrons/system/wifi.py +204 -0
  581. opentrons/tools/__init__.py +0 -0
  582. opentrons/tools/args_handler.py +22 -0
  583. opentrons/tools/write_pipette_memory.py +157 -0
  584. opentrons/types.py +618 -0
  585. opentrons/util/__init__.py +1 -0
  586. opentrons/util/async_helpers.py +166 -0
  587. opentrons/util/broker.py +84 -0
  588. opentrons/util/change_notifier.py +47 -0
  589. opentrons/util/entrypoint_util.py +278 -0
  590. opentrons/util/get_union_elements.py +26 -0
  591. opentrons/util/helpers.py +6 -0
  592. opentrons/util/linal.py +178 -0
  593. opentrons/util/logging_config.py +265 -0
  594. opentrons/util/logging_queue_handler.py +61 -0
  595. opentrons/util/performance_helpers.py +157 -0
  596. opentrons-8.6.0a1.dist-info/METADATA +37 -0
  597. opentrons-8.6.0a1.dist-info/RECORD +600 -0
  598. opentrons-8.6.0a1.dist-info/WHEEL +4 -0
  599. opentrons-8.6.0a1.dist-info/entry_points.txt +3 -0
  600. opentrons-8.6.0a1.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,900 @@
1
+ """Common flex stacker base models."""
2
+
3
+ from __future__ import annotations
4
+ from dataclasses import dataclass
5
+ from typing import Literal, TYPE_CHECKING, Sequence, Iterator
6
+ from typing_extensions import TypedDict
7
+ from textwrap import dedent
8
+
9
+ from opentrons_shared_data.errors import ErrorCodes
10
+ from opentrons_shared_data.errors.exceptions import CommandPreconditionViolated
11
+ from opentrons_shared_data.labware.labware_definition import LabwareDefinition
12
+
13
+
14
+ from ...errors import ErrorOccurrence
15
+ from ...types import (
16
+ StackerStoredLabwareGroup,
17
+ InStackerHopperLocation,
18
+ LoadedLabware,
19
+ OFF_DECK_LOCATION,
20
+ OnLabwareLocation,
21
+ OnLabwareLocationSequenceComponent,
22
+ LabwareLocationSequence,
23
+ LabwareLocation,
24
+ LabwareOffsetLocationSequence,
25
+ OnLabwareOffsetLocationSequenceComponent,
26
+ ModuleLocation,
27
+ )
28
+ from ...state.update_types import StateUpdate
29
+
30
+
31
+ if TYPE_CHECKING:
32
+ from opentrons.protocol_engine.execution import EquipmentHandler
33
+ from opentrons.protocol_engine.state.state import StateView
34
+ from opentrons.protocol_engine.resources import ModelUtils
35
+ from opentrons.protocol_engine.execution.equipment import LoadedLabwarePoolData
36
+ from opentrons.protocol_engine.state.module_substates import FlexStackerSubState
37
+
38
+ INITIAL_COUNT_DESCRIPTION = dedent(
39
+ """\
40
+ The number of labware that should be initially stored in the stacker. This number will be silently clamped to
41
+ the maximum number of labware that will fit; do not rely on the parameter to know how many labware are in the stacker.
42
+
43
+ This field works with the initialStoredLabware field in a complex way.
44
+
45
+ The following must be true for initialCount to be valid:
46
+ - It is not specified, and initialStoredLabware is not specified, in which case the stacker will start empty
47
+ - It is not specified, and initialStoredLabware is specified, in which case the contents of the stacker are entirely
48
+ determined by initialStoredLabware.
49
+ - It is specified, and initialStoredLabware is specified, in which case the length of initialStoredLabware must be
50
+ exactly initialCount, and the contents of the stacker will be determined by initialStoredLabware.
51
+ """
52
+ )
53
+
54
+ INITIAL_STORED_LABWARE_DESCRIPTION = dedent(
55
+ """\
56
+ A list of IDs that should be initially stored in the stacker.
57
+
58
+ If specified, the first element of the list is the labware on the physical bottom that will be the first labware retrieved.
59
+
60
+ This is a complex field. The following must be true for the field to be valid:
61
+ - If this field is specified, then either initialCount must not be specified, or this field must have exactly initalCount elements
62
+ - Each element must contain an id for each corresponding labware details field (i.e. if lidLabware is specified, each element must have
63
+ a lidLabwareId) and must not contain an id for a corresponding labware details field that is not specified (i.e., if adapterLabware
64
+ is not specified, each element must not have an adapterLabwareId).
65
+
66
+ The behavior of the command depends on the values of both this field and initialCount.
67
+ - If this field is not specified and initialCount is not specified, the command will create the maximum number of labware objects
68
+ the stacker can hold according to the labware pool specifications.
69
+ - If this field is not specified and initialCount is specified to be 0, the command will create 0 labware objects and the stacker will be empty.
70
+ - If this field is not specified and initialCount is specified to be non-0, the command will create initialCount labware objects of
71
+ each specified labware type (primary, lid, and adapter), with appropriate positions, and arbitrary IDs, loaded into the stacker
72
+ - If this field is specified (and therefore initialCount is not specified or is specified to be the length of this field) then the
73
+ command will create labware objects with the IDs specified in this field and appropriate positions, loaded into the stacker.
74
+
75
+ Behavior is also different depending on whether the labware identified by ID in this field exist or not. Either all labware specified
76
+ in this field must exist, or all must not exist.
77
+
78
+ Further,
79
+ - If the labware exist, they must be of the same type as identified in the primaryLabware field.
80
+ - If the labware exist and the adapterLabware field is specified, each labware must be currently loaded on a labware of the same kind as
81
+ specified in the adapterLabware field, and that labware must be loaded off-deck
82
+ - If the labware exist and the adapterLabware field is not specified, each labware must be currently loaded off deck directly
83
+ - If the labware exist and the lidLabware field is specified, each labware must currently have a loaded lid of the same kind as specified
84
+ in the lidLabware field
85
+ - If the labware exist and the lidLabware field is not specified, each labware must not currently have a lid
86
+ - If the labware exist, they must have nothing loaded underneath them or above them other than what is mentioned above
87
+
88
+ If all the above are true, when this command executes the labware will be immediately moved into InStackerHopper. If any of the above
89
+ are not true, analysis will fail.
90
+ """
91
+ )
92
+
93
+
94
+ class FailedLabware(TypedDict, total=False):
95
+ """Holds the labware ID that would have been involved in a failed command."""
96
+
97
+ labwareId: str
98
+
99
+
100
+ class FlexStackerStallOrCollisionError(ErrorOccurrence):
101
+ """Returned when the motor driver detects a stall."""
102
+
103
+ isDefined: bool = True
104
+ errorType: Literal["flexStackerStallOrCollision"] = "flexStackerStallOrCollision"
105
+
106
+ errorCode: str = ErrorCodes.STACKER_STALL_OR_COLLISION_DETECTED.value.code
107
+ detail: str = ErrorCodes.STACKER_STALL_OR_COLLISION_DETECTED.value.detail
108
+
109
+ errorInfo: FailedLabware
110
+
111
+
112
+ class FlexStackerShuttleError(ErrorOccurrence):
113
+ """Returned when the Flex Stacker Shuttle is not in the correct location."""
114
+
115
+ isDefined: bool = True
116
+ errorType: Literal["flexStackerShuttleMissing"] = "flexStackerShuttleMissing"
117
+
118
+ errorCode: str = ErrorCodes.STACKER_SHUTTLE_MISSING.value.code
119
+ detail: str = ErrorCodes.STACKER_SHUTTLE_MISSING.value.detail
120
+
121
+ errorInfo: FailedLabware
122
+
123
+
124
+ class FlexStackerHopperError(ErrorOccurrence):
125
+ """Returned when the Flex Stacker hopper labware presence sensor raises an error."""
126
+
127
+ isDefined: bool = True
128
+ errorType: Literal[
129
+ "flexStackerHopperLabwareFailed"
130
+ ] = "flexStackerHopperLabwareFailed"
131
+
132
+ errorCode: str = ErrorCodes.STACKER_HOPPER_LABWARE_FAILED.value.code
133
+ detail: str = ErrorCodes.STACKER_HOPPER_LABWARE_FAILED.value.detail
134
+
135
+ errorInfo: FailedLabware
136
+
137
+
138
+ class FlexStackerLabwareRetrieveError(ErrorOccurrence):
139
+ """Returned when the labware was not able to get to the shuttle."""
140
+
141
+ isDefined: bool = True
142
+ errorType: Literal[
143
+ "flexStackerLabwareRetrieveFailed"
144
+ ] = "flexStackerLabwareRetrieveFailed"
145
+
146
+ errorCode: str = ErrorCodes.STACKER_SHUTTLE_LABWARE_FAILED.value.code
147
+ detail: str = ErrorCodes.STACKER_SHUTTLE_LABWARE_FAILED.value.detail
148
+ errorInfo: FailedLabware
149
+
150
+
151
+ class FlexStackerShuttleOccupiedError(ErrorOccurrence):
152
+ """Returned when the Flex Stacker Shuttle is occupied when it shouldn't be."""
153
+
154
+ isDefined: bool = True
155
+ errorType: Literal["flexStackerShuttleOccupied"] = "flexStackerShuttleOccupied"
156
+
157
+ errorCode: str = ErrorCodes.STACKER_SHUTTLE_OCCUPIED.value.code
158
+ detail: str = ErrorCodes.STACKER_SHUTTLE_OCCUPIED.value.detail
159
+ errorInfo: FailedLabware
160
+
161
+
162
+ @dataclass
163
+ class _LabwareDefPair:
164
+ definition: LabwareDefinition
165
+ id: str
166
+
167
+
168
+ @dataclass
169
+ class _GroupWithDefs:
170
+ primary: _LabwareDefPair
171
+ adapter: _LabwareDefPair | None
172
+ lid: _LabwareDefPair | None
173
+
174
+
175
+ @dataclass
176
+ class LabwareWithLocationSequence:
177
+ """Holds a labware id and location."""
178
+
179
+ labwareId: str
180
+ locationSequence: LabwareLocationSequence
181
+
182
+
183
+ @dataclass
184
+ class GroupWithLocationSequences:
185
+ """Holds labware id and location for group components."""
186
+
187
+ primary: LabwareWithLocationSequence
188
+ adapter: LabwareWithLocationSequence | None
189
+ lid: LabwareWithLocationSequence | None
190
+
191
+
192
+ def _labware_location_seq_for_primary(
193
+ group: StackerStoredLabwareGroup,
194
+ base: LabwareLocationSequence,
195
+ ) -> LabwareWithLocationSequence:
196
+ if group.adapterLabwareId is not None:
197
+ return LabwareWithLocationSequence(
198
+ labwareId=group.primaryLabwareId,
199
+ locationSequence=(
200
+ [
201
+ OnLabwareLocationSequenceComponent(
202
+ labwareId=group.adapterLabwareId, lidId=None
203
+ )
204
+ ]
205
+ + base
206
+ ),
207
+ )
208
+ else:
209
+ return LabwareWithLocationSequence(
210
+ labwareId=group.primaryLabwareId,
211
+ locationSequence=base,
212
+ )
213
+
214
+
215
+ def _labware_location_seq_for_lid(
216
+ group: StackerStoredLabwareGroup,
217
+ base: LabwareLocationSequence,
218
+ ) -> LabwareWithLocationSequence | None:
219
+ if group.lidLabwareId is None:
220
+ return None
221
+ elif group.adapterLabwareId is None:
222
+ return LabwareWithLocationSequence(
223
+ labwareId=group.lidLabwareId,
224
+ locationSequence=(
225
+ [
226
+ OnLabwareLocationSequenceComponent(
227
+ labwareId=group.primaryLabwareId, lidId=group.lidLabwareId
228
+ )
229
+ ]
230
+ + base
231
+ ),
232
+ )
233
+ else:
234
+ return LabwareWithLocationSequence(
235
+ labwareId=group.lidLabwareId,
236
+ locationSequence=(
237
+ [
238
+ OnLabwareLocationSequenceComponent(
239
+ labwareId=group.primaryLabwareId, lidId=group.lidLabwareId
240
+ ),
241
+ OnLabwareLocationSequenceComponent(
242
+ labwareId=group.adapterLabwareId, lidId=None
243
+ ),
244
+ ]
245
+ + base
246
+ ),
247
+ )
248
+
249
+
250
+ def _labware_location_seq_for_adapter(
251
+ group: StackerStoredLabwareGroup,
252
+ base: LabwareLocationSequence,
253
+ ) -> LabwareWithLocationSequence | None:
254
+ if group.adapterLabwareId is None:
255
+ return None
256
+ return LabwareWithLocationSequence(
257
+ labwareId=group.adapterLabwareId, locationSequence=base
258
+ )
259
+
260
+
261
+ def labware_locations_for_group(
262
+ group: StackerStoredLabwareGroup, base: LabwareLocationSequence
263
+ ) -> GroupWithLocationSequences:
264
+ """Get the labware and location sequences bound together."""
265
+ return GroupWithLocationSequences(
266
+ primary=_labware_location_seq_for_primary(group, base),
267
+ adapter=_labware_location_seq_for_adapter(group, base),
268
+ lid=_labware_location_seq_for_lid(group, base),
269
+ )
270
+
271
+
272
+ def labware_location_base_sequence(
273
+ sample_group: StackerStoredLabwareGroup,
274
+ state_view: StateView,
275
+ default: LabwareLocationSequence,
276
+ ) -> LabwareLocationSequence:
277
+ """Get the base location sequence for a labware group, including loading the current location if it exists."""
278
+ first = (
279
+ sample_group.adapterLabwareId
280
+ if sample_group.adapterLabwareId is not None
281
+ else sample_group.primaryLabwareId
282
+ )
283
+ if state_view.labware.known(first):
284
+ return state_view.geometry.get_location_sequence(first)
285
+ return default
286
+
287
+
288
+ def primary_location_sequences(
289
+ groups: list[GroupWithLocationSequences],
290
+ ) -> list[LabwareLocationSequence]:
291
+ """Collate primary location sequences from lists of labware-plus-location."""
292
+ return [primary_location_sequence(group) for group in groups]
293
+
294
+
295
+ def primary_location_sequence(
296
+ group: GroupWithLocationSequences,
297
+ ) -> LabwareLocationSequence:
298
+ """Get the location sequence for the primary labware."""
299
+ return group.primary.locationSequence
300
+
301
+
302
+ def adapter_location_sequences(
303
+ groups: list[GroupWithLocationSequences],
304
+ ) -> list[LabwareLocationSequence] | None:
305
+ """Collate adapter location sequences from lists of labware-plus-location."""
306
+
307
+ def _yield_adapters(
308
+ groups: list[GroupWithLocationSequences],
309
+ ) -> Iterator[LabwareLocationSequence]:
310
+ for group in groups:
311
+ seq = adapter_location_sequence(group)
312
+ if seq is None:
313
+ continue
314
+ else:
315
+ yield seq
316
+
317
+ adapter_seqs = list(_yield_adapters(groups))
318
+ if len(adapter_seqs) != len(groups):
319
+ return None
320
+ return adapter_seqs
321
+
322
+
323
+ def adapter_location_sequences_with_default(
324
+ groups: list[GroupWithLocationSequences], adapter_def: LabwareDefinition | None
325
+ ) -> list[LabwareLocationSequence] | None:
326
+ """Collate adapter location sequences unless there is no adapter."""
327
+ if adapter_def is None:
328
+ return None
329
+ else:
330
+ return adapter_location_sequences(groups)
331
+
332
+
333
+ def adapter_location_sequence(
334
+ group: GroupWithLocationSequences,
335
+ ) -> LabwareLocationSequence | None:
336
+ """Get the adapter location sequence from a group."""
337
+ if group.adapter is None:
338
+ return None
339
+ return group.adapter.locationSequence
340
+
341
+
342
+ def lid_location_sequences(
343
+ groups: list[GroupWithLocationSequences],
344
+ ) -> list[LabwareLocationSequence] | None:
345
+ """Collate lid location sequences from lists of labware-plus-location."""
346
+
347
+ def _yield_lids(
348
+ groups: list[GroupWithLocationSequences],
349
+ ) -> Iterator[LabwareLocationSequence]:
350
+ for group in groups:
351
+ seq = lid_location_sequence(group)
352
+ if seq is None:
353
+ continue
354
+ else:
355
+ yield seq
356
+
357
+ lid_seqs = list(_yield_lids(groups))
358
+ if len(lid_seqs) != len(groups):
359
+ return None
360
+ return lid_seqs
361
+
362
+
363
+ def lid_location_sequences_with_default(
364
+ groups: list[GroupWithLocationSequences], lid_def: LabwareDefinition | None
365
+ ) -> list[LabwareLocationSequence] | None:
366
+ """Collate lid location sequences unless there is no lid."""
367
+ if lid_def is None:
368
+ return None
369
+ else:
370
+ return lid_location_sequences(groups)
371
+
372
+
373
+ def lid_location_sequence(
374
+ group: GroupWithLocationSequences,
375
+ ) -> LabwareLocationSequence | None:
376
+ """Get the lid location sequence from a group."""
377
+ if group.lid is None:
378
+ return None
379
+ return group.lid.locationSequence
380
+
381
+
382
+ def _check_one_preloaded_labware_known(
383
+ group: StackerStoredLabwareGroup, state_view: StateView
384
+ ) -> bool:
385
+ """Slightly tricky way to check if a labware group represents known labware.
386
+
387
+ Return true if all specified labware are known; false if all specified labware are not known; and
388
+ raise CommandPreconditionViolated if some specified labware are known and some are not.
389
+ """
390
+ if state_view.labware.known(group.primaryLabwareId):
391
+ if group.lidLabwareId is not None and not state_view.labware.known(
392
+ group.lidLabwareId
393
+ ):
394
+ raise CommandPreconditionViolated(
395
+ "Either all labware ids must be known or none must be, but primary and lid do not match"
396
+ )
397
+ if group.adapterLabwareId is not None and not state_view.labware.known(
398
+ group.adapterLabwareId
399
+ ):
400
+ raise CommandPreconditionViolated(
401
+ "Either all labware ids must be known or none must be, but primary and adapter do not match"
402
+ )
403
+
404
+ return True
405
+ else:
406
+ if group.lidLabwareId is not None and state_view.labware.known(
407
+ group.lidLabwareId
408
+ ):
409
+ raise CommandPreconditionViolated(
410
+ "Either all labware ids must be known or none must be, but primary and lid do not match"
411
+ )
412
+ if group.adapterLabwareId is not None and state_view.labware.known(
413
+ group.adapterLabwareId
414
+ ):
415
+ raise CommandPreconditionViolated(
416
+ "Either all labware ids must be known or none must be, but primary and lid do not match"
417
+ )
418
+ return False
419
+
420
+
421
+ def _check_one_preloaded_labware( # noqa: C901
422
+ pool_primary_definition: LabwareDefinition,
423
+ pool_adapter_definition: LabwareDefinition | None,
424
+ pool_lid_definition: LabwareDefinition | None,
425
+ group: StackerStoredLabwareGroup,
426
+ state_view: StateView,
427
+ ) -> None:
428
+ """Do some preflight checks for labware known to be preloaded.
429
+
430
+ Check that labware known to the engine is located appropriately to be loaded to the stacker.
431
+ hopper directly (i.e. during setStoredLabware or fill, NOT with store). While we're at it, bind the def and the id.
432
+ """
433
+ pool_primary_uri = state_view.labware.get_uri_from_definition(
434
+ pool_primary_definition
435
+ )
436
+ stored_primary_uri = state_view.labware.get_definition_uri(group.primaryLabwareId)
437
+
438
+ if pool_primary_uri != stored_primary_uri:
439
+ raise CommandPreconditionViolated(
440
+ f"URI {stored_primary_uri} of primary labware {group.primaryLabwareId} must match pool URI {pool_primary_uri} but does not"
441
+ )
442
+ if pool_adapter_definition:
443
+ if group.adapterLabwareId is None:
444
+ raise CommandPreconditionViolated(
445
+ "All pool components must have an ID, but adapter has no id"
446
+ )
447
+ stored_adapter_uri = state_view.labware.get_definition_uri(
448
+ group.adapterLabwareId
449
+ )
450
+ pool_adapter_uri = state_view.labware.get_uri_from_definition(
451
+ pool_adapter_definition
452
+ )
453
+ if stored_adapter_uri != pool_adapter_uri:
454
+ raise CommandPreconditionViolated(
455
+ f"URI {stored_adapter_uri} of adapter labware {group.adapterLabwareId} must match pool URI {pool_adapter_uri} but does not"
456
+ )
457
+ if state_view.labware.get_location(group.adapterLabwareId) != OFF_DECK_LOCATION:
458
+ raise CommandPreconditionViolated(
459
+ "All existing adapters to be loaded into a stacker must be currently OFF_DECK"
460
+ )
461
+ if state_view.labware.get_location(group.primaryLabwareId) != OnLabwareLocation(
462
+ labwareId=group.adapterLabwareId
463
+ ):
464
+ raise CommandPreconditionViolated(
465
+ "Existing labware groups to be loaded into a stacker must already be associated"
466
+ )
467
+ else:
468
+ if group.adapterLabwareId is not None:
469
+ raise CommandPreconditionViolated(
470
+ "No unspecified pool component may have an ID, but adapter has an id"
471
+ )
472
+ if state_view.labware.get_location(group.primaryLabwareId) != OFF_DECK_LOCATION:
473
+ raise CommandPreconditionViolated(
474
+ "All existing labware without adapters to be loaded into a stacker must be currently OFF_DECK"
475
+ )
476
+ if pool_lid_definition:
477
+ if group.lidLabwareId is None:
478
+ raise CommandPreconditionViolated(
479
+ "All pool components must have an ID but lid has no id"
480
+ )
481
+ stored_lid_uri = state_view.labware.get_definition_uri(group.lidLabwareId)
482
+ pool_lid_uri = state_view.labware.get_uri_from_definition(pool_lid_definition)
483
+ if stored_lid_uri != pool_lid_uri:
484
+ raise CommandPreconditionViolated(
485
+ f"URI {stored_lid_uri} of lid labware {group.lidLabwareId} must match pool URI {pool_lid_uri} but does not"
486
+ )
487
+
488
+ if (
489
+ state_view.labware.get_location(group.lidLabwareId)
490
+ != OnLabwareLocation(labwareId=group.primaryLabwareId)
491
+ or state_view.labware.get_lid_id_by_labware_id(group.primaryLabwareId)
492
+ != group.lidLabwareId
493
+ ):
494
+ raise CommandPreconditionViolated(
495
+ "Existing labware groups to be loaded into a stacker must already be associated"
496
+ )
497
+ else:
498
+ if group.lidLabwareId is not None:
499
+ raise CommandPreconditionViolated(
500
+ "No unspecified pool component may have an id, but lid has an id"
501
+ )
502
+
503
+
504
+ def check_preloaded_labware(
505
+ pool_primary_definition: LabwareDefinition,
506
+ pool_adapter_definition: LabwareDefinition | None,
507
+ pool_lid_definition: LabwareDefinition | None,
508
+ ids: list[StackerStoredLabwareGroup],
509
+ state_view: StateView,
510
+ ) -> None:
511
+ """Check whether a list of known-to-be-preloaded labware match the pool constraints."""
512
+ for group in ids:
513
+ _check_one_preloaded_labware(
514
+ pool_primary_definition,
515
+ pool_adapter_definition,
516
+ pool_lid_definition,
517
+ group,
518
+ state_view,
519
+ )
520
+
521
+
522
+ def check_if_labware_preloaded(
523
+ ids: list[StackerStoredLabwareGroup], state_view: StateView
524
+ ) -> bool:
525
+ """Determine whether the list of ids has already been loaded or needs to be loaded."""
526
+ if len(ids) == 0:
527
+ return False
528
+ first = _check_one_preloaded_labware_known(ids[0], state_view)
529
+ for group in ids[1:]:
530
+ if _check_one_preloaded_labware_known(group, state_view) != first:
531
+ raise CommandPreconditionViolated(
532
+ "All labware must be previously loaded or none must be previously loaded."
533
+ )
534
+ return first
535
+
536
+
537
+ def _add_labware_details_to_dicts(
538
+ definitions_by_id: dict[str, LabwareDefinition],
539
+ display_names_by_id: dict[str, str | None],
540
+ new_locations_by_id: dict[str, LabwareLocation],
541
+ offset_ids_by_id: dict[str, str | None],
542
+ definition: LabwareDefinition,
543
+ labware: LoadedLabware,
544
+ ) -> None:
545
+ definitions_by_id[labware.id] = definition
546
+ display_names_by_id[labware.id] = None
547
+ new_locations_by_id[labware.id] = labware.location
548
+ offset_ids_by_id[labware.id] = labware.offsetId
549
+
550
+
551
+ def _add_pool_labware_details_to_dicts(
552
+ definitions_by_id: dict[str, LabwareDefinition],
553
+ display_names_by_id: dict[str, str | None],
554
+ new_locations_by_id: dict[str, LabwareLocation],
555
+ offset_ids_by_id: dict[str, str | None],
556
+ lid_parent_ids: list[str],
557
+ lid_ids: list[str],
558
+ pool_primary_definition: LabwareDefinition,
559
+ pool_lid_definition: LabwareDefinition | None,
560
+ pool_adapter_definition: LabwareDefinition | None,
561
+ pool_group: LoadedLabwarePoolData,
562
+ ) -> None:
563
+ if pool_group.lid_labware:
564
+ assert pool_lid_definition # safe: only have lids if the pool has lids
565
+ lid_parent_ids.append(pool_group.primary_labware.id)
566
+ lid_ids.append(pool_group.lid_labware.id)
567
+ _add_labware_details_to_dicts(
568
+ definitions_by_id,
569
+ display_names_by_id,
570
+ new_locations_by_id,
571
+ offset_ids_by_id,
572
+ pool_lid_definition,
573
+ pool_group.lid_labware,
574
+ )
575
+ if pool_group.adapter_labware:
576
+ assert pool_adapter_definition
577
+ _add_labware_details_to_dicts(
578
+ definitions_by_id,
579
+ display_names_by_id,
580
+ new_locations_by_id,
581
+ offset_ids_by_id,
582
+ pool_adapter_definition,
583
+ pool_group.adapter_labware,
584
+ )
585
+
586
+ _add_labware_details_to_dicts(
587
+ definitions_by_id,
588
+ display_names_by_id,
589
+ new_locations_by_id,
590
+ offset_ids_by_id,
591
+ pool_primary_definition,
592
+ pool_group.primary_labware,
593
+ )
594
+
595
+
596
+ async def build_n_labware_with_ids(
597
+ pool_primary_definition: LabwareDefinition,
598
+ pool_adapter_definition: LabwareDefinition | None,
599
+ pool_lid_definition: LabwareDefinition | None,
600
+ module_id: str,
601
+ ids: list[StackerStoredLabwareGroup],
602
+ current_contained_labware: list[StackerStoredLabwareGroup],
603
+ equipment: EquipmentHandler,
604
+ ) -> tuple[StateUpdate, list[StackerStoredLabwareGroup]]:
605
+ """Create labware objects to be stored inside the hopper."""
606
+ pool_groups = [
607
+ await equipment.load_labware_pool_from_definitions(
608
+ pool_primary_definition=pool_primary_definition,
609
+ pool_adapter_definition=pool_adapter_definition,
610
+ pool_lid_definition=pool_lid_definition,
611
+ location=InStackerHopperLocation(moduleId=module_id),
612
+ primary_id=id_group.primaryLabwareId,
613
+ adapter_id=id_group.adapterLabwareId,
614
+ lid_id=id_group.lidLabwareId,
615
+ )
616
+ for id_group in ids
617
+ ]
618
+ definitions_by_id: dict[str, LabwareDefinition] = {}
619
+ display_names_by_id: dict[str, str | None] = {}
620
+ new_locations_by_id: dict[str, LabwareLocation] = {}
621
+ offset_ids_by_id: dict[str, str | None] = {}
622
+ lid_parent_ids: list[str] = []
623
+ lid_ids: list[str] = []
624
+ for pool_group in pool_groups:
625
+ _add_pool_labware_details_to_dicts(
626
+ definitions_by_id,
627
+ display_names_by_id,
628
+ new_locations_by_id,
629
+ offset_ids_by_id,
630
+ lid_parent_ids,
631
+ lid_ids,
632
+ pool_primary_definition,
633
+ pool_lid_definition,
634
+ pool_adapter_definition,
635
+ pool_group,
636
+ )
637
+ new_contained_labware = current_contained_labware + ids
638
+ return (
639
+ StateUpdate()
640
+ .update_flex_stacker_contained_labware(module_id, new_contained_labware)
641
+ .set_batch_loaded_labware(
642
+ definitions_by_id=definitions_by_id,
643
+ offset_ids_by_id=offset_ids_by_id,
644
+ display_names_by_id=display_names_by_id,
645
+ new_locations_by_id=new_locations_by_id,
646
+ )
647
+ .set_lids(parent_labware_ids=lid_parent_ids, lid_ids=lid_ids)
648
+ ), new_contained_labware
649
+
650
+
651
+ async def assign_n_labware(
652
+ pool_primary_definition: LabwareDefinition,
653
+ pool_adapter_definition: LabwareDefinition | None,
654
+ pool_lid_definition: LabwareDefinition | None,
655
+ module_id: str,
656
+ ids: list[StackerStoredLabwareGroup],
657
+ current_contained_labware: list[StackerStoredLabwareGroup],
658
+ state_view: StateView,
659
+ ) -> tuple[StateUpdate, list[StackerStoredLabwareGroup]]:
660
+ """Assign a list of labware to be inside the stacker hopper."""
661
+ check_preloaded_labware(
662
+ pool_primary_definition,
663
+ pool_adapter_definition,
664
+ pool_lid_definition,
665
+ ids,
666
+ state_view,
667
+ )
668
+
669
+ def _bottom_labware(group: StackerStoredLabwareGroup) -> str:
670
+ if group.adapterLabwareId:
671
+ return group.adapterLabwareId
672
+ return group.primaryLabwareId
673
+
674
+ def _add_ids(
675
+ group: StackerStoredLabwareGroup, offset_dict: dict[str, str | None]
676
+ ) -> None:
677
+ offset_dict[group.primaryLabwareId] = None
678
+ if group.adapterLabwareId:
679
+ offset_dict[group.adapterLabwareId] = None
680
+ if group.lidLabwareId:
681
+ offset_dict[group.lidLabwareId] = None
682
+
683
+ new_locations_by_id = {
684
+ _bottom_labware(group): InStackerHopperLocation(moduleId=module_id)
685
+ for group in ids
686
+ }
687
+ new_offset_ids_by_id: dict[str, str | None] = {}
688
+ for group in ids:
689
+ _add_ids(group, new_offset_ids_by_id)
690
+
691
+ new_contained_labware = current_contained_labware + ids
692
+ return (
693
+ StateUpdate()
694
+ .update_flex_stacker_contained_labware(module_id, new_contained_labware)
695
+ .set_batch_labware_location(
696
+ new_locations_by_id=new_locations_by_id,
697
+ new_offset_ids_by_id=new_offset_ids_by_id,
698
+ )
699
+ ), new_contained_labware
700
+
701
+
702
+ async def build_or_assign_labware_to_hopper(
703
+ pool_primary_definition: LabwareDefinition,
704
+ pool_adapter_definition: LabwareDefinition | None,
705
+ pool_lid_definition: LabwareDefinition | None,
706
+ module_id: str,
707
+ ids: list[StackerStoredLabwareGroup],
708
+ current_contained_labware: list[StackerStoredLabwareGroup],
709
+ equipment: EquipmentHandler,
710
+ state_view: StateView,
711
+ ) -> tuple[StateUpdate, list[StackerStoredLabwareGroup]]:
712
+ """Use the common params to labware-creating stacker commands to load labware appropriately.
713
+
714
+ If the specified labware IDs exist already, labware is moved; if they don't, labware is created.
715
+ """
716
+ if check_if_labware_preloaded(ids, state_view):
717
+ return await assign_n_labware(
718
+ pool_primary_definition,
719
+ pool_adapter_definition,
720
+ pool_lid_definition,
721
+ module_id,
722
+ ids,
723
+ current_contained_labware,
724
+ state_view,
725
+ )
726
+ else:
727
+ return await build_n_labware_with_ids(
728
+ pool_primary_definition,
729
+ pool_adapter_definition,
730
+ pool_lid_definition,
731
+ module_id,
732
+ ids,
733
+ current_contained_labware,
734
+ equipment,
735
+ )
736
+
737
+
738
+ def _count_from_lw_list_or_initial_count(
739
+ initial_count: int | None,
740
+ initial_lw: list[StackerStoredLabwareGroup] | None,
741
+ max_pool_count: int,
742
+ current_count: int,
743
+ ) -> int:
744
+ """Count the number of labware to be added to the stacker."""
745
+ capacity = max(max_pool_count - current_count, 0)
746
+
747
+ if initial_count is not None:
748
+ if initial_lw and len(initial_lw) != initial_count:
749
+ raise CommandPreconditionViolated(
750
+ "If initialCount and initialStoredLabware are both specified, the number of labware must equal the count"
751
+ )
752
+ to_store_count = initial_count
753
+ elif initial_lw is not None:
754
+ to_store_count = len(initial_lw)
755
+ else:
756
+ # neither initialCount nor initialStoredLabware are specified
757
+ if not capacity:
758
+ raise CommandPreconditionViolated(
759
+ "No labware groups were specified to be stored, but the stacker is already full"
760
+ )
761
+ return capacity
762
+
763
+ if to_store_count > capacity:
764
+ error_text = f" and is already holding {current_count}" if current_count else ""
765
+ raise CommandPreconditionViolated(
766
+ f"{to_store_count} labware groups were requested to be stored, "
767
+ f"but the stacker can hold only {max_pool_count}{error_text}"
768
+ )
769
+ return to_store_count
770
+
771
+
772
+ def _build_one_labware_group(
773
+ has_adapter: bool,
774
+ has_lid: bool,
775
+ group: StackerStoredLabwareGroup | None,
776
+ model_utils: ModelUtils,
777
+ ) -> StackerStoredLabwareGroup:
778
+ if group:
779
+ return group
780
+ return StackerStoredLabwareGroup(
781
+ primaryLabwareId=model_utils.generate_id(),
782
+ adapterLabwareId=(model_utils.generate_id() if has_adapter else None),
783
+ lidLabwareId=(model_utils.generate_id() if has_lid else None),
784
+ )
785
+
786
+
787
+ def build_ids_to_fill(
788
+ has_adapter: bool,
789
+ has_lid: bool,
790
+ initialLabware: list[StackerStoredLabwareGroup] | None,
791
+ initialCount: int | None,
792
+ max_count: int,
793
+ current_count: int,
794
+ model_utils: ModelUtils,
795
+ ) -> list[StackerStoredLabwareGroup]:
796
+ """Handle the common params for filling the stacker to make a list of ids.
797
+
798
+ Only builds labware to add to the current stored (defined by current count).
799
+ """
800
+ count = _count_from_lw_list_or_initial_count(
801
+ initialCount, initialLabware, max_count, current_count
802
+ )
803
+
804
+ def _pad_labware_to_count(
805
+ labware_list: list[StackerStoredLabwareGroup], count: int
806
+ ) -> Sequence[StackerStoredLabwareGroup | None]:
807
+ if len(labware_list) < count:
808
+ return labware_list + ([None] * (count - len(labware_list)))
809
+ else:
810
+ return labware_list[:count]
811
+
812
+ return [
813
+ _build_one_labware_group(has_adapter, has_lid, group, model_utils)
814
+ for group in _pad_labware_to_count(initialLabware or [], count)
815
+ ]
816
+
817
+
818
+ def build_retrieve_labware_move_updates(
819
+ group: StackerStoredLabwareGroup,
820
+ stacker: FlexStackerSubState,
821
+ state_view: StateView,
822
+ ) -> tuple[dict[str, LabwareLocation], dict[str, str | None]]:
823
+ """Build the arguments required for batch_labware_location."""
824
+ locations_for_ids: dict[str, LabwareLocation] = {}
825
+ offset_ids_by_id: dict[str, str | None] = {}
826
+ base_offset_location = state_view.geometry.get_projected_offset_location(
827
+ ModuleLocation(moduleId=stacker.module_id)
828
+ )
829
+ assert stacker.pool_primary_definition, "Undefined labware pool"
830
+ primary_uri = state_view.labware.get_uri_from_definition(
831
+ stacker.pool_primary_definition
832
+ )
833
+
834
+ def _prepend_loc(
835
+ new: LabwareOffsetLocationSequence,
836
+ current: LabwareOffsetLocationSequence | None,
837
+ ) -> LabwareOffsetLocationSequence | None:
838
+ if current is None:
839
+ return None
840
+ return new + current
841
+
842
+ def _find_offset_id(
843
+ uri: str, offset_location: LabwareOffsetLocationSequence | None
844
+ ) -> str | None:
845
+ if offset_location is None:
846
+ return None
847
+ offset = state_view.labware.find_applicable_labware_offset(uri, offset_location)
848
+ if offset is None:
849
+ return None
850
+ return offset.id
851
+
852
+ if group.adapterLabwareId:
853
+ locations_for_ids[group.adapterLabwareId] = ModuleLocation(
854
+ moduleId=stacker.module_id
855
+ )
856
+ locations_for_ids[group.primaryLabwareId] = OnLabwareLocation(
857
+ labwareId=group.adapterLabwareId
858
+ )
859
+ assert (
860
+ stacker.pool_adapter_definition
861
+ ), "Mismatched pool and labware definitions"
862
+ adapter_uri = state_view.labware.get_uri_from_definition(
863
+ stacker.pool_adapter_definition
864
+ )
865
+ offset_ids_by_id[group.adapterLabwareId] = _find_offset_id(
866
+ adapter_uri, base_offset_location
867
+ )
868
+ primary_offset_location = _prepend_loc(
869
+ [OnLabwareOffsetLocationSequenceComponent(labwareUri=adapter_uri)],
870
+ base_offset_location,
871
+ )
872
+ offset_ids_by_id[group.primaryLabwareId] = _find_offset_id(
873
+ primary_uri, primary_offset_location
874
+ )
875
+
876
+ else:
877
+ locations_for_ids[group.primaryLabwareId] = ModuleLocation(
878
+ moduleId=stacker.module_id
879
+ )
880
+ primary_offset_location = base_offset_location
881
+ offset_ids_by_id[group.primaryLabwareId] = _find_offset_id(
882
+ primary_uri, primary_offset_location
883
+ )
884
+
885
+ if group.lidLabwareId:
886
+ assert (
887
+ stacker.pool_lid_definition is not None
888
+ ), "Mismatched pool and stored labware"
889
+ lid_offset_location = _prepend_loc(
890
+ [OnLabwareOffsetLocationSequenceComponent(labwareUri=primary_uri)],
891
+ primary_offset_location,
892
+ )
893
+ locations_for_ids[group.lidLabwareId] = OnLabwareLocation(
894
+ labwareId=group.primaryLabwareId
895
+ )
896
+ offset_ids_by_id[group.lidLabwareId] = _find_offset_id(
897
+ state_view.labware.get_uri_from_definition(stacker.pool_lid_definition),
898
+ lid_offset_location,
899
+ )
900
+ return locations_for_ids, offset_ids_by_id