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,1025 @@
1
+ """Protocol API module implementation logic."""
2
+
3
+ from __future__ import annotations
4
+ from dataclasses import dataclass
5
+ from typing import Optional, List, Dict, Union, Sequence, TYPE_CHECKING, overload
6
+
7
+ from opentrons_shared_data.errors.exceptions import CommandPreconditionViolated
8
+
9
+ from opentrons.hardware_control import SynchronousAdapter, modules as hw_modules
10
+ from opentrons.hardware_control.modules.types import (
11
+ ModuleModel,
12
+ TemperatureStatus,
13
+ MagneticStatus,
14
+ SpeedStatus,
15
+ module_model_from_string,
16
+ )
17
+ from opentrons.drivers.types import (
18
+ HeaterShakerLabwareLatchStatus,
19
+ ThermocyclerLidStatus,
20
+ )
21
+
22
+ from opentrons.protocol_engine import commands as cmd
23
+ from opentrons.protocol_engine.types import (
24
+ ABSMeasureMode,
25
+ StackerFillEmptyStrategy,
26
+ StackerStoredLabwareGroup,
27
+ )
28
+ from opentrons.types import DeckSlotName
29
+ from opentrons.protocol_engine.clients import SyncClient as ProtocolEngineClient
30
+ from opentrons.protocol_engine.errors.exceptions import (
31
+ LabwareNotLoadedOnModuleError,
32
+ NoMagnetEngageHeightError,
33
+ CannotPerformModuleAction,
34
+ FlexStackerLabwarePoolNotYetDefinedError,
35
+ )
36
+
37
+ from opentrons.protocols.api_support.types import APIVersion, ThermocyclerStep
38
+
39
+ from ... import validation
40
+ from ..module import (
41
+ AbstractModuleCore,
42
+ AbstractTemperatureModuleCore,
43
+ AbstractMagneticModuleCore,
44
+ AbstractThermocyclerCore,
45
+ AbstractHeaterShakerCore,
46
+ AbstractMagneticBlockCore,
47
+ AbstractAbsorbanceReaderCore,
48
+ AbstractFlexStackerCore,
49
+ )
50
+ from .exceptions import InvalidMagnetEngageHeightError
51
+
52
+ from .labware import LabwareCore
53
+ from . import load_labware_params
54
+
55
+ if TYPE_CHECKING:
56
+ from .protocol import ProtocolCore
57
+
58
+ # Valid wavelength range for absorbance reader
59
+ ABS_WAVELENGTH_MIN = 350
60
+ ABS_WAVELENGTH_MAX = 1000
61
+
62
+
63
+ class ModuleCore(AbstractModuleCore[LabwareCore]):
64
+ """Module core logic implementation for Python protocols.
65
+ Args:
66
+ module_id: ProtocolEngine ID of the loaded modules.
67
+ """
68
+
69
+ def __init__(
70
+ self,
71
+ module_id: str,
72
+ engine_client: ProtocolEngineClient,
73
+ api_version: APIVersion,
74
+ sync_module_hardware: SynchronousAdapter[hw_modules.AbstractModule],
75
+ protocol_core: ProtocolCore,
76
+ ) -> None:
77
+ self._module_id = module_id
78
+ self._engine_client = engine_client
79
+ self._api_version = api_version
80
+ self._sync_module_hardware = sync_module_hardware
81
+ self._protocol_core = protocol_core
82
+
83
+ @property
84
+ def api_version(self) -> APIVersion:
85
+ """Get the api version protocol module target."""
86
+ return self._api_version
87
+
88
+ @property
89
+ def module_id(self) -> str:
90
+ """The module's unique ProtocolEngine ID."""
91
+ return self._module_id
92
+
93
+ def get_model(self) -> ModuleModel:
94
+ """Get the module's model identifier."""
95
+ return module_model_from_string(
96
+ self._engine_client.state.modules.get_connected_model(self.module_id)
97
+ )
98
+
99
+ def get_serial_number(self) -> str:
100
+ """Get the module's unique hardware serial number."""
101
+ return self._engine_client.state.modules.get_serial_number(self.module_id)
102
+
103
+ def get_deck_slot(self) -> DeckSlotName:
104
+ """Get the module's deck slot."""
105
+ return self._engine_client.state.modules.get_location(self.module_id).slotName
106
+
107
+ def get_deck_slot_id(self) -> str:
108
+ slot_name = self.get_deck_slot()
109
+ return validation.internal_slot_to_public_string(
110
+ slot_name, robot_type=self._engine_client.state.config.robot_type
111
+ )
112
+
113
+ def get_display_name(self) -> str:
114
+ """Get the module's display name."""
115
+ return self._engine_client.state.modules.get_definition(
116
+ self.module_id
117
+ ).displayName
118
+
119
+
120
+ class NonConnectedModuleCore(AbstractModuleCore[LabwareCore]):
121
+ """Not connected module core logic implementation for Python protocols.
122
+
123
+ Args:
124
+ module_id: ProtocolEngine ID of the loaded modules.
125
+ """
126
+
127
+ def __init__(
128
+ self,
129
+ module_id: str,
130
+ engine_client: ProtocolEngineClient,
131
+ api_version: APIVersion,
132
+ protocol_core: ProtocolCore,
133
+ ) -> None:
134
+ self._module_id = module_id
135
+ self._engine_client = engine_client
136
+ self._api_version = api_version
137
+ self._protocol_core = protocol_core
138
+
139
+ @property
140
+ def api_version(self) -> APIVersion:
141
+ """Get the api version protocol module target."""
142
+ return self._api_version
143
+
144
+ @property
145
+ def module_id(self) -> str:
146
+ """The module's unique ProtocolEngine ID."""
147
+ return self._module_id
148
+
149
+ def get_model(self) -> ModuleModel:
150
+ """Get the module's model identifier."""
151
+ return module_model_from_string(
152
+ self._engine_client.state.modules.get_connected_model(self.module_id)
153
+ )
154
+
155
+ def get_deck_slot(self) -> DeckSlotName:
156
+ """Get the module's deck slot."""
157
+ return self._engine_client.state.modules.get_location(self.module_id).slotName
158
+
159
+ def get_display_name(self) -> str:
160
+ """Get the module's display name."""
161
+ return self._engine_client.state.modules.get_definition(
162
+ self.module_id
163
+ ).displayName
164
+
165
+ def get_deck_slot_id(self) -> str:
166
+ slot_name = self.get_deck_slot()
167
+ return validation.internal_slot_to_public_string(
168
+ slot_name, robot_type=self._engine_client.state.config.robot_type
169
+ )
170
+
171
+
172
+ class TemperatureModuleCore(ModuleCore, AbstractTemperatureModuleCore[LabwareCore]):
173
+ """Temperature Module core logic implementation for Python protocols."""
174
+
175
+ _sync_module_hardware: SynchronousAdapter[hw_modules.TempDeck]
176
+
177
+ def set_target_temperature(self, celsius: float) -> None:
178
+ """Set the Temperature Module's target temperature in °C."""
179
+ self._engine_client.execute_command(
180
+ cmd.temperature_module.SetTargetTemperatureParams(
181
+ moduleId=self.module_id, celsius=celsius
182
+ )
183
+ )
184
+
185
+ def wait_for_target_temperature(self, celsius: Optional[float] = None) -> None:
186
+ """Wait until the module's target temperature is reached.
187
+ Specifying a value for ``celsius`` that is different than
188
+ the module's current target temperature may behave unpredictably.
189
+ """
190
+ self._engine_client.execute_command(
191
+ cmd.temperature_module.WaitForTemperatureParams(
192
+ moduleId=self.module_id, celsius=celsius
193
+ )
194
+ )
195
+
196
+ def deactivate(self) -> None:
197
+ """Deactivate the Temperature Module."""
198
+ self._engine_client.execute_command(
199
+ cmd.temperature_module.DeactivateTemperatureParams(moduleId=self.module_id)
200
+ )
201
+
202
+ def get_current_temperature(self) -> float:
203
+ """Get the module's current temperature in °C."""
204
+ return self._sync_module_hardware.temperature # type: ignore[no-any-return]
205
+
206
+ def get_target_temperature(self) -> Optional[float]:
207
+ """Get the module's target temperature in °C, if set."""
208
+ return self._sync_module_hardware.target # type: ignore[no-any-return]
209
+
210
+ def get_status(self) -> TemperatureStatus:
211
+ """Get the module's current temperature status."""
212
+ return self._sync_module_hardware.status # type: ignore[no-any-return]
213
+
214
+
215
+ class MagneticModuleCore(ModuleCore, AbstractMagneticModuleCore[LabwareCore]):
216
+ """Magnetic Module control interface via a ProtocolEngine."""
217
+
218
+ _sync_module_hardware: SynchronousAdapter[hw_modules.MagDeck]
219
+
220
+ def engage(
221
+ self,
222
+ height_from_base: Optional[float] = None,
223
+ height_from_home: Optional[float] = None,
224
+ ) -> None:
225
+ """Raise the module's magnets.
226
+ Only one of `height_from_base` or `height_from_home` may be specified.
227
+ Args:
228
+ height_from_base: Distance from labware base to raise the magnets.
229
+ height_from_home: Distance from motor home position to raise the magnets.
230
+ """
231
+
232
+ # This core will only be used in apiLevels >=2.14, where
233
+ # MagneticModuleContext.engage(height=...) is no longer available.
234
+ # So these asserts should always pass.
235
+ assert (
236
+ height_from_home is None
237
+ ), "Expected engage height to be specified from base."
238
+ assert (
239
+ height_from_base is not None
240
+ ), "Expected engage height to be specified from base."
241
+
242
+ self._engine_client.execute_command(
243
+ cmd.magnetic_module.EngageParams(
244
+ moduleId=self._module_id, height=height_from_base
245
+ )
246
+ )
247
+
248
+ def engage_to_labware(
249
+ self, offset: float = 0, preserve_half_mm: bool = False
250
+ ) -> None:
251
+ """Raise the module's magnets up to its loaded labware.
252
+ Args:
253
+ offset: Offset from the labware's default engage height.
254
+ preserve_half_mm: For labware whose definitions
255
+ erroneously use half-mm for their defined default engage height,
256
+ use the value directly instead of converting it to real millimeters.
257
+ """
258
+ try:
259
+ default_height = (
260
+ self._engine_client.state.labware.get_default_magnet_height(
261
+ module_id=self.module_id, offset=offset
262
+ )
263
+ )
264
+ except LabwareNotLoadedOnModuleError:
265
+ raise InvalidMagnetEngageHeightError(
266
+ "There is no labware loaded on this Magnetic Module,"
267
+ " so you must specify an engage height"
268
+ " with the `height_from_base` parameter."
269
+ )
270
+ except NoMagnetEngageHeightError:
271
+ raise InvalidMagnetEngageHeightError(
272
+ "The labware loaded on this Magnetic Module"
273
+ " does not have a default engage height,"
274
+ " so you must specify an engage height"
275
+ " with the `height_from_base` parameter."
276
+ )
277
+
278
+ self._engine_client.execute_command(
279
+ cmd.magnetic_module.EngageParams(
280
+ moduleId=self.module_id, height=default_height
281
+ )
282
+ )
283
+
284
+ def disengage(self) -> None:
285
+ """Lower the magnets back into the module."""
286
+ self._engine_client.execute_command(
287
+ cmd.magnetic_module.DisengageParams(moduleId=self.module_id)
288
+ )
289
+
290
+ def get_status(self) -> MagneticStatus:
291
+ """Get the module's current magnet status."""
292
+ return self._sync_module_hardware.status # type: ignore[no-any-return]
293
+
294
+
295
+ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
296
+ """Core control interface for an attached Thermocycler Module."""
297
+
298
+ _sync_module_hardware: SynchronousAdapter[hw_modules.Thermocycler]
299
+ _repetitions: Optional[int] = None
300
+ _step_count: Optional[int] = None
301
+
302
+ def open_lid(self) -> ThermocyclerLidStatus:
303
+ """Open the Thermocycler's lid."""
304
+ self._engine_client.execute_command(
305
+ cmd.thermocycler.OpenLidParams(moduleId=self.module_id)
306
+ )
307
+ return ThermocyclerLidStatus.OPEN
308
+
309
+ def close_lid(self) -> ThermocyclerLidStatus:
310
+ """Close the Thermocycler's lid."""
311
+ self._engine_client.execute_command(
312
+ cmd.thermocycler.CloseLidParams(moduleId=self.module_id)
313
+ )
314
+ return ThermocyclerLidStatus.CLOSED
315
+
316
+ def set_target_block_temperature(
317
+ self,
318
+ celsius: float,
319
+ hold_time_seconds: Optional[float] = None,
320
+ block_max_volume: Optional[float] = None,
321
+ ) -> None:
322
+ """Set the target temperature for the well block, in °C."""
323
+ self._engine_client.execute_command(
324
+ cmd.thermocycler.SetTargetBlockTemperatureParams(
325
+ moduleId=self.module_id,
326
+ celsius=celsius,
327
+ blockMaxVolumeUl=block_max_volume,
328
+ holdTimeSeconds=hold_time_seconds,
329
+ )
330
+ )
331
+
332
+ def wait_for_block_temperature(self) -> None:
333
+ """Wait for target block temperature to be reached."""
334
+ self._engine_client.execute_command(
335
+ cmd.thermocycler.WaitForBlockTemperatureParams(moduleId=self.module_id)
336
+ )
337
+
338
+ def set_target_lid_temperature(self, celsius: float) -> None:
339
+ """Set the target temperature for the heated lid, in °C."""
340
+ self._engine_client.execute_command(
341
+ cmd.thermocycler.SetTargetLidTemperatureParams(
342
+ moduleId=self.module_id, celsius=celsius
343
+ )
344
+ )
345
+
346
+ def wait_for_lid_temperature(self) -> None:
347
+ """Wait for target lid temperature to be reached."""
348
+ self._engine_client.execute_command(
349
+ cmd.thermocycler.WaitForLidTemperatureParams(moduleId=self.module_id)
350
+ )
351
+
352
+ def _execute_profile_pre_221(
353
+ self,
354
+ steps: List[ThermocyclerStep],
355
+ repetitions: int,
356
+ block_max_volume: Optional[float],
357
+ ) -> None:
358
+ """Execute a thermocycler profile using thermocycler/runProfile and flattened steps."""
359
+ engine_steps = [
360
+ cmd.thermocycler.RunProfileStepParams(
361
+ celsius=step["temperature"],
362
+ holdSeconds=step["hold_time_seconds"],
363
+ )
364
+ for step in steps
365
+ ]
366
+ repeated_engine_steps = engine_steps * repetitions
367
+ self._engine_client.execute_command(
368
+ cmd.thermocycler.RunProfileParams(
369
+ moduleId=self.module_id,
370
+ profile=repeated_engine_steps,
371
+ blockMaxVolumeUl=block_max_volume,
372
+ )
373
+ )
374
+
375
+ def _execute_profile_post_221(
376
+ self,
377
+ steps: List[ThermocyclerStep],
378
+ repetitions: int,
379
+ block_max_volume: Optional[float],
380
+ ) -> None:
381
+ """Execute a thermocycler profile using thermocycler/runExtendedProfile."""
382
+ engine_steps: List[
383
+ Union[cmd.thermocycler.ProfileCycle, cmd.thermocycler.ProfileStep]
384
+ ] = [
385
+ cmd.thermocycler.ProfileCycle(
386
+ repetitions=repetitions,
387
+ steps=[
388
+ cmd.thermocycler.ProfileStep(
389
+ celsius=step["temperature"],
390
+ holdSeconds=step["hold_time_seconds"],
391
+ )
392
+ for step in steps
393
+ ],
394
+ )
395
+ ]
396
+ self._engine_client.execute_command(
397
+ cmd.thermocycler.RunExtendedProfileParams(
398
+ moduleId=self.module_id,
399
+ profileElements=engine_steps,
400
+ blockMaxVolumeUl=block_max_volume,
401
+ )
402
+ )
403
+
404
+ def execute_profile(
405
+ self,
406
+ steps: List[ThermocyclerStep],
407
+ repetitions: int,
408
+ block_max_volume: Optional[float] = None,
409
+ ) -> None:
410
+ """Execute a Thermocycler Profile."""
411
+ self._repetitions = repetitions
412
+ self._step_count = len(steps)
413
+ if self.api_version >= APIVersion(2, 21):
414
+ return self._execute_profile_post_221(steps, repetitions, block_max_volume)
415
+ else:
416
+ return self._execute_profile_pre_221(steps, repetitions, block_max_volume)
417
+
418
+ def deactivate_lid(self) -> None:
419
+ """Turn off the heated lid."""
420
+ self._engine_client.execute_command(
421
+ cmd.thermocycler.DeactivateLidParams(moduleId=self.module_id)
422
+ )
423
+
424
+ def deactivate_block(self) -> None:
425
+ """Turn off the well block temperature controller"""
426
+ self._clear_cycle_counters()
427
+ self._engine_client.execute_command(
428
+ cmd.thermocycler.DeactivateBlockParams(moduleId=self.module_id)
429
+ )
430
+
431
+ def deactivate(self) -> None:
432
+ """Turn off the well block temperature controller, and heated lid"""
433
+ self.deactivate_block()
434
+ self.deactivate_lid()
435
+
436
+ def get_lid_position(self) -> Optional[ThermocyclerLidStatus]:
437
+ """Get the thermocycler's lid position."""
438
+ return self._sync_module_hardware.lid_status # type: ignore[no-any-return]
439
+
440
+ def get_block_temperature_status(self) -> TemperatureStatus:
441
+ """Get the thermocycler's block temperature status."""
442
+ return self._sync_module_hardware.status # type: ignore[no-any-return]
443
+
444
+ def get_lid_temperature_status(self) -> Optional[TemperatureStatus]:
445
+ """Get the thermocycler's lid temperature status."""
446
+ return self._sync_module_hardware.lid_temp_status # type: ignore[no-any-return]
447
+
448
+ def get_block_temperature(self) -> Optional[float]:
449
+ """Get the thermocycler's current block temperature in °C."""
450
+ return self._sync_module_hardware.temperature # type: ignore[no-any-return]
451
+
452
+ def get_block_target_temperature(self) -> Optional[float]:
453
+ """Get the thermocycler's target block temperature in °C."""
454
+ return self._sync_module_hardware.target # type: ignore[no-any-return]
455
+
456
+ def get_lid_temperature(self) -> Optional[float]:
457
+ """Get the thermocycler's current lid temperature in °C."""
458
+ return self._sync_module_hardware.lid_temp # type: ignore[no-any-return]
459
+
460
+ def get_lid_target_temperature(self) -> Optional[float]:
461
+ """Get the thermocycler's target lid temperature in °C."""
462
+ return self._sync_module_hardware.lid_target # type: ignore[no-any-return]
463
+
464
+ def get_ramp_rate(self) -> Optional[float]:
465
+ """Get the thermocycler's current ramp rate in °C/sec."""
466
+ return self._sync_module_hardware.ramp_rate # type: ignore[no-any-return]
467
+
468
+ def get_hold_time(self) -> Optional[float]:
469
+ """Get the remaining hold time in seconds."""
470
+ return self._sync_module_hardware.hold_time # type: ignore[no-any-return]
471
+
472
+ def get_total_cycle_count(self) -> Optional[int]:
473
+ """Get number of repetitions for current set cycle."""
474
+ return self._repetitions
475
+
476
+ def get_current_cycle_index(self) -> Optional[int]:
477
+ """Get index of the current set cycle repetition."""
478
+ if self._repetitions is None:
479
+ return None
480
+ step_index = self._sync_module_hardware.current_step_index
481
+ # TODO(jbl 2022-10-31) this is intended to work even if execute profile is non-blocking, but it is blocking so
482
+ # this is not guaranteed to be accurate
483
+ return (step_index - 1) // self._step_count + 1 # type: ignore[no-any-return]
484
+
485
+ def get_total_step_count(self) -> Optional[int]:
486
+ """Get number of steps within the current cycle."""
487
+ return self._step_count
488
+
489
+ def get_current_step_index(self) -> Optional[int]:
490
+ """Get the index of the current step within the current cycle."""
491
+ if self._step_count is None:
492
+ return None
493
+ step_index = self._sync_module_hardware.current_step_index
494
+ # TODO(jbl 2022-10-31) this is intended to work even if execute profile is non-blocking, but it is blocking so
495
+ # this is not guaranteed to be accurate
496
+ return (step_index - 1) % self._step_count + 1 # type: ignore[no-any-return]
497
+
498
+ def _clear_cycle_counters(self) -> None:
499
+ """Clear core-tracked cycle counters."""
500
+ self._repetitions = None
501
+ self._step_count = None
502
+
503
+
504
+ class HeaterShakerModuleCore(ModuleCore, AbstractHeaterShakerCore[LabwareCore]):
505
+ """Core control interface for an attached Heater-Shaker Module."""
506
+
507
+ _sync_module_hardware: SynchronousAdapter[hw_modules.HeaterShaker]
508
+
509
+ def set_target_temperature(self, celsius: float) -> None:
510
+ """Set the labware plate's target temperature in °C."""
511
+ self._engine_client.execute_command(
512
+ cmd.heater_shaker.SetTargetTemperatureParams(
513
+ moduleId=self.module_id, celsius=celsius
514
+ )
515
+ )
516
+
517
+ def wait_for_target_temperature(self) -> None:
518
+ """Wait for the labware plate's target temperature to be reached."""
519
+ self._engine_client.execute_command(
520
+ cmd.heater_shaker.WaitForTemperatureParams(moduleId=self.module_id)
521
+ )
522
+
523
+ def set_and_wait_for_shake_speed(self, rpm: int) -> None:
524
+ """Set the shaker's target shake speed and wait for it to spin up."""
525
+ self._engine_client.execute_command(
526
+ cmd.heater_shaker.SetAndWaitForShakeSpeedParams(
527
+ moduleId=self.module_id, rpm=rpm
528
+ )
529
+ )
530
+
531
+ def open_labware_latch(self) -> None:
532
+ """Open the labware latch."""
533
+ self._engine_client.execute_command(
534
+ cmd.heater_shaker.OpenLabwareLatchParams(moduleId=self.module_id)
535
+ )
536
+
537
+ def close_labware_latch(self) -> None:
538
+ """Close the labware latch."""
539
+ self._engine_client.execute_command(
540
+ cmd.heater_shaker.CloseLabwareLatchParams(moduleId=self.module_id)
541
+ )
542
+
543
+ def deactivate_shaker(self) -> None:
544
+ """Stop shaking."""
545
+ self._engine_client.execute_command(
546
+ cmd.heater_shaker.DeactivateShakerParams(moduleId=self.module_id)
547
+ )
548
+
549
+ def deactivate_heater(self) -> None:
550
+ """Stop heating."""
551
+ self._engine_client.execute_command(
552
+ cmd.heater_shaker.DeactivateHeaterParams(moduleId=self.module_id)
553
+ )
554
+
555
+ def get_current_temperature(self) -> float:
556
+ """Get the labware plate's current temperature in °C."""
557
+ return self._sync_module_hardware.temperature # type: ignore[no-any-return]
558
+
559
+ def get_target_temperature(self) -> Optional[float]:
560
+ """Get the labware plate's target temperature in °C, if set."""
561
+ return self._sync_module_hardware.target_temperature # type: ignore[no-any-return]
562
+
563
+ def get_current_speed(self) -> int:
564
+ """Get the shaker's current speed in RPM."""
565
+ return self._sync_module_hardware.speed # type: ignore[no-any-return]
566
+
567
+ def get_target_speed(self) -> Optional[int]:
568
+ """Get the shaker's target speed in RPM, if set."""
569
+ return self._sync_module_hardware.target_speed # type: ignore[no-any-return]
570
+
571
+ def get_temperature_status(self) -> TemperatureStatus:
572
+ """Get the module's heater status."""
573
+ return self._sync_module_hardware.temperature_status # type: ignore[no-any-return]
574
+
575
+ def get_speed_status(self) -> SpeedStatus:
576
+ """Get the module's heater status."""
577
+ return self._sync_module_hardware.speed_status # type: ignore[no-any-return]
578
+
579
+ def get_labware_latch_status(self) -> HeaterShakerLabwareLatchStatus:
580
+ """Get the module's labware latch status."""
581
+ return self._sync_module_hardware.labware_latch_status # type: ignore[no-any-return]
582
+
583
+
584
+ class MagneticBlockCore(NonConnectedModuleCore, AbstractMagneticBlockCore[LabwareCore]):
585
+ """Magnetic Block control interface via a ProtocolEngine."""
586
+
587
+
588
+ class AbsorbanceReaderCore(ModuleCore, AbstractAbsorbanceReaderCore[LabwareCore]):
589
+ """Absorbance Reader core logic implementation for Python protocols."""
590
+
591
+ _sync_module_hardware: SynchronousAdapter[hw_modules.AbsorbanceReader]
592
+ _initialized_value: Optional[List[int]] = None
593
+ _ready_to_initialize: bool = False
594
+
595
+ def initialize(
596
+ self,
597
+ mode: ABSMeasureMode,
598
+ wavelengths: List[int],
599
+ reference_wavelength: Optional[int] = None,
600
+ ) -> None:
601
+ """Initialize the Absorbance Reader by taking zero reading."""
602
+ if not self._ready_to_initialize:
603
+ raise CannotPerformModuleAction(
604
+ "Cannot perform Initialize action on Absorbance Reader without calling `.close_lid()` first."
605
+ )
606
+
607
+ wavelength_len = len(wavelengths)
608
+ if mode == "single" and wavelength_len != 1:
609
+ raise ValueError(
610
+ f"Single mode can only be initialized with 1 wavelength"
611
+ f" {wavelength_len} wavelengths provided instead."
612
+ )
613
+
614
+ if mode == "multi" and (wavelength_len < 1 or wavelength_len > 6):
615
+ raise ValueError(
616
+ f"Multi mode can only be initialized with 1 - 6 wavelengths."
617
+ f" {wavelength_len} wavelengths provided instead."
618
+ )
619
+
620
+ if reference_wavelength is not None and (
621
+ reference_wavelength < ABS_WAVELENGTH_MIN
622
+ or reference_wavelength > ABS_WAVELENGTH_MAX
623
+ ):
624
+ raise ValueError(
625
+ f"Unsupported reference wavelength: ({reference_wavelength}) needs"
626
+ f" to between {ABS_WAVELENGTH_MIN} and {ABS_WAVELENGTH_MAX} nm."
627
+ )
628
+
629
+ for wavelength in wavelengths:
630
+ if (
631
+ not isinstance(wavelength, int)
632
+ or wavelength < ABS_WAVELENGTH_MIN
633
+ or wavelength > ABS_WAVELENGTH_MAX
634
+ ):
635
+ raise ValueError(
636
+ f"Unsupported sample wavelength: ({wavelength}) needs"
637
+ f" to between {ABS_WAVELENGTH_MIN} and {ABS_WAVELENGTH_MAX} nm."
638
+ )
639
+
640
+ self._engine_client.execute_command(
641
+ cmd.absorbance_reader.InitializeParams(
642
+ moduleId=self.module_id,
643
+ measureMode=mode,
644
+ sampleWavelengths=wavelengths,
645
+ referenceWavelength=reference_wavelength,
646
+ ),
647
+ )
648
+ self._initialized_value = wavelengths
649
+
650
+ def read(self, filename: Optional[str] = None) -> Dict[int, Dict[str, float]]:
651
+ """Initiate a read on the Absorbance Reader, and return the results. During Analysis, this will return a measurement of zero for all wells."""
652
+ wavelengths = self._engine_client.state.modules.get_absorbance_reader_substate(
653
+ self.module_id
654
+ ).configured_wavelengths
655
+ if wavelengths is None:
656
+ raise CannotPerformModuleAction(
657
+ "Cannot perform Read action on Absorbance Reader without calling `.initialize(...)` first."
658
+ )
659
+ if self._initialized_value:
660
+ self._engine_client.execute_command(
661
+ cmd.absorbance_reader.ReadAbsorbanceParams(
662
+ moduleId=self.module_id, fileName=filename
663
+ )
664
+ )
665
+ if not self._engine_client.state.config.use_virtual_modules:
666
+ read_result = (
667
+ self._engine_client.state.modules.get_absorbance_reader_substate(
668
+ self.module_id
669
+ ).data
670
+ )
671
+ if read_result is not None:
672
+ return read_result
673
+ raise CannotPerformModuleAction(
674
+ "Absorbance Reader failed to return expected read result."
675
+ )
676
+
677
+ # When using virtual modules, return all zeroes
678
+ virtual_asbsorbance_result: Dict[int, Dict[str, float]] = {}
679
+ for wavelength in wavelengths:
680
+ converted_values = (
681
+ self._engine_client.state.modules.convert_absorbance_reader_data_points(
682
+ data=[0] * 96
683
+ )
684
+ )
685
+ virtual_asbsorbance_result[wavelength] = converted_values
686
+ return virtual_asbsorbance_result
687
+
688
+ def close_lid(
689
+ self,
690
+ ) -> None:
691
+ """Close the Absorbance Reader's lid."""
692
+ self._engine_client.execute_command(
693
+ cmd.absorbance_reader.CloseLidParams(
694
+ moduleId=self.module_id,
695
+ )
696
+ )
697
+ self._ready_to_initialize = True
698
+
699
+ def open_lid(self) -> None:
700
+ """Close the Absorbance Reader's lid."""
701
+ self._engine_client.execute_command(
702
+ cmd.absorbance_reader.OpenLidParams(
703
+ moduleId=self.module_id,
704
+ )
705
+ )
706
+
707
+ def is_lid_on(self) -> bool:
708
+ """Returns True if the Absorbance Reader's lid is currently on the Reader slot."""
709
+ abs_state = self._engine_client.state.modules.get_absorbance_reader_substate(
710
+ self.module_id
711
+ )
712
+ return abs_state.is_lid_on
713
+
714
+
715
+ @dataclass
716
+ class _CoreTrio:
717
+ primary: LabwareCore
718
+ adapter: LabwareCore | None
719
+ lid: LabwareCore | None
720
+
721
+
722
+ class FlexStackerCore(ModuleCore, AbstractFlexStackerCore[LabwareCore]):
723
+ """Flex Stacker core logic implementation for Python protocols."""
724
+
725
+ _sync_module_hardware: SynchronousAdapter[hw_modules.FlexStacker]
726
+
727
+ def retrieve(self) -> LabwareCore:
728
+ """Retrieve a labware from the Flex Stacker's hopper.
729
+
730
+ Returns the primary labware.
731
+ """
732
+ self._engine_client.execute_command(
733
+ cmd.flex_stacker.RetrieveParams(
734
+ moduleId=self.module_id,
735
+ )
736
+ )
737
+ base = self._protocol_core.get_labware_on_module(self)
738
+ assert base, "Retrieve failed to provide a labware"
739
+ if base.is_adapter():
740
+ primary = self._protocol_core.get_labware_on_labware(base)
741
+ if primary:
742
+ return primary
743
+ return base
744
+
745
+ def store(self) -> None:
746
+ """Store a labware into Flex Stacker's hopper."""
747
+ self._engine_client.execute_command(
748
+ cmd.flex_stacker.StoreParams(
749
+ moduleId=self.module_id,
750
+ )
751
+ )
752
+
753
+ def fill(self, count: int | None, message: str | None) -> None:
754
+ """Pause the protocol to add more labware to the Flex Stacker's hopper."""
755
+ self._engine_client.execute_command(
756
+ cmd.flex_stacker.FillParams(
757
+ moduleId=self.module_id,
758
+ strategy=StackerFillEmptyStrategy.MANUAL_WITH_PAUSE,
759
+ message=message,
760
+ count=count,
761
+ )
762
+ )
763
+
764
+ def _core_groups_from_primary_core(self, labware: LabwareCore) -> _CoreTrio:
765
+ possible_adapter = self._protocol_core.get_labware_location(labware)
766
+ return _CoreTrio(
767
+ primary=labware,
768
+ adapter=(
769
+ possible_adapter if isinstance(possible_adapter, LabwareCore) else None
770
+ ),
771
+ lid=self._protocol_core.get_labware_on_labware(labware),
772
+ )
773
+
774
+ def _group_from_core_group(
775
+ self, core_group: _CoreTrio
776
+ ) -> StackerStoredLabwareGroup:
777
+ return StackerStoredLabwareGroup(
778
+ primaryLabwareId=core_group.primary.labware_id,
779
+ adapterLabwareId=(
780
+ core_group.adapter.labware_id if core_group.adapter else None
781
+ ),
782
+ lidLabwareId=core_group.lid.labware_id if core_group.lid else None,
783
+ )
784
+
785
+ def _group_from_core(self, labware: LabwareCore) -> StackerStoredLabwareGroup:
786
+ return self._group_from_core_group(self._core_groups_from_primary_core(labware))
787
+
788
+ def fill_items(self, labware: Sequence[LabwareCore], message: str | None) -> None:
789
+ """Pause the protocol to fill with a specific set of labware."""
790
+ groups = [self._group_from_core(core) for core in labware]
791
+ self._engine_client.execute_command(
792
+ cmd.flex_stacker.FillParams(
793
+ moduleId=self._module_id,
794
+ strategy=StackerFillEmptyStrategy.MANUAL_WITH_PAUSE,
795
+ message=message,
796
+ labwareToStore=groups,
797
+ count=None,
798
+ )
799
+ )
800
+
801
+ def empty(self, message: str | None) -> None:
802
+ """Pause the protocol to remove labware from the Flex Stacker's hopper."""
803
+ self._engine_client.execute_command(
804
+ cmd.flex_stacker.EmptyParams(
805
+ moduleId=self.module_id,
806
+ strategy=StackerFillEmptyStrategy.MANUAL_WITH_PAUSE,
807
+ message=message,
808
+ count=0,
809
+ )
810
+ )
811
+
812
+ def get_max_storable_labware(self) -> int:
813
+ """Get the total number of configured labware the stacker can store."""
814
+ max_lw = self._engine_client.state.modules.stacker_max_pool_count(
815
+ self._module_id
816
+ )
817
+ if max_lw is None:
818
+ location = self._engine_client.state.modules.get_location(self._module_id)
819
+ raise FlexStackerLabwarePoolNotYetDefinedError(
820
+ message=f"The Flex Stacker in {location} has not been configured yet and cannot be filled."
821
+ )
822
+ return max_lw
823
+
824
+ def get_current_storable_labware(self) -> int:
825
+ """Get the amount of space currently available for labware."""
826
+ max_lw = self.get_max_storable_labware()
827
+ if max_lw is None:
828
+ location = self._engine_client.state.modules.get_location(self._module_id)
829
+ raise FlexStackerLabwarePoolNotYetDefinedError(
830
+ message=f"The Flex Stacker in {location} has not been configured yet and cannot be filled."
831
+ )
832
+ current = len(
833
+ self._engine_client.state.modules.stacker_contained_labware(self._module_id)
834
+ )
835
+ return max_lw - current
836
+
837
+ def _predict_storable_count(
838
+ self,
839
+ labwares: _CoreTrio,
840
+ overlap_offset: float | None = None,
841
+ ) -> int:
842
+ definitions = (
843
+ self._engine_client.state.labware.stacker_labware_pool_to_ordered_list(
844
+ labwares.primary.get_engine_definition(),
845
+ labwares.lid.get_engine_definition() if labwares.lid else None,
846
+ labwares.adapter.get_engine_definition() if labwares.adapter else None,
847
+ )
848
+ )
849
+ pool_height = self._engine_client.state.geometry.get_height_of_labware_stack(
850
+ definitions
851
+ )
852
+ pool_overlap = (
853
+ overlap_offset
854
+ if overlap_offset is not None
855
+ else self._engine_client.state.labware.get_stacker_labware_overlap_offset(
856
+ definitions
857
+ ).z
858
+ )
859
+ return self._engine_client.state.modules.stacker_max_pool_count_by_height(
860
+ self._module_id, pool_height, pool_overlap
861
+ )
862
+
863
+ def get_max_storable_labware_from_list(
864
+ self,
865
+ labware: Sequence[LabwareCore],
866
+ overlap_offset: float | None = None,
867
+ ) -> Sequence[LabwareCore]:
868
+ """Limit the passed list to how many labware can fit in a stacker."""
869
+ if not labware:
870
+ return labware
871
+ max_count: int
872
+ try:
873
+ # if the stacker has been configured, make sure the provided overlap
874
+ # offset, if any, matches the configured one
875
+ max_count = self.get_max_storable_labware()
876
+ if overlap_offset is not None:
877
+ self._engine_client.state.modules.validate_stacker_overlap_offset(
878
+ self._module_id, overlap_offset
879
+ )
880
+ except FlexStackerLabwarePoolNotYetDefinedError:
881
+ max_count = self._predict_storable_count(
882
+ self._core_groups_from_primary_core(labware[0]), overlap_offset
883
+ )
884
+ return labware[:max_count]
885
+
886
+ def get_current_storable_labware_from_list(
887
+ self,
888
+ labware: Sequence[LabwareCore],
889
+ ) -> Sequence[LabwareCore]:
890
+ """Limit the passed list to how many labware can fit in the stacker right now."""
891
+ if not labware:
892
+ return labware
893
+ storable = self.get_current_storable_labware()
894
+ return labware[:storable]
895
+
896
+ def get_stored_labware(self) -> Sequence[LabwareCore]:
897
+ """Get the currently-stored primary labware from the stacker."""
898
+ stored_groups = self._engine_client.state.modules.stacker_contained_labware(
899
+ self._module_id
900
+ )
901
+ return [
902
+ self._protocol_core.add_or_get_labware_core(group.primaryLabwareId)
903
+ for group in stored_groups
904
+ ]
905
+
906
+ @overload
907
+ def _ssld_from_core(
908
+ self, core: LabwareCore
909
+ ) -> cmd.flex_stacker.StackerStoredLabwareDetails:
910
+ ...
911
+
912
+ @overload
913
+ def _ssld_from_core(self, core: None) -> None:
914
+ ...
915
+
916
+ def _ssld_from_core(
917
+ self, core: LabwareCore | None
918
+ ) -> cmd.flex_stacker.StackerStoredLabwareDetails | None:
919
+ if not core:
920
+ return None
921
+ definition = core.get_engine_definition()
922
+ return cmd.flex_stacker.StackerStoredLabwareDetails(
923
+ loadName=definition.parameters.loadName,
924
+ namespace=definition.namespace,
925
+ version=definition.version,
926
+ )
927
+
928
+ def set_stored_labware_items(
929
+ self,
930
+ labware: Sequence[LabwareCore],
931
+ stacking_offset_z: float | None,
932
+ ) -> None:
933
+ """Configure the stacker to contain a set of labware."""
934
+ core_groups = [self._core_groups_from_primary_core(core) for core in labware]
935
+ if len(core_groups) < 1:
936
+ raise CommandPreconditionViolated(
937
+ "At least one labware must be passed to set_stored_labware_items"
938
+ )
939
+ stacker_groups = [
940
+ self._group_from_core_group(core_group) for core_group in core_groups
941
+ ]
942
+
943
+ self._engine_client.execute_command(
944
+ cmd.flex_stacker.SetStoredLabwareParams(
945
+ moduleId=self.module_id,
946
+ initialCount=None,
947
+ initialStoredLabware=stacker_groups,
948
+ primaryLabware=self._ssld_from_core(core_groups[0].primary),
949
+ lidLabware=self._ssld_from_core(core_groups[0].lid),
950
+ adapterLabware=self._ssld_from_core(core_groups[0].adapter),
951
+ poolOverlapOverride=stacking_offset_z,
952
+ )
953
+ )
954
+
955
+ def set_stored_labware(
956
+ self,
957
+ main_load_name: str,
958
+ main_namespace: str | None,
959
+ main_version: int | None,
960
+ lid_load_name: str | None,
961
+ lid_namespace: str | None,
962
+ lid_version: int | None,
963
+ adapter_load_name: str | None,
964
+ adapter_namespace: str | None,
965
+ adapter_version: int | None,
966
+ count: int | None,
967
+ stacking_offset_z: float | None = None,
968
+ ) -> None:
969
+ """Configure the kind of labware that the stacker stores."""
970
+
971
+ custom_labware_params = (
972
+ self._engine_client.state.labware.find_custom_labware_load_params()
973
+ )
974
+
975
+ main_namespace, main_version = load_labware_params.resolve(
976
+ main_load_name,
977
+ main_namespace,
978
+ main_version,
979
+ custom_labware_params,
980
+ self._api_version,
981
+ )
982
+ main_labware = cmd.flex_stacker.StackerStoredLabwareDetails(
983
+ loadName=main_load_name, namespace=main_namespace, version=main_version
984
+ )
985
+
986
+ lid_labware: cmd.flex_stacker.StackerStoredLabwareDetails | None = None
987
+
988
+ if lid_load_name:
989
+ lid_namespace, lid_version = load_labware_params.resolve(
990
+ lid_load_name,
991
+ lid_namespace,
992
+ lid_version,
993
+ custom_labware_params,
994
+ self._api_version,
995
+ )
996
+ lid_labware = cmd.flex_stacker.StackerStoredLabwareDetails(
997
+ loadName=lid_load_name, namespace=lid_namespace, version=lid_version
998
+ )
999
+
1000
+ adapter_labware: cmd.flex_stacker.StackerStoredLabwareDetails | None = None
1001
+
1002
+ if adapter_load_name:
1003
+ adapter_namespace, adapter_version = load_labware_params.resolve(
1004
+ adapter_load_name,
1005
+ adapter_namespace,
1006
+ adapter_version,
1007
+ custom_labware_params,
1008
+ self._api_version,
1009
+ )
1010
+ adapter_labware = cmd.flex_stacker.StackerStoredLabwareDetails(
1011
+ loadName=adapter_load_name,
1012
+ namespace=adapter_namespace,
1013
+ version=adapter_version,
1014
+ )
1015
+
1016
+ self._engine_client.execute_command(
1017
+ cmd.flex_stacker.SetStoredLabwareParams(
1018
+ moduleId=self.module_id,
1019
+ initialCount=count,
1020
+ primaryLabware=main_labware,
1021
+ lidLabware=lid_labware,
1022
+ adapterLabware=adapter_labware,
1023
+ poolOverlapOverride=stacking_offset_z,
1024
+ )
1025
+ )