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,607 @@
1
+ """Pipetting command handling."""
2
+ from typing import Optional, Iterator, Tuple
3
+ from typing_extensions import Protocol as TypingProtocol
4
+ from contextlib import contextmanager
5
+
6
+ from opentrons.hardware_control import HardwareControlAPI
7
+
8
+ from ..state.state import StateView
9
+ from ..state.pipettes import HardwarePipette
10
+ from ..notes import CommandNoteAdder, CommandNote
11
+ from ..errors.exceptions import (
12
+ TipNotAttachedError,
13
+ InvalidAspirateVolumeError,
14
+ InvalidPushOutVolumeError,
15
+ InvalidDispenseVolumeError,
16
+ InvalidLiquidHeightFound,
17
+ )
18
+ from opentrons.protocol_engine.types import WellLocation
19
+ from opentrons.protocol_engine.types.liquid_level_detection import (
20
+ SimulatedProbeResult,
21
+ LiquidTrackingType,
22
+ )
23
+
24
+ # 1e-9 µL (1 femtoliter!) is a good value because:
25
+ # * It's large relative to rounding errors that occur in practice in protocols. For
26
+ # example, https://opentrons.atlassian.net/browse/RESC-182 shows a rounding error
27
+ # on the order of 1e-15 µL.
28
+ # * It's small relative to volumes that our users might actually care about and
29
+ # expect the robot to execute faithfully.
30
+ # * It's the default absolute tolerance for math.isclose(), where it apparently works
31
+ # well in general.
32
+ _VOLUME_ROUNDING_ERROR_TOLERANCE = 1e-9
33
+
34
+
35
+ class PipettingHandler(TypingProtocol):
36
+ """Liquid handling commands."""
37
+
38
+ def get_state_view(self) -> StateView:
39
+ """Get the stateview associated with this handler."""
40
+
41
+ def get_is_ready_to_aspirate(self, pipette_id: str) -> bool:
42
+ """Get whether a pipette is ready to aspirate."""
43
+
44
+ async def prepare_for_aspirate(self, pipette_id: str) -> None:
45
+ """Prepare for pipette aspiration."""
46
+
47
+ async def aspirate_in_place(
48
+ self,
49
+ pipette_id: str,
50
+ volume: float,
51
+ flow_rate: float,
52
+ command_note_adder: CommandNoteAdder,
53
+ correction_volume: float = 0.0,
54
+ ) -> float:
55
+ """Set flow-rate and aspirate."""
56
+
57
+ async def aspirate_while_tracking(
58
+ self,
59
+ pipette_id: str,
60
+ labware_id: str,
61
+ well_name: str,
62
+ volume: float,
63
+ flow_rate: float,
64
+ command_note_adder: CommandNoteAdder,
65
+ ) -> float:
66
+ """Set flow-rate and aspirate while tracking."""
67
+
68
+ async def dispense_while_tracking(
69
+ self,
70
+ pipette_id: str,
71
+ labware_id: str,
72
+ well_name: str,
73
+ volume: float,
74
+ flow_rate: float,
75
+ push_out: Optional[float],
76
+ is_full_dispense: bool = False,
77
+ ) -> float:
78
+ """Set flow-rate and dispense while tracking."""
79
+
80
+ async def dispense_in_place(
81
+ self,
82
+ pipette_id: str,
83
+ volume: float,
84
+ flow_rate: float,
85
+ push_out: Optional[float],
86
+ is_full_dispense: bool,
87
+ correction_volume: float = 0.0,
88
+ ) -> float:
89
+ """Set flow-rate and dispense."""
90
+
91
+ async def blow_out_in_place(
92
+ self,
93
+ pipette_id: str,
94
+ flow_rate: float,
95
+ ) -> None:
96
+ """Set flow rate and blow-out."""
97
+
98
+ async def liquid_probe_in_place(
99
+ self,
100
+ pipette_id: str,
101
+ labware_id: str,
102
+ well_name: str,
103
+ well_location: WellLocation,
104
+ ) -> LiquidTrackingType:
105
+ """Detect liquid level."""
106
+
107
+ async def increase_evo_disp_count(self, pipette_id: str) -> None:
108
+ """Increase evo tip dispense action count."""
109
+
110
+
111
+ class HardwarePipettingHandler(PipettingHandler):
112
+ """Liquid handling, using the Hardware API."""
113
+
114
+ def __init__(self, state_view: StateView, hardware_api: HardwareControlAPI) -> None:
115
+ """Initialize a PipettingHandler instance."""
116
+ self._state_view = state_view
117
+ self._hardware_api = hardware_api
118
+
119
+ def get_state_view(self) -> StateView:
120
+ """Get the stateview associated with this handler."""
121
+ return self._state_view
122
+
123
+ def get_is_ready_to_aspirate(self, pipette_id: str) -> bool:
124
+ """Get whether a pipette is ready to aspirate."""
125
+ hw_pipette = self._state_view.pipettes.get_hardware_pipette(
126
+ pipette_id=pipette_id,
127
+ attached_pipettes=self._hardware_api.attached_instruments,
128
+ )
129
+ return (
130
+ self._state_view.pipettes.get_aspirated_volume(pipette_id) is not None
131
+ and hw_pipette.config["ready_to_aspirate"]
132
+ and self._state_view.pipettes.get_ready_to_aspirate(pipette_id)
133
+ )
134
+
135
+ async def prepare_for_aspirate(self, pipette_id: str) -> None:
136
+ """Prepare for pipette aspiration.
137
+
138
+ Raises:
139
+ PipetteOverpressureError, propagated as-is from the hardware controller.
140
+ """
141
+ hw_mount = self._state_view.pipettes.get_mount(pipette_id).to_hw_mount()
142
+ await self._hardware_api.prepare_for_aspirate(mount=hw_mount)
143
+
144
+ def get_hw_aspirate_params(
145
+ self,
146
+ pipette_id: str,
147
+ volume: float,
148
+ command_note_adder: CommandNoteAdder,
149
+ ) -> Tuple[HardwarePipette, float]:
150
+ """Get params for hardware aspirate."""
151
+ _adjusted_volume = _validate_aspirate_volume(
152
+ state_view=self._state_view,
153
+ pipette_id=pipette_id,
154
+ aspirate_volume=volume,
155
+ command_note_adder=command_note_adder,
156
+ )
157
+ _hw_pipette = self._state_view.pipettes.get_hardware_pipette(
158
+ pipette_id=pipette_id,
159
+ attached_pipettes=self._hardware_api.attached_instruments,
160
+ )
161
+ return _hw_pipette, _adjusted_volume
162
+
163
+ def get_hw_dispense_params(
164
+ self,
165
+ pipette_id: str,
166
+ volume: float,
167
+ ) -> Tuple[HardwarePipette, float]:
168
+ """Get params for hardware dispense."""
169
+ _adjusted_volume = _validate_dispense_volume(
170
+ state_view=self._state_view,
171
+ pipette_id=pipette_id,
172
+ dispense_volume=volume,
173
+ )
174
+ _hw_pipette = self._state_view.pipettes.get_hardware_pipette(
175
+ pipette_id=pipette_id,
176
+ attached_pipettes=self._hardware_api.attached_instruments,
177
+ )
178
+ return _hw_pipette, _adjusted_volume
179
+
180
+ async def aspirate_while_tracking(
181
+ self,
182
+ pipette_id: str,
183
+ labware_id: str,
184
+ well_name: str,
185
+ volume: float,
186
+ flow_rate: float,
187
+ command_note_adder: CommandNoteAdder,
188
+ ) -> float:
189
+ """Set flow-rate and aspirate.
190
+
191
+ Raises:
192
+ PipetteOverpressureError, propagated as-is from the hardware controller.
193
+ """
194
+ # get mount and config data from state and hardware controller
195
+ hw_pipette, adjusted_volume = self.get_hw_aspirate_params(
196
+ pipette_id, volume, command_note_adder
197
+ )
198
+ aspirate_z_distance = self._state_view.geometry.get_liquid_handling_z_change(
199
+ labware_id=labware_id,
200
+ well_name=well_name,
201
+ operation_volume=volume * -1,
202
+ pipette_id=pipette_id,
203
+ )
204
+ if isinstance(aspirate_z_distance, SimulatedProbeResult):
205
+ raise InvalidLiquidHeightFound(
206
+ "Aspirate distance must be a float in Hardware pipetting handler."
207
+ )
208
+ with self._set_flow_rate(pipette=hw_pipette, aspirate_flow_rate=flow_rate):
209
+ await self._hardware_api.aspirate_while_tracking(
210
+ mount=hw_pipette.mount,
211
+ z_distance=aspirate_z_distance,
212
+ flow_rate=flow_rate,
213
+ volume=adjusted_volume,
214
+ )
215
+ return adjusted_volume
216
+
217
+ async def dispense_while_tracking(
218
+ self,
219
+ pipette_id: str,
220
+ labware_id: str,
221
+ well_name: str,
222
+ volume: float,
223
+ flow_rate: float,
224
+ push_out: Optional[float],
225
+ is_full_dispense: bool = False,
226
+ ) -> float:
227
+ """Set flow-rate and dispense.
228
+
229
+ Raises:
230
+ PipetteOverpressureError, propagated as-is from the hardware controller.
231
+ """
232
+ # get mount and config data from state and hardware controller
233
+ hw_pipette, adjusted_volume = self.get_hw_dispense_params(pipette_id, volume)
234
+ dispense_z_distance = self._state_view.geometry.get_liquid_handling_z_change(
235
+ labware_id=labware_id,
236
+ well_name=well_name,
237
+ operation_volume=volume,
238
+ pipette_id=pipette_id,
239
+ )
240
+ if isinstance(dispense_z_distance, SimulatedProbeResult):
241
+ raise InvalidLiquidHeightFound(
242
+ "Dispense distance must be a float in Hardware pipetting handler."
243
+ )
244
+ with self._set_flow_rate(pipette=hw_pipette, dispense_flow_rate=flow_rate):
245
+ await self._hardware_api.dispense_while_tracking(
246
+ mount=hw_pipette.mount,
247
+ z_distance=dispense_z_distance,
248
+ flow_rate=flow_rate,
249
+ volume=adjusted_volume,
250
+ push_out=push_out,
251
+ is_full_dispense=is_full_dispense,
252
+ )
253
+ return adjusted_volume
254
+
255
+ async def aspirate_in_place(
256
+ self,
257
+ pipette_id: str,
258
+ volume: float,
259
+ flow_rate: float,
260
+ command_note_adder: CommandNoteAdder,
261
+ correction_volume: float = 0.0,
262
+ ) -> float:
263
+ """Set flow-rate and aspirate.
264
+
265
+ Raises:
266
+ PipetteOverpressureError, propagated as-is from the hardware controller.
267
+ """
268
+ # get mount and config data from state and hardware controller
269
+ hw_pipette, adjusted_volume = self.get_hw_aspirate_params(
270
+ pipette_id, volume, command_note_adder
271
+ )
272
+ with self._set_flow_rate(pipette=hw_pipette, aspirate_flow_rate=flow_rate):
273
+ await self._hardware_api.aspirate(
274
+ mount=hw_pipette.mount,
275
+ volume=adjusted_volume,
276
+ correction_volume=correction_volume,
277
+ )
278
+
279
+ return adjusted_volume
280
+
281
+ async def dispense_in_place(
282
+ self,
283
+ pipette_id: str,
284
+ volume: float,
285
+ flow_rate: float,
286
+ push_out: Optional[float],
287
+ is_full_dispense: bool,
288
+ correction_volume: float = 0.0,
289
+ ) -> float:
290
+ """Dispense liquid without moving the pipette."""
291
+ hw_pipette, adjusted_volume = self.get_hw_dispense_params(pipette_id, volume)
292
+ # TODO (tz, 8-23-23): add a check for push_out not larger that the max volume allowed when working on this https://opentrons.atlassian.net/browse/RSS-329
293
+ if push_out and push_out < 0:
294
+ raise InvalidPushOutVolumeError(
295
+ "push out value cannot have a negative value."
296
+ )
297
+ with self._set_flow_rate(pipette=hw_pipette, dispense_flow_rate=flow_rate):
298
+ await self._hardware_api.dispense(
299
+ mount=hw_pipette.mount,
300
+ volume=adjusted_volume,
301
+ push_out=push_out,
302
+ correction_volume=correction_volume,
303
+ is_full_dispense=is_full_dispense,
304
+ )
305
+
306
+ return adjusted_volume
307
+
308
+ async def blow_out_in_place(
309
+ self,
310
+ pipette_id: str,
311
+ flow_rate: float,
312
+ ) -> None:
313
+ """Set flow rate and blow-out."""
314
+ # get mount and config data from state and hardware controller
315
+ hw_pipette = self._state_view.pipettes.get_hardware_pipette(
316
+ pipette_id=pipette_id,
317
+ attached_pipettes=self._hardware_api.attached_instruments,
318
+ )
319
+ with self._set_flow_rate(pipette=hw_pipette, blow_out_flow_rate=flow_rate):
320
+ await self._hardware_api.blow_out(mount=hw_pipette.mount)
321
+
322
+ async def liquid_probe_in_place(
323
+ self,
324
+ pipette_id: str,
325
+ labware_id: str,
326
+ well_name: str,
327
+ well_location: WellLocation,
328
+ ) -> LiquidTrackingType:
329
+ """Return liquid level relative to the bottom of the well."""
330
+ hw_pipette = self._state_view.pipettes.get_hardware_pipette(
331
+ pipette_id=pipette_id,
332
+ attached_pipettes=self._hardware_api.attached_instruments,
333
+ )
334
+ well_def = self._state_view.labware.get_well_definition(labware_id, well_name)
335
+ well_depth = well_def.depth
336
+ lld_min_height = self._state_view.pipettes.get_current_tip_lld_settings(
337
+ pipette_id=pipette_id
338
+ )
339
+ z_pos = await self._hardware_api.liquid_probe(
340
+ mount=hw_pipette.mount,
341
+ max_z_dist=well_depth - lld_min_height + well_location.offset.z,
342
+ )
343
+ labware_pos = self._state_view.geometry.get_labware_position(labware_id)
344
+ relative_height = z_pos - labware_pos.z - well_def.z
345
+ return float(relative_height)
346
+
347
+ @contextmanager
348
+ def _set_flow_rate(
349
+ self,
350
+ pipette: HardwarePipette,
351
+ aspirate_flow_rate: Optional[float] = None,
352
+ dispense_flow_rate: Optional[float] = None,
353
+ blow_out_flow_rate: Optional[float] = None,
354
+ ) -> Iterator[None]:
355
+ """Context manager for setting flow rate before calling aspirate, dispense, or blowout."""
356
+ original_aspirate_rate = pipette.config["aspirate_flow_rate"]
357
+ original_dispense_rate = pipette.config["dispense_flow_rate"]
358
+ original_blow_out_rate = pipette.config["blow_out_flow_rate"]
359
+ self._hardware_api.set_flow_rate(
360
+ pipette.mount,
361
+ aspirate=aspirate_flow_rate,
362
+ dispense=dispense_flow_rate,
363
+ blow_out=blow_out_flow_rate,
364
+ )
365
+ try:
366
+ yield
367
+ finally:
368
+ self._hardware_api.set_flow_rate(
369
+ pipette.mount,
370
+ aspirate=original_aspirate_rate,
371
+ dispense=original_dispense_rate,
372
+ blow_out=original_blow_out_rate,
373
+ )
374
+
375
+ async def increase_evo_disp_count(self, pipette_id: str) -> None:
376
+ """Increase evo tip dispense action count."""
377
+ hw_pipette = self._state_view.pipettes.get_hardware_pipette(
378
+ pipette_id=pipette_id,
379
+ attached_pipettes=self._hardware_api.attached_instruments,
380
+ )
381
+ await self._hardware_api.increase_evo_disp_count(mount=hw_pipette.mount)
382
+
383
+
384
+ class VirtualPipettingHandler(PipettingHandler):
385
+ """Liquid handling, using the virtual pipettes.""" ""
386
+
387
+ _state_view: StateView
388
+
389
+ def __init__(
390
+ self,
391
+ state_view: StateView,
392
+ ) -> None:
393
+ """Initialize a PipettingHandler instance."""
394
+ self._state_view = state_view
395
+
396
+ def get_state_view(self) -> StateView:
397
+ """Get the stateview associated with this handler."""
398
+ return self._state_view
399
+
400
+ def get_is_ready_to_aspirate(self, pipette_id: str) -> bool:
401
+ """Get whether a pipette is ready to aspirate."""
402
+ return self._state_view.pipettes.get_aspirated_volume(
403
+ pipette_id
404
+ ) is not None and self._state_view.pipettes.get_ready_to_aspirate(pipette_id)
405
+
406
+ async def prepare_for_aspirate(self, pipette_id: str) -> None:
407
+ """Virtually prepare to aspirate (no-op)."""
408
+ self._validate_tip_attached(pipette_id=pipette_id, command_name="aspirate")
409
+
410
+ async def aspirate_in_place(
411
+ self,
412
+ pipette_id: str,
413
+ volume: float,
414
+ flow_rate: float,
415
+ command_note_adder: CommandNoteAdder,
416
+ correction_volume: float = 0.0,
417
+ ) -> float:
418
+ """Virtually aspirate (no-op)."""
419
+ self._validate_tip_attached(pipette_id=pipette_id, command_name="aspirate")
420
+ return _validate_aspirate_volume(
421
+ state_view=self._state_view,
422
+ pipette_id=pipette_id,
423
+ aspirate_volume=volume,
424
+ command_note_adder=command_note_adder,
425
+ )
426
+
427
+ async def dispense_in_place(
428
+ self,
429
+ pipette_id: str,
430
+ volume: float,
431
+ flow_rate: float,
432
+ push_out: Optional[float],
433
+ is_full_dispense: bool,
434
+ correction_volume: float = 0.0,
435
+ ) -> float:
436
+ """Virtually dispense (no-op)."""
437
+ # TODO (tz, 8-23-23): add a check for push_out not larger that the max volume allowed when working on this https://opentrons.atlassian.net/browse/RSS-329
438
+ if push_out and push_out < 0:
439
+ raise InvalidPushOutVolumeError(
440
+ "push out value cannot have a negative value."
441
+ )
442
+ self._validate_tip_attached(pipette_id=pipette_id, command_name="dispense")
443
+ return _validate_dispense_volume(
444
+ state_view=self._state_view, pipette_id=pipette_id, dispense_volume=volume
445
+ )
446
+
447
+ async def blow_out_in_place(
448
+ self,
449
+ pipette_id: str,
450
+ flow_rate: float,
451
+ ) -> None:
452
+ """Virtually blow out (no-op)."""
453
+
454
+ async def liquid_probe_in_place(
455
+ self,
456
+ pipette_id: str,
457
+ labware_id: str,
458
+ well_name: str,
459
+ well_location: WellLocation,
460
+ ) -> LiquidTrackingType:
461
+ """Detect liquid level."""
462
+ return SimulatedProbeResult()
463
+
464
+ def _validate_tip_attached(self, pipette_id: str, command_name: str) -> None:
465
+ """Validate if there is a tip attached."""
466
+ tip_geometry = self._state_view.pipettes.get_attached_tip(pipette_id)
467
+ if not tip_geometry:
468
+ raise TipNotAttachedError(
469
+ f"Cannot perform {command_name} without a tip attached"
470
+ )
471
+
472
+ async def aspirate_while_tracking(
473
+ self,
474
+ pipette_id: str,
475
+ labware_id: str,
476
+ well_name: str,
477
+ volume: float,
478
+ flow_rate: float,
479
+ command_note_adder: CommandNoteAdder,
480
+ ) -> float:
481
+ """Virtually aspirate (no-op)."""
482
+ self._validate_tip_attached(pipette_id=pipette_id, command_name="aspirate")
483
+
484
+ return _validate_aspirate_volume(
485
+ state_view=self._state_view,
486
+ pipette_id=pipette_id,
487
+ aspirate_volume=volume,
488
+ command_note_adder=command_note_adder,
489
+ )
490
+
491
+ async def dispense_while_tracking(
492
+ self,
493
+ pipette_id: str,
494
+ labware_id: str,
495
+ well_name: str,
496
+ volume: float,
497
+ flow_rate: float,
498
+ push_out: Optional[float],
499
+ is_full_dispense: bool = False,
500
+ ) -> float:
501
+ """Virtually dispense (no-op)."""
502
+ # TODO (tz, 8-23-23): add a check for push_out not larger that the max volume allowed when working on this https://opentrons.atlassian.net/browse/RSS-329
503
+ if push_out and push_out < 0:
504
+ raise InvalidPushOutVolumeError(
505
+ "push out value cannot have a negative value."
506
+ )
507
+ self._validate_tip_attached(pipette_id=pipette_id, command_name="dispense")
508
+ return _validate_dispense_volume(
509
+ state_view=self._state_view, pipette_id=pipette_id, dispense_volume=volume
510
+ )
511
+
512
+ async def increase_evo_disp_count(self, pipette_id: str) -> None:
513
+ """Increase evo tip dispense action count."""
514
+ pass
515
+
516
+
517
+ def create_pipetting_handler(
518
+ state_view: StateView, hardware_api: HardwareControlAPI
519
+ ) -> PipettingHandler:
520
+ """Create a pipetting handler."""
521
+ return (
522
+ HardwarePipettingHandler(state_view=state_view, hardware_api=hardware_api)
523
+ if state_view.config.use_virtual_pipettes is False
524
+ else VirtualPipettingHandler(state_view=state_view)
525
+ )
526
+
527
+
528
+ def _validate_aspirate_volume(
529
+ state_view: StateView,
530
+ pipette_id: str,
531
+ aspirate_volume: float,
532
+ command_note_adder: CommandNoteAdder,
533
+ ) -> float:
534
+ """Get whether the given volume is valid to aspirate right now.
535
+
536
+ Return the volume to aspirate, possibly clamped, or raise an
537
+ InvalidAspirateVolumeError.
538
+ """
539
+ working_volume = state_view.pipettes.get_working_volume(pipette_id=pipette_id)
540
+
541
+ current_volume = (
542
+ state_view.pipettes.get_aspirated_volume(pipette_id=pipette_id) or 0
543
+ )
544
+
545
+ # TODO(mm, 2024-01-11): We should probably just use
546
+ # state_view.pipettes.get_available_volume()? Its whole `None` return vs. exception
547
+ # raising thing is confusing me.
548
+ available_volume = working_volume - current_volume
549
+ available_volume_with_tolerance = (
550
+ available_volume + _VOLUME_ROUNDING_ERROR_TOLERANCE
551
+ )
552
+
553
+ if aspirate_volume > available_volume_with_tolerance:
554
+ raise InvalidAspirateVolumeError(
555
+ attempted_aspirate_volume=aspirate_volume,
556
+ available_volume=available_volume,
557
+ max_pipette_volume=state_view.pipettes.get_maximum_volume(
558
+ pipette_id=pipette_id
559
+ ),
560
+ max_tip_volume=_get_max_tip_volume(
561
+ state_view=state_view, pipette_id=pipette_id
562
+ ),
563
+ )
564
+ else:
565
+ volume_to_aspirate = min(aspirate_volume, available_volume)
566
+ if volume_to_aspirate < aspirate_volume:
567
+ command_note_adder(
568
+ CommandNote(
569
+ noteKind="warning",
570
+ shortMessage=f"Aspirate clamped to {available_volume} µL",
571
+ longMessage=(
572
+ f"Command requested to aspirate {aspirate_volume} µL but only"
573
+ f" {available_volume} µL were available in the pipette. This is"
574
+ " probably a floating point artifact."
575
+ ),
576
+ source="execution",
577
+ )
578
+ )
579
+ return volume_to_aspirate
580
+
581
+
582
+ def _validate_dispense_volume(
583
+ state_view: StateView, pipette_id: str, dispense_volume: float
584
+ ) -> float:
585
+ """Get whether the given volume is valid to dispense right now.
586
+
587
+ Return the volume to dispense, possibly clamped, or raise an
588
+ InvalidDispenseVolumeError.
589
+ """
590
+ aspirated_volume = state_view.pipettes.get_aspirated_volume(pipette_id)
591
+ if aspirated_volume is None:
592
+ raise InvalidDispenseVolumeError(
593
+ "Cannot perform a dispense if there is no volume in attached tip."
594
+ )
595
+ else:
596
+ remaining = aspirated_volume - dispense_volume
597
+ if remaining < -_VOLUME_ROUNDING_ERROR_TOLERANCE:
598
+ raise InvalidDispenseVolumeError(
599
+ f"Cannot dispense {dispense_volume} µL when only {aspirated_volume} µL has been aspirated."
600
+ )
601
+ else:
602
+ return min(dispense_volume, aspirated_volume)
603
+
604
+
605
+ def _get_max_tip_volume(state_view: StateView, pipette_id: str) -> Optional[float]:
606
+ attached_tip = state_view.pipettes.get_attached_tip(pipette_id=pipette_id)
607
+ return None if attached_tip is None else attached_tip.volume
@@ -0,0 +1,86 @@
1
+ """Command queue execution worker module."""
2
+ import asyncio
3
+ from logging import getLogger
4
+ from typing import Optional, AsyncGenerator, Callable
5
+
6
+ from ..state.state import StateStore
7
+ from .command_executor import CommandExecutor
8
+
9
+ log = getLogger(__name__)
10
+
11
+
12
+ class QueueWorker:
13
+ """Handle and track execution of commands queued in ProtocolEngine state."""
14
+
15
+ def __init__(
16
+ self,
17
+ state_store: StateStore,
18
+ command_executor: CommandExecutor,
19
+ command_generator: Callable[[], AsyncGenerator[str, None]],
20
+ ) -> None:
21
+ """Initialize the queue worker's dependencies and state.
22
+
23
+ Arguments:
24
+ state_store: The source of truth for protocol state, including
25
+ all queued commands.
26
+ command_executor: Interface used to execute and update commands.
27
+ command_generator: Command generator to get the next command to execute.
28
+ """
29
+ self._state_store: StateStore = state_store
30
+ self._command_executor: CommandExecutor = command_executor
31
+ self._command_generator = command_generator
32
+ self._worker_task: Optional["asyncio.Task[None]"] = None
33
+
34
+ def start(self) -> None:
35
+ """Start processing jobs.
36
+
37
+ This method will no-op if the worker is already running.
38
+ """
39
+ if self._worker_task is None:
40
+ self._worker_task = asyncio.create_task(self._run_commands())
41
+
42
+ def cancel(self) -> None:
43
+ """Cancel any in-progress commands.
44
+
45
+ This method is synchronous to allow synchronous callers to
46
+ cancel the ongoing background task in situations where it
47
+ needs to happen immediately.
48
+
49
+ You should call `join` after calling `cancel` to clean up and
50
+ propagate errors.
51
+ """
52
+ if self._worker_task:
53
+ self._worker_task.cancel()
54
+
55
+ async def join(self) -> None:
56
+ """Wait for the worker to finish, propagating any errors."""
57
+ worker_task = self._worker_task
58
+
59
+ if worker_task:
60
+ self._worker_task = None
61
+
62
+ try:
63
+ await worker_task
64
+ except asyncio.CancelledError: # From self.cancel().
65
+ pass
66
+ except Exception as e:
67
+ log.error("Unhandled exception in QueueWorker job", exc_info=e)
68
+ raise e
69
+
70
+ async def _run_commands(self) -> None:
71
+ async for command_id in self._command_generator():
72
+ try:
73
+ await self._command_executor.execute(command_id=command_id)
74
+ except BaseException:
75
+ log.exception(
76
+ # The state can tear if e.g. we've finished updating PipetteStore,
77
+ # but the exception came before we could update LabwareStore. Or
78
+ # the exception could have interrupted updating a single store.
79
+ "Unhandled failure in command executor."
80
+ " This is a bug in opentrons.protocol_engine"
81
+ " and has probably left the ProtocolEngine in a torn state."
82
+ )
83
+ raise
84
+ # Yield to the event loop in case we're executing a long sequence of commands
85
+ # that never yields internally. For example, a long sequence of comment commands.
86
+ await asyncio.sleep(0)