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