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,166 @@
1
+ """
2
+ util.async_helpers - various utilities for asyncio functions and tasks.
3
+ """
4
+
5
+ from functools import wraps
6
+ from threading import Thread
7
+ from typing import (
8
+ Any,
9
+ AsyncContextManager,
10
+ Awaitable,
11
+ Callable,
12
+ Generator,
13
+ Tuple,
14
+ TypeVar,
15
+ cast,
16
+ )
17
+
18
+ import asyncio
19
+ import contextlib
20
+ import queue
21
+
22
+
23
+ async def asyncio_yield() -> None:
24
+ """
25
+ Ensure that the current task yields to the event loop.
26
+
27
+ The python async framework only switches between concurrently-running tasks when
28
+ the currently-running task hits a leaf call that requires waiting for an event on
29
+ the loop. That means that you can have a very long call of nice coroutines with
30
+ async def and await call() that still effectively "block" other concurrent tasks
31
+ from actually executing.
32
+
33
+ There's also not really a nice way to yield to the event loop explicitly. The best
34
+ way to do it is to drop in await asyncio.sleep(0), which will yield to the loop and
35
+ let something else run.
36
+
37
+ If you have an async call chain that is used in a tight loop and at no point contains
38
+ an await() call that will yield the loop - this will be anything that
39
+ - Involves touching a file descriptor that is registered with an asyncio protocol
40
+ - Involves waiting for a Future
41
+ - Involves waiting for another task
42
+ - Involves specifically invoking an asyncio scheduling operation like gather()
43
+ - Uses asyncio.sleep()
44
+
45
+ You should drop an await asyncio_yield() at the most frequent leaf call to make sure
46
+ that other tasks on the loop get a chance to run.
47
+ """
48
+ await asyncio.sleep(0)
49
+
50
+
51
+ _Wrapped = TypeVar("_Wrapped", bound=Callable[..., Awaitable[Any]])
52
+
53
+
54
+ def ensure_yield(async_def_func: _Wrapped) -> _Wrapped:
55
+ """
56
+ A decorator that makes sure that asyncio_yield() is called after the decorated async
57
+ function finishes executing.
58
+ """
59
+
60
+ # _wrapper can be typed using ParamSpec https://docs.python.org/3/library/typing.html#typing.ParamSpec
61
+ # when we
62
+ # - bump to a mypy version that supports it (>0.930)
63
+ # - either go to python 3.10 or bump typing_extensions to 4.2.0
64
+ # Until then, this is a mess of opaque type vars and disabling internal checking because of their
65
+ # opacity. The cast on line 58 should keep the external interface of the annotated function correct.
66
+ @wraps(async_def_func)
67
+ async def _wrapper(*args: Any, **kwargs: Any) -> Any:
68
+ ret = await async_def_func(*args, **kwargs)
69
+ await asyncio_yield()
70
+ return ret
71
+
72
+ return cast(_Wrapped, _wrapper)
73
+
74
+
75
+ _ContextManagerResult = TypeVar("_ContextManagerResult")
76
+
77
+
78
+ @contextlib.contextmanager
79
+ def async_context_manager_in_thread(
80
+ async_context_manager: AsyncContextManager[_ContextManagerResult],
81
+ ) -> Generator[Tuple[_ContextManagerResult, asyncio.AbstractEventLoop], None, None]:
82
+ """Enter an async context manager in a worker thread.
83
+
84
+ When you enter this context manager, it:
85
+
86
+ 1. Spawns a worker thread.
87
+ 2. In that thread, starts an asyncio event loop.
88
+ 3. In that event loop, enters the context manager that you passed in.
89
+ 4. Returns: the result of entering that context manager, and the running event loop.
90
+ Use functions like `asyncio.run_coroutine_threadsafe()` to safely interact
91
+ with the returned object from your thread.
92
+
93
+ When you exit this context manager, it:
94
+
95
+ 1. In the worker thread's event loop, exits the context manager that you passed in.
96
+ 2. Stops and cleans up the worker thread's event loop.
97
+ 3. Joins the worker thread.
98
+ """
99
+ with _run_loop_in_thread() as loop_in_thread:
100
+ async_object = asyncio.run_coroutine_threadsafe(
101
+ async_context_manager.__aenter__(),
102
+ loop=loop_in_thread,
103
+ ).result()
104
+
105
+ try:
106
+ yield async_object, loop_in_thread
107
+
108
+ finally:
109
+ exit = asyncio.run_coroutine_threadsafe(
110
+ async_context_manager.__aexit__(None, None, None),
111
+ loop=loop_in_thread,
112
+ )
113
+ exit.result()
114
+
115
+
116
+ @contextlib.contextmanager
117
+ def _run_loop_in_thread() -> Generator[asyncio.AbstractEventLoop, None, None]:
118
+ """Run an event loop in a worker thread.
119
+
120
+ Entering this context manager spawns a thread, starts an asyncio event loop in it,
121
+ and returns that loop.
122
+
123
+ Exiting this context manager stops and cleans up the event loop, and then joins the thread.
124
+ """
125
+ loop_mailbox: "queue.SimpleQueue[asyncio.AbstractEventLoop]" = queue.SimpleQueue()
126
+
127
+ def _in_thread() -> None:
128
+ loop = asyncio.new_event_loop()
129
+
130
+ # We assume that the lines above this will never fail,
131
+ # so we will always reach this point to unblock the parent thread.
132
+ loop_mailbox.put(loop)
133
+
134
+ loop.run_forever()
135
+
136
+ # If we've reached here, the loop has been stopped from outside this thread. Clean it up.
137
+ #
138
+ # This cleanup is naive because asyncio makes it difficult and confusing to get it right.
139
+ # Compare this with asyncio.run()'s cleanup, which:
140
+ #
141
+ # * Cancels and awaits any remaining tasks
142
+ # (according to the source code--this seems undocumented)
143
+ # * Shuts down asynchronous generators
144
+ # (see asyncio.shutdown_asyncgens())
145
+ # * Shuts down the default thread pool executor
146
+ # (see https://bugs.python.org/issue34037 and asyncio.shutdown_default_executor())
147
+ #
148
+ # In Python >=3.11, we should rewrite this to use asyncio.Runner,
149
+ # which can take care of these nuances for us.
150
+ loop.close()
151
+
152
+ thread = Thread(
153
+ target=_in_thread,
154
+ name=f"{__name__} event loop thread",
155
+ # This is a load-bearing daemon=True. It avoids @atexit-related deadlocks when this is used
156
+ # by opentrons.execute and cleaned up by opentrons.execute's @atexit handler.
157
+ # https://github.com/Opentrons/opentrons/pull/12970#issuecomment-1648243785
158
+ daemon=True,
159
+ )
160
+ thread.start()
161
+ loop_in_thread = loop_mailbox.get()
162
+ try:
163
+ yield loop_in_thread
164
+ finally:
165
+ loop_in_thread.call_soon_threadsafe(loop_in_thread.stop)
166
+ thread.join()
@@ -0,0 +1,84 @@
1
+ """A simple pub/sub message broker."""
2
+
3
+
4
+ from abc import ABC, abstractmethod
5
+ from contextlib import contextmanager
6
+ from typing import Callable, ContextManager, Generator, Generic, Set, TypeVar
7
+
8
+
9
+ _MessageT = TypeVar("_MessageT")
10
+ _CallbackT = Callable[[_MessageT], None]
11
+
12
+
13
+ class ReadOnlyBroker(ABC, Generic[_MessageT]):
14
+ """The read-only subset of `Broker`.
15
+
16
+ Useful for typing if you want people to be able to subscribe to your `Broker`,
17
+ but don't want them to be able to publish their own messages to it.
18
+ """
19
+
20
+ @abstractmethod
21
+ def subscribed(self, callback: _CallbackT[_MessageT]) -> ContextManager[None]:
22
+ """See `Broker.subscribed()`.""" # noqa: D402
23
+ pass
24
+
25
+ @abstractmethod
26
+ def subscribe(self, callback: _CallbackT[_MessageT]) -> Callable[[], None]:
27
+ """See `Broker.subscribe()`.""" # noqa: D402
28
+ pass
29
+
30
+
31
+ class Broker(Generic[_MessageT], ReadOnlyBroker[_MessageT]):
32
+ """A simple pub/sub message broker.
33
+
34
+ Subscribers can listen to events. Publishers can push events to all subscribers.
35
+ """
36
+
37
+ def __init__(self) -> None:
38
+ self._callbacks: Set[_CallbackT[_MessageT]] = set()
39
+
40
+ @contextmanager
41
+ def subscribed(
42
+ self, callback: _CallbackT[_MessageT]
43
+ ) -> Generator[None, None, None]:
44
+ """Register a callback to be called on each message.
45
+
46
+ The callback is subscribed when this context manager is entered,
47
+ and unsubscribed when it's exited.
48
+
49
+ You must not subscribe the same callback again unless you first usubscribe it.
50
+ """
51
+ unsubscribe = self.subscribe(callback)
52
+ try:
53
+ yield
54
+ finally:
55
+ unsubscribe()
56
+
57
+ def subscribe(self, callback: _CallbackT[_MessageT]) -> Callable[[], None]:
58
+ """Register a callback to be called on each message.
59
+
60
+ You must not subscribe the same callback again unless you first unsubscribe it.
61
+
62
+ Returns:
63
+ A function that you can call to unsubscribe ``callback``.
64
+ You must not call it more than once.
65
+ """
66
+
67
+ def unsubscribe() -> None:
68
+ self._callbacks.remove(callback)
69
+
70
+ self._callbacks.add(callback)
71
+ return unsubscribe
72
+
73
+ def publish(self, message: _MessageT) -> None:
74
+ """Call every subscribed callback, with ``message`` as the argument.
75
+
76
+ The order in which the callbacks are called is undefined.
77
+
78
+ If any callback raises an exception, it's propagated,
79
+ and any remaining callbacks will be left uncalled.
80
+ """
81
+ # Callback order is undefined because
82
+ # Python sets don't preserve insertion order.
83
+ for callback in self._callbacks:
84
+ callback(message)
@@ -0,0 +1,47 @@
1
+ """Simple state change notification interface."""
2
+ import asyncio
3
+
4
+
5
+ class ChangeNotifier:
6
+ """An interface to emit or subscribe to state change notifications."""
7
+
8
+ def __init__(self) -> None:
9
+ """Initialize the ChangeNotifier with an internal Event."""
10
+ self._event = asyncio.Event()
11
+
12
+ def notify(self) -> None:
13
+ """Notify all `wait`'ers that the state has changed."""
14
+ self._event.set()
15
+
16
+ async def wait(self) -> None:
17
+ """Wait until the next state change notification."""
18
+ await self._event.wait()
19
+ self._event.clear()
20
+
21
+
22
+ class ChangeNotifier_ts(ChangeNotifier):
23
+ """ChangeNotifier initialized with Event_ts."""
24
+
25
+ def __init__(self) -> None:
26
+ """Initialize the ChangeNotifier_Ts with an internal Event_ts."""
27
+ super().__init__()
28
+ self._event = Event_ts()
29
+
30
+
31
+ class Event_ts(asyncio.Event):
32
+ """asyncio.Event with threadsafe methods."""
33
+
34
+ def __init__(self) -> None:
35
+ """Initialize Event_ts with the active event_loop or event_loop_policy if not active."""
36
+ super().__init__()
37
+ if self._loop is None:
38
+ self._loop: asyncio.AbstractEventLoop = asyncio.get_event_loop()
39
+
40
+ def set(self) -> None:
41
+ """Primarily intended for calling from a thread not responsible for the event loop.
42
+
43
+ Calling set() from the event loop thread will actually delay the execution of the set() until the
44
+ calling method either yields, awaits, or exits altogether. This is usually fine but might occasionally cause
45
+ unexpected behavior.
46
+ """
47
+ self._loop.call_soon_threadsafe(super().set)
@@ -0,0 +1,278 @@
1
+ """ opentrons.util.entrypoint_util: functions common to entrypoints
2
+ """
3
+
4
+ import asyncio
5
+ import contextlib
6
+ from dataclasses import dataclass
7
+ import json
8
+ import logging
9
+ import pathlib
10
+ import subprocess
11
+ import sys
12
+ import tempfile
13
+ from typing import (
14
+ Dict,
15
+ Generator,
16
+ List,
17
+ Optional,
18
+ Sequence,
19
+ Union,
20
+ TYPE_CHECKING,
21
+ )
22
+
23
+ from opentrons.calibration_storage.deck_configuration import (
24
+ deserialize_deck_configuration,
25
+ )
26
+ from opentrons.config import (
27
+ ARCHITECTURE,
28
+ IS_ROBOT,
29
+ JUPYTER_NOTEBOOK_LABWARE_DIR,
30
+ SystemArchitecture,
31
+ )
32
+ from opentrons.protocols import labware
33
+ from opentrons.calibration_storage import helpers
34
+ from opentrons.protocol_engine.errors.error_occurrence import (
35
+ ErrorOccurrence as ProtocolEngineErrorOccurrence,
36
+ )
37
+ from opentrons.protocol_engine.types import DeckConfigurationType
38
+ from opentrons.protocol_reader import ProtocolReader, ProtocolSource
39
+ from opentrons.protocols.types import JsonProtocol, Protocol, PythonProtocol
40
+
41
+ if TYPE_CHECKING:
42
+ from opentrons_shared_data.labware.types import LabwareDefinition
43
+
44
+
45
+ log = logging.getLogger(__name__)
46
+
47
+
48
+ @dataclass
49
+ class FoundLabware:
50
+ """An individual labware found by `labware_from_paths()`."""
51
+
52
+ path: pathlib.Path
53
+ definition: "LabwareDefinition"
54
+
55
+
56
+ def labware_from_paths(
57
+ paths: Sequence[Union[str, pathlib.Path]]
58
+ ) -> Dict[str, FoundLabware]:
59
+ """Search paths for labware definitions.
60
+
61
+ Returns:
62
+ A dict, keyed by labware URI, where each value has the file path and the parsed def.
63
+ """
64
+ labware_defs: Dict[str, FoundLabware] = {}
65
+
66
+ for strpath in paths:
67
+ log.info(f"local labware: checking path {strpath}")
68
+ purepath = pathlib.PurePath(strpath)
69
+ if purepath.is_absolute():
70
+ path = pathlib.Path(purepath)
71
+ else:
72
+ path = pathlib.Path.cwd() / purepath
73
+ if not path.is_dir():
74
+ raise RuntimeError(f"{path} is not a directory")
75
+ for child in path.iterdir():
76
+ if child.is_file() and child.suffix.endswith("json"):
77
+ try:
78
+ defn = labware.verify_definition(child.read_bytes())
79
+ except labware.NotALabwareError:
80
+ log.info(f"{child}: invalid labware, ignoring")
81
+ log.debug(
82
+ f"{child}: labware invalid because of this exception.",
83
+ exc_info=True,
84
+ )
85
+ else:
86
+ uri = helpers.uri_from_definition(defn)
87
+ labware_defs[uri] = FoundLabware(path=child, definition=defn)
88
+ log.info(f"loaded labware {uri} from {child}")
89
+ else:
90
+ log.info(f"ignoring {child} in labware path")
91
+ return labware_defs
92
+
93
+
94
+ def find_jupyter_labware() -> Optional[Dict[str, FoundLabware]]:
95
+ """Return labware files in this robot's Jupyter Notebook directory.
96
+
97
+ Returns:
98
+ If we're running on an Opentrons robot:
99
+ A dict, keyed by labware URI, where each value has the file path and the parsed def.
100
+
101
+ Otherwise: None.
102
+ """
103
+ if IS_ROBOT:
104
+ # JUPYTER_NOTEBOOK_LABWARE_DIR should never be None when IS_ROBOT == True.
105
+ assert JUPYTER_NOTEBOOK_LABWARE_DIR is not None
106
+ if JUPYTER_NOTEBOOK_LABWARE_DIR.is_dir():
107
+ return labware_from_paths([JUPYTER_NOTEBOOK_LABWARE_DIR])
108
+
109
+ return None
110
+
111
+
112
+ def datafiles_from_paths(paths: Sequence[Union[str, pathlib.Path]]) -> Dict[str, bytes]:
113
+ datafiles: Dict[str, bytes] = {}
114
+ for strpath in paths:
115
+ log.info(f"data files: checking path {strpath}")
116
+ purepath = pathlib.PurePath(strpath)
117
+ if purepath.is_absolute():
118
+ path = pathlib.Path(purepath)
119
+ else:
120
+ path = pathlib.Path.cwd() / purepath
121
+ if path.is_file():
122
+ datafiles[path.name] = path.read_bytes()
123
+ log.info(f"read {path} into custom data as {path.name}")
124
+ elif path.is_dir():
125
+ for child in path.iterdir():
126
+ if child.is_file():
127
+ datafiles[child.name] = child.read_bytes()
128
+ log.info(f"read {child} into data path as {child.name}")
129
+ else:
130
+ log.info(f"ignoring {child} in data path")
131
+ return datafiles
132
+
133
+
134
+ def get_deck_configuration() -> DeckConfigurationType:
135
+ """Return the host robot's current deck configuration.
136
+
137
+ This is a hacky implementation because the deck configuration is owned by
138
+ robot-server. See `robot_server.deck_configuration.cli`.
139
+ """
140
+ match ARCHITECTURE:
141
+ # These hard-coded paths need to be kept in sync with robot-server's
142
+ # systemd configuration:
143
+ case SystemArchitecture.BUILDROOT:
144
+ robot_server_persistence_dir = "/data/opentrons_robot_server"
145
+ case SystemArchitecture.YOCTO:
146
+ robot_server_persistence_dir = "/var/lib/opentrons-robot-server"
147
+ case SystemArchitecture.HOST:
148
+ # todo(mm, 2024-08-13):
149
+ # It's unclear what should happen if you run an `opentrons.execute` entry
150
+ # point on a non-robot device that doesn't have robot-server. I can't
151
+ # imagine we'd let actual users do this, but it might happen in internal
152
+ # testing. This empty list return value is totally arbitrary and will
153
+ # probably not do the right thing.
154
+ return []
155
+
156
+ proc = subprocess.run(
157
+ [
158
+ sys.executable,
159
+ "-m",
160
+ "robot_server.deck_configuration.cli",
161
+ "--persistence-directory",
162
+ robot_server_persistence_dir,
163
+ ],
164
+ check=True,
165
+ capture_output=True,
166
+ )
167
+ deserialized_deck_configuration = deserialize_deck_configuration(proc.stdout)
168
+ if deserialized_deck_configuration is None:
169
+ raise RuntimeError("Error getting the host robot's deck configuration.")
170
+
171
+ cutout_fixture_placements, _ = deserialized_deck_configuration
172
+
173
+ return [
174
+ (
175
+ cutout_fixture_placement.cutout_id,
176
+ cutout_fixture_placement.cutout_fixture_id,
177
+ cutout_fixture_placement.opentrons_module_serial_number,
178
+ )
179
+ for cutout_fixture_placement in cutout_fixture_placements
180
+ ]
181
+
182
+
183
+ @contextlib.contextmanager
184
+ def adapt_protocol_source(protocol: Protocol) -> Generator[ProtocolSource, None, None]:
185
+ """Convert a `Protocol` to a `ProtocolSource`.
186
+
187
+ `Protocol` and `ProtocolSource` do basically the same thing. `Protocol` is the traditional
188
+ interface. `ProtocolSource` is the newer, but not necessarily better, interface that's required
189
+ to run stuff through Protocol Engine. Ideally, the two would be unified. Until then, we have
190
+ this shim.
191
+
192
+ This is a context manager because it needs to keep some temp files around.
193
+ """
194
+ # ProtocolReader needs to know the filename of the main protocol file so it can infer from its
195
+ # extension whether it's a JSON or Python protocol. But that filename doesn't necessarily exist,
196
+ # like when a user passes a text stream to opentrons.simulate.simulate(). As a hack, work
197
+ # backwards and synthesize a dummy filename with the correct extension.
198
+ if protocol.filename is not None:
199
+ # We were given a filename, so no need to guess.
200
+ #
201
+ # It's not well-defined in our customer-facing interfaces whether the supplied protocol_name
202
+ # should be just the filename part, or a path with separators. In case it contains stuff
203
+ # like "../", sanitize it to just the filename part so we don't save files somewhere bad.
204
+ main_file_name = pathlib.Path(protocol.filename).name
205
+ elif isinstance(protocol, JsonProtocol):
206
+ main_file_name = "protocol.json"
207
+ else:
208
+ main_file_name = "protocol.py"
209
+
210
+ with tempfile.TemporaryDirectory() as temporary_directory:
211
+ # FIXME(mm, 2023-06-26): Copying these files is pure overhead, and it introduces encoding
212
+ # hazards. Remove this when we can parse JSONv6+ and PAPIv2.14+ protocols without going
213
+ # through the filesystem. https://opentrons.atlassian.net/browse/RSS-281
214
+
215
+ main_file = pathlib.Path(temporary_directory) / main_file_name
216
+ if isinstance(protocol.text, str):
217
+ main_file.write_text(protocol.text, encoding="utf-8")
218
+ else:
219
+ main_file.write_bytes(protocol.text)
220
+
221
+ labware_files: List[pathlib.Path] = []
222
+ if isinstance(protocol, PythonProtocol) and protocol.extra_labware is not None:
223
+ for labware_index, labware_definition in enumerate(
224
+ protocol.extra_labware.values()
225
+ ):
226
+ new_labware_file = (
227
+ pathlib.Path(temporary_directory) / f"{labware_index}.json"
228
+ )
229
+ new_labware_file.write_text(
230
+ json.dumps(labware_definition), encoding="utf-8"
231
+ )
232
+ labware_files.append(new_labware_file)
233
+
234
+ protocol_source = asyncio.run(
235
+ ProtocolReader().read_saved(
236
+ files=[main_file] + labware_files,
237
+ directory=None,
238
+ files_are_prevalidated=False,
239
+ )
240
+ )
241
+
242
+ yield protocol_source
243
+
244
+
245
+ class ProtocolEngineExecuteError(Exception):
246
+ def __init__(self, errors: List[ProtocolEngineErrorOccurrence]) -> None:
247
+ """Raised when there was any fatal error running a protocol through Protocol Engine.
248
+
249
+ Protocol Engine reports errors as data, not as exceptions.
250
+ But the only way for `opentrons.execute.execute()` and `opentrons.simulate.simulate()`
251
+ to signal problems to their callers is to raise something.
252
+ So we need this class to wrap them.
253
+
254
+ Params:
255
+ errors: The errors that Protocol Engine reported.
256
+ """
257
+ # Show the full error details if this is part of a traceback. Don't try to summarize.
258
+ super().__init__(errors)
259
+
260
+ self._error_occurrences = errors
261
+
262
+ def to_stderr_string(self) -> str:
263
+ """Return a string suitable as the stderr output of the `opentrons_execute` CLI.
264
+
265
+ This summarizes from the full error details.
266
+ """
267
+ # It's unclear what exactly we should extract here.
268
+ #
269
+ # First, do we print the first element, or the last, or all of them?
270
+ #
271
+ # Second, do we print the .detail? .errorCode? .errorInfo? .wrappedErrors?
272
+ # By contract, .detail seems like it would be insufficient, but experimentally,
273
+ # it includes a lot, like:
274
+ #
275
+ # ProtocolEngineError [line 3]: Error 4000 GENERAL_ERROR (ProtocolEngineError):
276
+ # UnexpectedProtocolError: Labware "fixture_12_trough" not found with version 1
277
+ # in namespace "fixture".
278
+ return self._error_occurrences[0].detail
@@ -0,0 +1,26 @@
1
+ # noqa: D100
2
+
3
+ import typing
4
+
5
+
6
+ def get_union_elements(type_alias: typing.Any) -> tuple[typing.Any, ...]:
7
+ """Return the elements comprising a `typing.Union`.
8
+
9
+ e.g. `get_union_elements(Union[int, str, float])` returns `(int, str, float)`.
10
+
11
+ If the union itself is wrapped with `typing.Annotated`, it's discarded.
12
+ If an individual element is wrapped with `typing.Annotated`, it's returned as-is.
13
+
14
+ Ideally, we would use `typing.get_type_hints(..., include_extras=False)` for this,
15
+ but that only works for getting the annotations of a function, method, module, or
16
+ class, and sometimes we want to unpack an individual union type alias.
17
+ """
18
+ origin, args = typing.get_origin(type_alias), typing.get_args(type_alias)
19
+ if origin is typing.Annotated:
20
+ # Unwrap Annotated[Union[A, B, C]] to Union[A, B, C].
21
+ union_annotation = args[0]
22
+ return get_union_elements(union_annotation)
23
+ elif origin is typing.Union:
24
+ return args
25
+ else:
26
+ raise TypeError(f"get_union_elements() got unrecognized type {type_alias}")
@@ -0,0 +1,6 @@
1
+ from datetime import datetime, timezone
2
+
3
+
4
+ def utc_now() -> datetime:
5
+ """Return the current time in the UTC timezone."""
6
+ return datetime.now(tz=timezone.utc)