opentrons 8.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of opentrons might be problematic. Click here for more details.

Files changed (601) hide show
  1. opentrons/__init__.py +150 -0
  2. opentrons/_version.py +34 -0
  3. opentrons/calibration_storage/__init__.py +54 -0
  4. opentrons/calibration_storage/deck_configuration.py +62 -0
  5. opentrons/calibration_storage/encoder_decoder.py +31 -0
  6. opentrons/calibration_storage/file_operators.py +142 -0
  7. opentrons/calibration_storage/helpers.py +103 -0
  8. opentrons/calibration_storage/ot2/__init__.py +34 -0
  9. opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
  10. opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
  11. opentrons/calibration_storage/ot2/models/__init__.py +0 -0
  12. opentrons/calibration_storage/ot2/models/v1.py +149 -0
  13. opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
  14. opentrons/calibration_storage/ot2/tip_length.py +281 -0
  15. opentrons/calibration_storage/ot3/__init__.py +31 -0
  16. opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
  17. opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
  18. opentrons/calibration_storage/ot3/models/__init__.py +0 -0
  19. opentrons/calibration_storage/ot3/models/v1.py +122 -0
  20. opentrons/calibration_storage/ot3/module_offset.py +138 -0
  21. opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
  22. opentrons/calibration_storage/types.py +45 -0
  23. opentrons/cli/__init__.py +21 -0
  24. opentrons/cli/__main__.py +5 -0
  25. opentrons/cli/analyze.py +557 -0
  26. opentrons/config/__init__.py +631 -0
  27. opentrons/config/advanced_settings.py +871 -0
  28. opentrons/config/defaults_ot2.py +214 -0
  29. opentrons/config/defaults_ot3.py +499 -0
  30. opentrons/config/feature_flags.py +86 -0
  31. opentrons/config/gripper_config.py +55 -0
  32. opentrons/config/reset.py +203 -0
  33. opentrons/config/robot_configs.py +187 -0
  34. opentrons/config/types.py +183 -0
  35. opentrons/drivers/__init__.py +0 -0
  36. opentrons/drivers/absorbance_reader/__init__.py +11 -0
  37. opentrons/drivers/absorbance_reader/abstract.py +72 -0
  38. opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
  39. opentrons/drivers/absorbance_reader/driver.py +81 -0
  40. opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
  41. opentrons/drivers/absorbance_reader/simulator.py +84 -0
  42. opentrons/drivers/asyncio/__init__.py +0 -0
  43. opentrons/drivers/asyncio/communication/__init__.py +22 -0
  44. opentrons/drivers/asyncio/communication/async_serial.py +187 -0
  45. opentrons/drivers/asyncio/communication/errors.py +88 -0
  46. opentrons/drivers/asyncio/communication/serial_connection.py +557 -0
  47. opentrons/drivers/command_builder.py +102 -0
  48. opentrons/drivers/flex_stacker/__init__.py +13 -0
  49. opentrons/drivers/flex_stacker/abstract.py +214 -0
  50. opentrons/drivers/flex_stacker/driver.py +768 -0
  51. opentrons/drivers/flex_stacker/errors.py +68 -0
  52. opentrons/drivers/flex_stacker/simulator.py +309 -0
  53. opentrons/drivers/flex_stacker/types.py +367 -0
  54. opentrons/drivers/flex_stacker/utils.py +19 -0
  55. opentrons/drivers/heater_shaker/__init__.py +5 -0
  56. opentrons/drivers/heater_shaker/abstract.py +76 -0
  57. opentrons/drivers/heater_shaker/driver.py +204 -0
  58. opentrons/drivers/heater_shaker/simulator.py +94 -0
  59. opentrons/drivers/mag_deck/__init__.py +6 -0
  60. opentrons/drivers/mag_deck/abstract.py +44 -0
  61. opentrons/drivers/mag_deck/driver.py +208 -0
  62. opentrons/drivers/mag_deck/simulator.py +63 -0
  63. opentrons/drivers/rpi_drivers/__init__.py +33 -0
  64. opentrons/drivers/rpi_drivers/dev_types.py +94 -0
  65. opentrons/drivers/rpi_drivers/gpio.py +282 -0
  66. opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
  67. opentrons/drivers/rpi_drivers/interfaces.py +15 -0
  68. opentrons/drivers/rpi_drivers/types.py +364 -0
  69. opentrons/drivers/rpi_drivers/usb.py +102 -0
  70. opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
  71. opentrons/drivers/serial_communication.py +151 -0
  72. opentrons/drivers/smoothie_drivers/__init__.py +4 -0
  73. opentrons/drivers/smoothie_drivers/connection.py +51 -0
  74. opentrons/drivers/smoothie_drivers/constants.py +121 -0
  75. opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
  76. opentrons/drivers/smoothie_drivers/errors.py +49 -0
  77. opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
  78. opentrons/drivers/smoothie_drivers/simulator.py +99 -0
  79. opentrons/drivers/smoothie_drivers/types.py +16 -0
  80. opentrons/drivers/temp_deck/__init__.py +10 -0
  81. opentrons/drivers/temp_deck/abstract.py +54 -0
  82. opentrons/drivers/temp_deck/driver.py +197 -0
  83. opentrons/drivers/temp_deck/simulator.py +57 -0
  84. opentrons/drivers/thermocycler/__init__.py +12 -0
  85. opentrons/drivers/thermocycler/abstract.py +99 -0
  86. opentrons/drivers/thermocycler/driver.py +395 -0
  87. opentrons/drivers/thermocycler/simulator.py +126 -0
  88. opentrons/drivers/types.py +107 -0
  89. opentrons/drivers/utils.py +222 -0
  90. opentrons/execute.py +742 -0
  91. opentrons/hardware_control/__init__.py +65 -0
  92. opentrons/hardware_control/__main__.py +77 -0
  93. opentrons/hardware_control/adapters.py +98 -0
  94. opentrons/hardware_control/api.py +1347 -0
  95. opentrons/hardware_control/backends/__init__.py +7 -0
  96. opentrons/hardware_control/backends/controller.py +400 -0
  97. opentrons/hardware_control/backends/errors.py +9 -0
  98. opentrons/hardware_control/backends/estop_state.py +164 -0
  99. opentrons/hardware_control/backends/flex_protocol.py +497 -0
  100. opentrons/hardware_control/backends/ot3controller.py +1930 -0
  101. opentrons/hardware_control/backends/ot3simulator.py +900 -0
  102. opentrons/hardware_control/backends/ot3utils.py +664 -0
  103. opentrons/hardware_control/backends/simulator.py +442 -0
  104. opentrons/hardware_control/backends/status_bar_state.py +240 -0
  105. opentrons/hardware_control/backends/subsystem_manager.py +431 -0
  106. opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
  107. opentrons/hardware_control/backends/types.py +14 -0
  108. opentrons/hardware_control/constants.py +6 -0
  109. opentrons/hardware_control/dev_types.py +125 -0
  110. opentrons/hardware_control/emulation/__init__.py +0 -0
  111. opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
  112. opentrons/hardware_control/emulation/app.py +56 -0
  113. opentrons/hardware_control/emulation/connection_handler.py +38 -0
  114. opentrons/hardware_control/emulation/heater_shaker.py +150 -0
  115. opentrons/hardware_control/emulation/magdeck.py +60 -0
  116. opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
  117. opentrons/hardware_control/emulation/module_server/client.py +78 -0
  118. opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
  119. opentrons/hardware_control/emulation/module_server/models.py +31 -0
  120. opentrons/hardware_control/emulation/module_server/server.py +110 -0
  121. opentrons/hardware_control/emulation/parser.py +74 -0
  122. opentrons/hardware_control/emulation/proxy.py +241 -0
  123. opentrons/hardware_control/emulation/run_emulator.py +68 -0
  124. opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
  125. opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
  126. opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
  127. opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
  128. opentrons/hardware_control/emulation/settings.py +119 -0
  129. opentrons/hardware_control/emulation/simulations.py +133 -0
  130. opentrons/hardware_control/emulation/smoothie.py +192 -0
  131. opentrons/hardware_control/emulation/tempdeck.py +69 -0
  132. opentrons/hardware_control/emulation/thermocycler.py +128 -0
  133. opentrons/hardware_control/emulation/types.py +10 -0
  134. opentrons/hardware_control/emulation/util.py +38 -0
  135. opentrons/hardware_control/errors.py +43 -0
  136. opentrons/hardware_control/execution_manager.py +164 -0
  137. opentrons/hardware_control/instruments/__init__.py +5 -0
  138. opentrons/hardware_control/instruments/instrument_abc.py +39 -0
  139. opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
  140. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
  141. opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
  142. opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
  143. opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
  144. opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
  145. opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
  146. opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
  147. opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
  148. opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
  149. opentrons/hardware_control/module_control.py +332 -0
  150. opentrons/hardware_control/modules/__init__.py +69 -0
  151. opentrons/hardware_control/modules/absorbance_reader.py +373 -0
  152. opentrons/hardware_control/modules/errors.py +7 -0
  153. opentrons/hardware_control/modules/flex_stacker.py +948 -0
  154. opentrons/hardware_control/modules/heater_shaker.py +426 -0
  155. opentrons/hardware_control/modules/lid_temp_status.py +35 -0
  156. opentrons/hardware_control/modules/magdeck.py +233 -0
  157. opentrons/hardware_control/modules/mod_abc.py +245 -0
  158. opentrons/hardware_control/modules/module_calibration.py +93 -0
  159. opentrons/hardware_control/modules/plate_temp_status.py +61 -0
  160. opentrons/hardware_control/modules/tempdeck.py +299 -0
  161. opentrons/hardware_control/modules/thermocycler.py +731 -0
  162. opentrons/hardware_control/modules/types.py +417 -0
  163. opentrons/hardware_control/modules/update.py +255 -0
  164. opentrons/hardware_control/modules/utils.py +73 -0
  165. opentrons/hardware_control/motion_utilities.py +318 -0
  166. opentrons/hardware_control/nozzle_manager.py +422 -0
  167. opentrons/hardware_control/ot3_calibration.py +1171 -0
  168. opentrons/hardware_control/ot3api.py +3227 -0
  169. opentrons/hardware_control/pause_manager.py +31 -0
  170. opentrons/hardware_control/poller.py +112 -0
  171. opentrons/hardware_control/protocols/__init__.py +106 -0
  172. opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
  173. opentrons/hardware_control/protocols/calibratable.py +45 -0
  174. opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
  175. opentrons/hardware_control/protocols/configurable.py +48 -0
  176. opentrons/hardware_control/protocols/event_sourcer.py +18 -0
  177. opentrons/hardware_control/protocols/execution_controllable.py +33 -0
  178. opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
  179. opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
  180. opentrons/hardware_control/protocols/gripper_controller.py +55 -0
  181. opentrons/hardware_control/protocols/hardware_manager.py +51 -0
  182. opentrons/hardware_control/protocols/identifiable.py +16 -0
  183. opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
  184. opentrons/hardware_control/protocols/liquid_handler.py +266 -0
  185. opentrons/hardware_control/protocols/module_provider.py +16 -0
  186. opentrons/hardware_control/protocols/motion_controller.py +243 -0
  187. opentrons/hardware_control/protocols/position_estimator.py +45 -0
  188. opentrons/hardware_control/protocols/simulatable.py +10 -0
  189. opentrons/hardware_control/protocols/stoppable.py +9 -0
  190. opentrons/hardware_control/protocols/types.py +27 -0
  191. opentrons/hardware_control/robot_calibration.py +224 -0
  192. opentrons/hardware_control/scripts/README.md +28 -0
  193. opentrons/hardware_control/scripts/__init__.py +1 -0
  194. opentrons/hardware_control/scripts/gripper_control.py +208 -0
  195. opentrons/hardware_control/scripts/ot3gripper +7 -0
  196. opentrons/hardware_control/scripts/ot3repl +7 -0
  197. opentrons/hardware_control/scripts/repl.py +187 -0
  198. opentrons/hardware_control/scripts/tc_control.py +97 -0
  199. opentrons/hardware_control/scripts/update_module_fw.py +274 -0
  200. opentrons/hardware_control/simulator_setup.py +260 -0
  201. opentrons/hardware_control/thread_manager.py +431 -0
  202. opentrons/hardware_control/threaded_async_lock.py +97 -0
  203. opentrons/hardware_control/types.py +792 -0
  204. opentrons/hardware_control/util.py +234 -0
  205. opentrons/legacy_broker.py +53 -0
  206. opentrons/legacy_commands/__init__.py +1 -0
  207. opentrons/legacy_commands/commands.py +483 -0
  208. opentrons/legacy_commands/helpers.py +153 -0
  209. opentrons/legacy_commands/module_commands.py +276 -0
  210. opentrons/legacy_commands/protocol_commands.py +54 -0
  211. opentrons/legacy_commands/publisher.py +155 -0
  212. opentrons/legacy_commands/robot_commands.py +51 -0
  213. opentrons/legacy_commands/types.py +1186 -0
  214. opentrons/motion_planning/__init__.py +32 -0
  215. opentrons/motion_planning/adjacent_slots_getters.py +168 -0
  216. opentrons/motion_planning/deck_conflict.py +501 -0
  217. opentrons/motion_planning/errors.py +35 -0
  218. opentrons/motion_planning/types.py +42 -0
  219. opentrons/motion_planning/waypoints.py +218 -0
  220. opentrons/ordered_set.py +138 -0
  221. opentrons/protocol_api/__init__.py +105 -0
  222. opentrons/protocol_api/_liquid.py +157 -0
  223. opentrons/protocol_api/_liquid_properties.py +814 -0
  224. opentrons/protocol_api/_nozzle_layout.py +31 -0
  225. opentrons/protocol_api/_parameter_context.py +300 -0
  226. opentrons/protocol_api/_parameters.py +31 -0
  227. opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
  228. opentrons/protocol_api/_types.py +43 -0
  229. opentrons/protocol_api/config.py +23 -0
  230. opentrons/protocol_api/core/__init__.py +23 -0
  231. opentrons/protocol_api/core/common.py +33 -0
  232. opentrons/protocol_api/core/core_map.py +74 -0
  233. opentrons/protocol_api/core/engine/__init__.py +22 -0
  234. opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
  235. opentrons/protocol_api/core/engine/deck_conflict.py +400 -0
  236. opentrons/protocol_api/core/engine/exceptions.py +19 -0
  237. opentrons/protocol_api/core/engine/instrument.py +2391 -0
  238. opentrons/protocol_api/core/engine/labware.py +238 -0
  239. opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
  240. opentrons/protocol_api/core/engine/module_core.py +1027 -0
  241. opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
  242. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
  243. opentrons/protocol_api/core/engine/point_calculations.py +64 -0
  244. opentrons/protocol_api/core/engine/protocol.py +1153 -0
  245. opentrons/protocol_api/core/engine/robot.py +139 -0
  246. opentrons/protocol_api/core/engine/stringify.py +74 -0
  247. opentrons/protocol_api/core/engine/transfer_components_executor.py +1006 -0
  248. opentrons/protocol_api/core/engine/well.py +241 -0
  249. opentrons/protocol_api/core/instrument.py +459 -0
  250. opentrons/protocol_api/core/labware.py +151 -0
  251. opentrons/protocol_api/core/legacy/__init__.py +11 -0
  252. opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
  253. opentrons/protocol_api/core/legacy/deck.py +369 -0
  254. opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
  255. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
  256. opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
  257. opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
  258. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
  259. opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
  260. opentrons/protocol_api/core/legacy/load_info.py +67 -0
  261. opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
  262. opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
  263. opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
  264. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
  265. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
  266. opentrons/protocol_api/core/module.py +484 -0
  267. opentrons/protocol_api/core/protocol.py +311 -0
  268. opentrons/protocol_api/core/robot.py +51 -0
  269. opentrons/protocol_api/core/well.py +116 -0
  270. opentrons/protocol_api/core/well_grid.py +45 -0
  271. opentrons/protocol_api/create_protocol_context.py +177 -0
  272. opentrons/protocol_api/deck.py +223 -0
  273. opentrons/protocol_api/disposal_locations.py +244 -0
  274. opentrons/protocol_api/instrument_context.py +3272 -0
  275. opentrons/protocol_api/labware.py +1579 -0
  276. opentrons/protocol_api/module_contexts.py +1447 -0
  277. opentrons/protocol_api/module_validation_and_errors.py +61 -0
  278. opentrons/protocol_api/protocol_context.py +1688 -0
  279. opentrons/protocol_api/robot_context.py +303 -0
  280. opentrons/protocol_api/validation.py +761 -0
  281. opentrons/protocol_engine/__init__.py +155 -0
  282. opentrons/protocol_engine/actions/__init__.py +65 -0
  283. opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
  284. opentrons/protocol_engine/actions/action_handler.py +13 -0
  285. opentrons/protocol_engine/actions/actions.py +302 -0
  286. opentrons/protocol_engine/actions/get_state_update.py +38 -0
  287. opentrons/protocol_engine/clients/__init__.py +5 -0
  288. opentrons/protocol_engine/clients/sync_client.py +174 -0
  289. opentrons/protocol_engine/clients/transports.py +197 -0
  290. opentrons/protocol_engine/commands/__init__.py +757 -0
  291. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
  292. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
  293. opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
  294. opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
  295. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
  296. opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
  297. opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
  298. opentrons/protocol_engine/commands/aspirate.py +244 -0
  299. opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
  300. opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
  301. opentrons/protocol_engine/commands/blow_out.py +146 -0
  302. opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
  303. opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
  304. opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
  305. opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
  306. opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
  307. opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
  308. opentrons/protocol_engine/commands/command.py +308 -0
  309. opentrons/protocol_engine/commands/command_unions.py +974 -0
  310. opentrons/protocol_engine/commands/comment.py +57 -0
  311. opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
  312. opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
  313. opentrons/protocol_engine/commands/custom.py +67 -0
  314. opentrons/protocol_engine/commands/dispense.py +194 -0
  315. opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
  316. opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
  317. opentrons/protocol_engine/commands/drop_tip.py +232 -0
  318. opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
  319. opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
  320. opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
  321. opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
  322. opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
  323. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
  324. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
  325. opentrons/protocol_engine/commands/flex_stacker/store.py +339 -0
  326. opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
  327. opentrons/protocol_engine/commands/get_next_tip.py +134 -0
  328. opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
  329. opentrons/protocol_engine/commands/hash_command_params.py +38 -0
  330. opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
  331. opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
  332. opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
  333. opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
  334. opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
  335. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
  336. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
  337. opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
  338. opentrons/protocol_engine/commands/home.py +100 -0
  339. opentrons/protocol_engine/commands/identify_module.py +86 -0
  340. opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
  341. opentrons/protocol_engine/commands/liquid_probe.py +464 -0
  342. opentrons/protocol_engine/commands/load_labware.py +210 -0
  343. opentrons/protocol_engine/commands/load_lid.py +154 -0
  344. opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
  345. opentrons/protocol_engine/commands/load_liquid.py +95 -0
  346. opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
  347. opentrons/protocol_engine/commands/load_module.py +223 -0
  348. opentrons/protocol_engine/commands/load_pipette.py +167 -0
  349. opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
  350. opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
  351. opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
  352. opentrons/protocol_engine/commands/move_labware.py +546 -0
  353. opentrons/protocol_engine/commands/move_relative.py +102 -0
  354. opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
  355. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
  356. opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
  357. opentrons/protocol_engine/commands/move_to_well.py +119 -0
  358. opentrons/protocol_engine/commands/movement_common.py +338 -0
  359. opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
  360. opentrons/protocol_engine/commands/pipetting_common.py +443 -0
  361. opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
  362. opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
  363. opentrons/protocol_engine/commands/reload_labware.py +90 -0
  364. opentrons/protocol_engine/commands/retract_axis.py +75 -0
  365. opentrons/protocol_engine/commands/robot/__init__.py +70 -0
  366. opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -0
  367. opentrons/protocol_engine/commands/robot/common.py +18 -0
  368. opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
  369. opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
  370. opentrons/protocol_engine/commands/robot/move_to.py +94 -0
  371. opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +86 -0
  372. opentrons/protocol_engine/commands/save_position.py +109 -0
  373. opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
  374. opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
  375. opentrons/protocol_engine/commands/set_status_bar.py +89 -0
  376. opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
  377. opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
  378. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
  379. opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
  380. opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
  381. opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
  382. opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
  383. opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
  384. opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
  385. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
  386. opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
  387. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
  388. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
  389. opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
  390. opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
  391. opentrons/protocol_engine/commands/touch_tip.py +189 -0
  392. opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
  393. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
  394. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
  395. opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
  396. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
  397. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
  398. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
  399. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
  400. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
  401. opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
  402. opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
  403. opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
  404. opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
  405. opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
  406. opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
  407. opentrons/protocol_engine/create_protocol_engine.py +193 -0
  408. opentrons/protocol_engine/engine_support.py +28 -0
  409. opentrons/protocol_engine/error_recovery_policy.py +81 -0
  410. opentrons/protocol_engine/errors/__init__.py +191 -0
  411. opentrons/protocol_engine/errors/error_occurrence.py +182 -0
  412. opentrons/protocol_engine/errors/exceptions.py +1308 -0
  413. opentrons/protocol_engine/execution/__init__.py +50 -0
  414. opentrons/protocol_engine/execution/command_executor.py +216 -0
  415. opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
  416. opentrons/protocol_engine/execution/door_watcher.py +119 -0
  417. opentrons/protocol_engine/execution/equipment.py +819 -0
  418. opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
  419. opentrons/protocol_engine/execution/gantry_mover.py +686 -0
  420. opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
  421. opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
  422. opentrons/protocol_engine/execution/labware_movement.py +297 -0
  423. opentrons/protocol_engine/execution/movement.py +350 -0
  424. opentrons/protocol_engine/execution/pipetting.py +607 -0
  425. opentrons/protocol_engine/execution/queue_worker.py +86 -0
  426. opentrons/protocol_engine/execution/rail_lights.py +25 -0
  427. opentrons/protocol_engine/execution/run_control.py +33 -0
  428. opentrons/protocol_engine/execution/status_bar.py +34 -0
  429. opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
  430. opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
  431. opentrons/protocol_engine/execution/tip_handler.py +550 -0
  432. opentrons/protocol_engine/labware_offset_standardization.py +194 -0
  433. opentrons/protocol_engine/notes/__init__.py +17 -0
  434. opentrons/protocol_engine/notes/notes.py +59 -0
  435. opentrons/protocol_engine/plugins.py +104 -0
  436. opentrons/protocol_engine/protocol_engine.py +683 -0
  437. opentrons/protocol_engine/resources/__init__.py +26 -0
  438. opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
  439. opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
  440. opentrons/protocol_engine/resources/file_provider.py +161 -0
  441. opentrons/protocol_engine/resources/fixture_validation.py +68 -0
  442. opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
  443. opentrons/protocol_engine/resources/labware_validation.py +73 -0
  444. opentrons/protocol_engine/resources/model_utils.py +32 -0
  445. opentrons/protocol_engine/resources/module_data_provider.py +44 -0
  446. opentrons/protocol_engine/resources/ot3_validation.py +21 -0
  447. opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
  448. opentrons/protocol_engine/slot_standardization.py +128 -0
  449. opentrons/protocol_engine/state/__init__.py +1 -0
  450. opentrons/protocol_engine/state/_abstract_store.py +27 -0
  451. opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
  452. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  453. opentrons/protocol_engine/state/_move_types.py +83 -0
  454. opentrons/protocol_engine/state/_well_math.py +193 -0
  455. opentrons/protocol_engine/state/addressable_areas.py +699 -0
  456. opentrons/protocol_engine/state/command_history.py +309 -0
  457. opentrons/protocol_engine/state/commands.py +1164 -0
  458. opentrons/protocol_engine/state/config.py +39 -0
  459. opentrons/protocol_engine/state/files.py +57 -0
  460. opentrons/protocol_engine/state/fluid_stack.py +138 -0
  461. opentrons/protocol_engine/state/geometry.py +2408 -0
  462. opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
  463. opentrons/protocol_engine/state/labware.py +1432 -0
  464. opentrons/protocol_engine/state/liquid_classes.py +82 -0
  465. opentrons/protocol_engine/state/liquids.py +73 -0
  466. opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
  467. opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
  468. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
  469. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
  470. opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
  471. opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
  472. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
  473. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
  474. opentrons/protocol_engine/state/modules.py +1515 -0
  475. opentrons/protocol_engine/state/motion.py +373 -0
  476. opentrons/protocol_engine/state/pipettes.py +905 -0
  477. opentrons/protocol_engine/state/state.py +421 -0
  478. opentrons/protocol_engine/state/state_summary.py +36 -0
  479. opentrons/protocol_engine/state/tips.py +420 -0
  480. opentrons/protocol_engine/state/update_types.py +904 -0
  481. opentrons/protocol_engine/state/wells.py +290 -0
  482. opentrons/protocol_engine/types/__init__.py +310 -0
  483. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  484. opentrons/protocol_engine/types/command_annotations.py +53 -0
  485. opentrons/protocol_engine/types/deck_configuration.py +81 -0
  486. opentrons/protocol_engine/types/execution.py +96 -0
  487. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  488. opentrons/protocol_engine/types/instrument.py +47 -0
  489. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  490. opentrons/protocol_engine/types/labware.py +131 -0
  491. opentrons/protocol_engine/types/labware_movement.py +22 -0
  492. opentrons/protocol_engine/types/labware_offset_location.py +111 -0
  493. opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
  494. opentrons/protocol_engine/types/liquid.py +40 -0
  495. opentrons/protocol_engine/types/liquid_class.py +59 -0
  496. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  497. opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
  498. opentrons/protocol_engine/types/location.py +194 -0
  499. opentrons/protocol_engine/types/module.py +310 -0
  500. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  501. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  502. opentrons/protocol_engine/types/tip.py +18 -0
  503. opentrons/protocol_engine/types/util.py +21 -0
  504. opentrons/protocol_engine/types/well_position.py +124 -0
  505. opentrons/protocol_reader/__init__.py +37 -0
  506. opentrons/protocol_reader/extract_labware_definitions.py +66 -0
  507. opentrons/protocol_reader/file_format_validator.py +152 -0
  508. opentrons/protocol_reader/file_hasher.py +27 -0
  509. opentrons/protocol_reader/file_identifier.py +284 -0
  510. opentrons/protocol_reader/file_reader_writer.py +90 -0
  511. opentrons/protocol_reader/input_file.py +16 -0
  512. opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
  513. opentrons/protocol_reader/protocol_reader.py +188 -0
  514. opentrons/protocol_reader/protocol_source.py +124 -0
  515. opentrons/protocol_reader/role_analyzer.py +86 -0
  516. opentrons/protocol_runner/__init__.py +26 -0
  517. opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
  518. opentrons/protocol_runner/json_file_reader.py +55 -0
  519. opentrons/protocol_runner/json_translator.py +314 -0
  520. opentrons/protocol_runner/legacy_command_mapper.py +852 -0
  521. opentrons/protocol_runner/legacy_context_plugin.py +116 -0
  522. opentrons/protocol_runner/protocol_runner.py +530 -0
  523. opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
  524. opentrons/protocol_runner/run_orchestrator.py +496 -0
  525. opentrons/protocol_runner/task_queue.py +95 -0
  526. opentrons/protocols/__init__.py +6 -0
  527. opentrons/protocols/advanced_control/__init__.py +0 -0
  528. opentrons/protocols/advanced_control/common.py +38 -0
  529. opentrons/protocols/advanced_control/mix.py +60 -0
  530. opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
  531. opentrons/protocols/advanced_control/transfers/common.py +180 -0
  532. opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
  533. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
  534. opentrons/protocols/api_support/__init__.py +0 -0
  535. opentrons/protocols/api_support/constants.py +8 -0
  536. opentrons/protocols/api_support/deck_type.py +110 -0
  537. opentrons/protocols/api_support/definitions.py +18 -0
  538. opentrons/protocols/api_support/instrument.py +151 -0
  539. opentrons/protocols/api_support/labware_like.py +233 -0
  540. opentrons/protocols/api_support/tip_tracker.py +175 -0
  541. opentrons/protocols/api_support/types.py +32 -0
  542. opentrons/protocols/api_support/util.py +403 -0
  543. opentrons/protocols/bundle.py +89 -0
  544. opentrons/protocols/duration/__init__.py +4 -0
  545. opentrons/protocols/duration/errors.py +5 -0
  546. opentrons/protocols/duration/estimator.py +628 -0
  547. opentrons/protocols/execution/__init__.py +0 -0
  548. opentrons/protocols/execution/dev_types.py +181 -0
  549. opentrons/protocols/execution/errors.py +40 -0
  550. opentrons/protocols/execution/execute.py +84 -0
  551. opentrons/protocols/execution/execute_json_v3.py +275 -0
  552. opentrons/protocols/execution/execute_json_v4.py +359 -0
  553. opentrons/protocols/execution/execute_json_v5.py +28 -0
  554. opentrons/protocols/execution/execute_python.py +169 -0
  555. opentrons/protocols/execution/json_dispatchers.py +87 -0
  556. opentrons/protocols/execution/types.py +7 -0
  557. opentrons/protocols/geometry/__init__.py +0 -0
  558. opentrons/protocols/geometry/planning.py +297 -0
  559. opentrons/protocols/labware.py +312 -0
  560. opentrons/protocols/models/__init__.py +0 -0
  561. opentrons/protocols/models/json_protocol.py +679 -0
  562. opentrons/protocols/parameters/__init__.py +0 -0
  563. opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
  564. opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
  565. opentrons/protocols/parameters/exceptions.py +34 -0
  566. opentrons/protocols/parameters/parameter_definition.py +272 -0
  567. opentrons/protocols/parameters/types.py +17 -0
  568. opentrons/protocols/parameters/validation.py +267 -0
  569. opentrons/protocols/parse.py +671 -0
  570. opentrons/protocols/types.py +159 -0
  571. opentrons/py.typed +0 -0
  572. opentrons/resources/scripts/lpc21isp +0 -0
  573. opentrons/resources/smoothie-edge-8414642.hex +23010 -0
  574. opentrons/simulate.py +1065 -0
  575. opentrons/system/__init__.py +6 -0
  576. opentrons/system/camera.py +51 -0
  577. opentrons/system/log_control.py +59 -0
  578. opentrons/system/nmcli.py +856 -0
  579. opentrons/system/resin.py +24 -0
  580. opentrons/system/smoothie_update.py +15 -0
  581. opentrons/system/wifi.py +204 -0
  582. opentrons/tools/__init__.py +0 -0
  583. opentrons/tools/args_handler.py +22 -0
  584. opentrons/tools/write_pipette_memory.py +157 -0
  585. opentrons/types.py +618 -0
  586. opentrons/util/__init__.py +1 -0
  587. opentrons/util/async_helpers.py +166 -0
  588. opentrons/util/broker.py +84 -0
  589. opentrons/util/change_notifier.py +47 -0
  590. opentrons/util/entrypoint_util.py +278 -0
  591. opentrons/util/get_union_elements.py +26 -0
  592. opentrons/util/helpers.py +6 -0
  593. opentrons/util/linal.py +178 -0
  594. opentrons/util/logging_config.py +265 -0
  595. opentrons/util/logging_queue_handler.py +61 -0
  596. opentrons/util/performance_helpers.py +157 -0
  597. opentrons-8.6.0.dist-info/METADATA +37 -0
  598. opentrons-8.6.0.dist-info/RECORD +601 -0
  599. opentrons-8.6.0.dist-info/WHEEL +4 -0
  600. opentrons-8.6.0.dist-info/entry_points.txt +3 -0
  601. opentrons-8.6.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,858 @@
1
+ import logging
2
+ import functools
3
+
4
+ from typing import Any, Dict, Optional, Set, Tuple, Union, cast
5
+
6
+ from opentrons.types import Point
7
+
8
+ from opentrons_shared_data.pipette.pipette_definition import (
9
+ PipetteConfigurations,
10
+ PlungerPositions,
11
+ MotorConfigurations,
12
+ SupportedTipsDefinition,
13
+ PickUpTipConfigurations,
14
+ PressFitPickUpTipConfiguration,
15
+ CamActionPickUpTipConfiguration,
16
+ DropTipConfigurations,
17
+ PlungerHomingConfigurations,
18
+ PipetteNameType,
19
+ PipetteModelVersionType,
20
+ PipetteLiquidPropertiesDefinition,
21
+ default_tip_for_liquid_class,
22
+ )
23
+ from opentrons_shared_data.errors.exceptions import (
24
+ InvalidLiquidClassName,
25
+ CommandPreconditionViolated,
26
+ PythonException,
27
+ InvalidInstrumentData,
28
+ )
29
+ from opentrons_shared_data.pipette.ul_per_mm import (
30
+ calculate_ul_per_mm,
31
+ PIPETTING_FUNCTION_FALLBACK_VERSION,
32
+ PIPETTING_FUNCTION_LATEST_VERSION,
33
+ )
34
+ from ..instrument_abc import AbstractInstrument
35
+ from .instrument_calibration import (
36
+ save_pipette_offset_calibration,
37
+ load_pipette_offset,
38
+ PipetteOffsetByPipetteMount,
39
+ )
40
+ from opentrons_shared_data.pipette.types import (
41
+ UlPerMmAction,
42
+ PipetteName,
43
+ PipetteModel,
44
+ Quirks,
45
+ PipetteOEMType,
46
+ )
47
+ from opentrons_shared_data.pipette import (
48
+ load_data as load_pipette_data,
49
+ types as pip_types,
50
+ )
51
+ from opentrons.hardware_control.types import CriticalPoint, OT3Mount
52
+ from opentrons.hardware_control.errors import InvalidCriticalPoint
53
+ from opentrons.hardware_control import nozzle_manager
54
+
55
+ from opentrons.hardware_control.util import (
56
+ pick_up_speed_by_configuration,
57
+ pick_up_distance_by_configuration,
58
+ pick_up_current_by_configuration,
59
+ nominal_tip_overlap_dictionary_by_configuration,
60
+ )
61
+
62
+ mod_log = logging.getLogger(__name__)
63
+
64
+
65
+ class Pipette(AbstractInstrument[PipetteConfigurations]):
66
+ """A class to gather and track pipette state and configs.
67
+
68
+ This class should not touch hardware or call back out to the hardware
69
+ control API. Its only purpose is to gather state.
70
+ """
71
+
72
+ DictType = Dict[str, Union[str, float, bool]]
73
+ #: The type of this data class as a dict
74
+
75
+ def __init__(
76
+ self,
77
+ config: PipetteConfigurations,
78
+ pipette_offset_cal: PipetteOffsetByPipetteMount,
79
+ pipette_id: Optional[str] = None,
80
+ use_old_aspiration_functions: bool = False,
81
+ ) -> None:
82
+ self._config = config
83
+ self._config_as_dict = config.model_dump()
84
+ self._plunger_motor_current = config.plunger_motor_configurations
85
+ self._pick_up_configurations = config.pick_up_tip_configurations
86
+ self._plunger_homing_configurations = config.plunger_homing_configurations
87
+ self._drop_configurations = config.drop_tip_configurations
88
+ self._pipette_offset = pipette_offset_cal
89
+ self._pipette_type = self._config.pipette_type
90
+ self._pipette_version = self._config.version
91
+ self._max_channels = self._config.channels
92
+ self._backlash_distance = config.backlash_distance
93
+
94
+ self._liquid_class_name = pip_types.LiquidClasses.default
95
+ self._liquid_class = self._config.liquid_properties[self._liquid_class_name]
96
+
97
+ oem = PipetteOEMType.get_oem_from_quirks(config.quirks)
98
+ # TODO (lc 12-05-2022) figure out how we can safely deprecate "name" and "model"
99
+ self._pipette_name = PipetteNameType(
100
+ pipette_type=config.pipette_type,
101
+ pipette_channels=config.channels,
102
+ pipette_generation=config.display_category,
103
+ oem_type=oem,
104
+ )
105
+ self._acting_as = self._pipette_name
106
+ self._pipette_model = PipetteModelVersionType(
107
+ pipette_type=config.pipette_type,
108
+ pipette_channels=config.channels,
109
+ pipette_version=config.version,
110
+ oem_type=oem,
111
+ )
112
+ self._valid_nozzle_maps = load_pipette_data.load_valid_nozzle_maps(
113
+ self._pipette_model.pipette_type,
114
+ self._pipette_model.pipette_channels,
115
+ self._pipette_model.pipette_version,
116
+ self._pipette_model.oem_type,
117
+ )
118
+ self._nozzle_offset = self._config.nozzle_offset
119
+ self._nozzle_manager = (
120
+ nozzle_manager.NozzleConfigurationManager.build_from_config(
121
+ self._config, self._valid_nozzle_maps
122
+ )
123
+ )
124
+ self._current_volume = 0.0
125
+ self._working_volume = float(self._liquid_class.max_volume)
126
+ self._current_tip_length = 0.0
127
+ self._has_tip_length: Optional[bool] = None
128
+ self._current_tiprack_diameter = 0.0
129
+ self._pipette_id = pipette_id
130
+ self._log = mod_log.getChild(
131
+ self._pipette_id if self._pipette_id else "<unknown>"
132
+ )
133
+ self._log.info(
134
+ "loaded: {}, pipette offset: {}".format(
135
+ self._pipette_model, self._pipette_offset.offset
136
+ )
137
+ )
138
+ self.ready_to_aspirate = False
139
+
140
+ self._active_tip_setting_name = default_tip_for_liquid_class(self._liquid_class)
141
+ self._active_tip_settings = self._liquid_class.supported_tips[
142
+ self._active_tip_setting_name
143
+ ]
144
+ self._fallback_tip_length = self._active_tip_settings.default_tip_length
145
+
146
+ self._aspirate_flow_rate = (
147
+ self._active_tip_settings.default_aspirate_flowrate.default
148
+ )
149
+ self._dispense_flow_rate = (
150
+ self._active_tip_settings.default_dispense_flowrate.default
151
+ )
152
+ self._blow_out_flow_rate = (
153
+ self._active_tip_settings.default_blowout_flowrate.default
154
+ )
155
+ self._flow_acceleration = self._active_tip_settings.default_flow_acceleration
156
+
157
+ self._versioned_tip_overlap_dictionary = (
158
+ self.get_nominal_tip_overlap_dictionary_by_configuration()
159
+ )
160
+
161
+ if use_old_aspiration_functions:
162
+ self._pipetting_function_version = PIPETTING_FUNCTION_FALLBACK_VERSION
163
+ else:
164
+ self._pipetting_function_version = PIPETTING_FUNCTION_LATEST_VERSION
165
+
166
+ @property
167
+ def config(self) -> PipetteConfigurations:
168
+ return self._config
169
+
170
+ @property
171
+ def liquid_class(self) -> PipetteLiquidPropertiesDefinition:
172
+ return self._liquid_class
173
+
174
+ @property
175
+ def liquid_class_name(self) -> pip_types.LiquidClasses:
176
+ return self._liquid_class_name
177
+
178
+ @property
179
+ def channels(self) -> pip_types.PipetteChannelType:
180
+ return self._max_channels
181
+
182
+ @property
183
+ def backlash_distance(self) -> float:
184
+ return self._backlash_distance
185
+
186
+ @property
187
+ def tip_overlap(self) -> Dict[str, Dict[str, float]]:
188
+ return self._versioned_tip_overlap_dictionary
189
+
190
+ @property
191
+ def nozzle_offset(self) -> Point:
192
+ return self._nozzle_manager.starting_nozzle_offset
193
+
194
+ @property
195
+ def nozzle_manager(self) -> nozzle_manager.NozzleConfigurationManager:
196
+ return self._nozzle_manager
197
+
198
+ @property
199
+ def pipette_offset(self) -> PipetteOffsetByPipetteMount:
200
+ return self._pipette_offset
201
+
202
+ @property
203
+ def plunger_positions(self) -> PlungerPositions:
204
+ return self._config.plunger_positions_configurations[self._liquid_class_name]
205
+
206
+ @property
207
+ def plunger_motor_current(self) -> MotorConfigurations:
208
+ return self._plunger_motor_current
209
+
210
+ @property
211
+ def pick_up_configurations(self) -> PickUpTipConfigurations:
212
+ return self._pick_up_configurations
213
+
214
+ @pick_up_configurations.setter
215
+ def pick_up_configurations(self, pick_up_configs: PickUpTipConfigurations) -> None:
216
+ self._pick_up_configurations = pick_up_configs
217
+
218
+ @property
219
+ def plunger_homing_configurations(self) -> PlungerHomingConfigurations:
220
+ return self._plunger_homing_configurations
221
+
222
+ @property
223
+ def drop_configurations(self) -> DropTipConfigurations:
224
+ return self._drop_configurations
225
+
226
+ @property
227
+ def active_tip_settings(self) -> SupportedTipsDefinition:
228
+ return self._active_tip_settings
229
+
230
+ @property
231
+ def push_out_volume(self) -> float:
232
+ return self._active_tip_settings.default_push_out_volume
233
+
234
+ def is_high_speed_pipette(self) -> bool:
235
+ return Quirks.highSpeed in self._config.quirks
236
+
237
+ def act_as(self, name: PipetteName) -> None:
238
+ """Reconfigure to act as ``name``. ``name`` must be either the
239
+ actual name of the pipette, or a name in its back-compatibility
240
+ config.
241
+ """
242
+ raise NotImplementedError(
243
+ "Backwards compatibility is not supported at this time."
244
+ )
245
+
246
+ def update_config_item(self, elem_name: Dict[str, Any]) -> None:
247
+ raise NotImplementedError("Update config is not supported at this time.")
248
+
249
+ @property
250
+ def acting_as(self) -> PipetteName:
251
+ return cast(PipetteName, f"{self._acting_as}")
252
+
253
+ def reload_configurations(self) -> None:
254
+ self._config = load_pipette_data.load_definition(
255
+ self._pipette_model.pipette_type,
256
+ self._pipette_model.pipette_channels,
257
+ self._pipette_model.pipette_version,
258
+ self._pipette_model.oem_type,
259
+ )
260
+ self._config_as_dict = self._config.model_dump()
261
+
262
+ def reset_state(self) -> None:
263
+ self._current_volume = 0.0
264
+ self._working_volume = float(self.liquid_class.max_volume)
265
+ self._current_tip_length = 0.0
266
+ self._has_tip_length = None
267
+ self._current_tiprack_diameter = 0.0
268
+ self.ready_to_aspirate = False
269
+ #: True if ready to aspirate
270
+ self.set_liquid_class_by_name("default")
271
+ self.set_tip_type(default_tip_for_liquid_class(self._liquid_class))
272
+
273
+ self._aspirate_flow_rate = (
274
+ self._active_tip_settings.default_aspirate_flowrate.default
275
+ )
276
+ self._dispense_flow_rate = (
277
+ self._active_tip_settings.default_dispense_flowrate.default
278
+ )
279
+ self._blow_out_flow_rate = (
280
+ self._active_tip_settings.default_blowout_flowrate.default
281
+ )
282
+ self._flow_acceleration = self._active_tip_settings.default_flow_acceleration
283
+
284
+ self._versioned_tip_overlap_dictionary = (
285
+ self.get_nominal_tip_overlap_dictionary_by_configuration()
286
+ )
287
+ self._nozzle_manager = (
288
+ nozzle_manager.NozzleConfigurationManager.build_from_config(
289
+ self._config, self._valid_nozzle_maps
290
+ )
291
+ )
292
+
293
+ def reset_pipette_offset(self, mount: OT3Mount, to_default: bool) -> None:
294
+ """Reset the pipette offset to system defaults."""
295
+ if to_default:
296
+ self._pipette_offset = load_pipette_offset(pip_id=None, mount=mount)
297
+ else:
298
+ self._pipette_offset = load_pipette_offset(self._pipette_id, mount)
299
+
300
+ def save_pipette_offset(
301
+ self, mount: OT3Mount, offset: Point
302
+ ) -> PipetteOffsetByPipetteMount:
303
+ """Update the pipette offset to a new value."""
304
+ save_pipette_offset_calibration(self._pipette_id, mount, offset)
305
+ self._pipette_offset = load_pipette_offset(self._pipette_id, mount)
306
+ return self._pipette_offset
307
+
308
+ @property
309
+ def name(self) -> PipetteName:
310
+ return cast(PipetteName, f"{self._pipette_name}")
311
+
312
+ @property
313
+ def model(self) -> PipetteModel:
314
+ return cast(PipetteModel, f"{self._pipette_model}")
315
+
316
+ @property
317
+ def pipette_type(self) -> pip_types.PipetteModelType:
318
+ return self._pipette_type
319
+
320
+ @property
321
+ def pipette_id(self) -> Optional[str]:
322
+ return self._pipette_id
323
+
324
+ def critical_point(self, cp_override: Optional[CriticalPoint] = None) -> Point:
325
+ """
326
+ The vector from the pipette's origin to its critical point. The
327
+ critical point for a pipette is the end of the nozzle if no tip is
328
+ attached, or the end of the tip if a tip is attached.
329
+
330
+ If `cp_override` is specified and valid - so is either
331
+ :py:attr:`CriticalPoint.NOZZLE` or :py:attr:`CriticalPoint.TIP` when
332
+ we have a tip, or :py:attr:`CriticalPoint.XY_CENTER` - the specified
333
+ critical point will be used.
334
+ """
335
+ if cp_override in [
336
+ CriticalPoint.GRIPPER_JAW_CENTER,
337
+ CriticalPoint.GRIPPER_FRONT_CALIBRATION_PIN,
338
+ CriticalPoint.GRIPPER_REAR_CALIBRATION_PIN,
339
+ ]:
340
+ raise InvalidCriticalPoint(cp_override.name, "pipette")
341
+
342
+ instr = Point(*self._pipette_offset.offset)
343
+ cp_with_tip_length = self._nozzle_manager.critical_point_with_tip_length(
344
+ cp_override,
345
+ self.current_tip_length if cp_override != CriticalPoint.NOZZLE else 0.0,
346
+ )
347
+ cp = cp_with_tip_length + instr
348
+
349
+ if self._log.isEnabledFor(logging.DEBUG):
350
+ info_str = "cp: {}{}: {} (from: ".format(
351
+ cp_override, " (from override)" if cp_override else "", cp
352
+ )
353
+ info_str += "model offset: {} + instrument offset: {}".format(
354
+ cp_with_tip_length, instr
355
+ )
356
+ info_str += " - tip_length: {}".format(self.current_tip_length)
357
+ info_str += ")"
358
+ self._log.debug(info_str)
359
+
360
+ return cp
361
+
362
+ @property
363
+ def current_volume(self) -> float:
364
+ """The amount of liquid currently aspirated"""
365
+ return self._current_volume
366
+
367
+ @property
368
+ def current_tip_length(self) -> float:
369
+ """The length of the current tip attached (0.0 if no tip)"""
370
+ return self._current_tip_length
371
+
372
+ @current_tip_length.setter
373
+ def current_tip_length(self, tip_length: float) -> None:
374
+ self._current_tip_length = tip_length
375
+ self._has_tip_length = True
376
+
377
+ @property
378
+ def current_tiprack_diameter(self) -> float:
379
+ """The diameter of the current tip rack (0.0 if no tip)"""
380
+ return self._current_tiprack_diameter
381
+
382
+ @current_tiprack_diameter.setter
383
+ def current_tiprack_diameter(self, diameter: float) -> None:
384
+ self._current_tiprack_diameter = diameter
385
+
386
+ @property
387
+ def aspirate_flow_rate(self) -> float:
388
+ """Current active flow rate (not config value)"""
389
+ return self._aspirate_flow_rate
390
+
391
+ @aspirate_flow_rate.setter
392
+ def aspirate_flow_rate(self, new_flow_rate: float) -> None:
393
+ assert new_flow_rate > 0
394
+ self._aspirate_flow_rate = new_flow_rate
395
+
396
+ @property
397
+ def dispense_flow_rate(self) -> float:
398
+ """Current active flow rate (not config value)"""
399
+ return self._dispense_flow_rate
400
+
401
+ @dispense_flow_rate.setter
402
+ def dispense_flow_rate(self, new_flow_rate: float) -> None:
403
+ assert new_flow_rate > 0
404
+ self._dispense_flow_rate = new_flow_rate
405
+
406
+ @property
407
+ def blow_out_flow_rate(self) -> float:
408
+ """Current active flow rate (not config value)"""
409
+ return self._blow_out_flow_rate
410
+
411
+ @blow_out_flow_rate.setter
412
+ def blow_out_flow_rate(self, new_flow_rate: float) -> None:
413
+ assert new_flow_rate > 0
414
+ self._blow_out_flow_rate = new_flow_rate
415
+
416
+ @property
417
+ def flow_acceleration(self) -> float:
418
+ """Current active flow acceleration (not config value)"""
419
+ return self._flow_acceleration
420
+
421
+ @flow_acceleration.setter
422
+ def flow_acceleration(self, new_flow_acceleration: float) -> None:
423
+ assert new_flow_acceleration > 0
424
+ self._flow_acceleration = new_flow_acceleration
425
+
426
+ @property
427
+ def aspirate_flow_rates_lookup(self) -> Dict[str, float]:
428
+ return self._active_tip_settings.default_aspirate_flowrate.values_by_api_level
429
+
430
+ @property
431
+ def dispense_flow_rates_lookup(self) -> Dict[str, float]:
432
+ return self._active_tip_settings.default_dispense_flowrate.values_by_api_level
433
+
434
+ @property
435
+ def blow_out_flow_rates_lookup(self) -> Dict[str, float]:
436
+ return self._active_tip_settings.default_blowout_flowrate.values_by_api_level
437
+
438
+ @property
439
+ def working_volume(self) -> float:
440
+ """The working volume of the pipette"""
441
+ return self._working_volume
442
+
443
+ @working_volume.setter
444
+ def working_volume(self, tip_volume: float) -> None:
445
+ """The working volume is the current tip max volume"""
446
+ self.set_tip_type_by_volume(tip_volume)
447
+ self._working_volume = min(tip_volume, self.liquid_class.max_volume)
448
+
449
+ @property
450
+ def minimum_volume(self) -> float:
451
+ """The smallest controllable volume the pipette can handle in this liquid class."""
452
+ return self.liquid_class.min_volume
453
+
454
+ @property
455
+ def available_volume(self) -> float:
456
+ """The amount of liquid possible to aspirate"""
457
+ return self.working_volume - self.current_volume
458
+
459
+ def set_current_volume(self, new_volume: float) -> None:
460
+ assert new_volume >= 0
461
+ assert new_volume <= self.working_volume
462
+ self._current_volume = new_volume
463
+
464
+ def add_current_volume(self, volume_incr: float) -> None:
465
+ assert self.ok_to_add_volume(volume_incr)
466
+ self._current_volume += volume_incr
467
+
468
+ def remove_current_volume(self, volume_incr: float) -> None:
469
+ assert self._current_volume >= volume_incr
470
+ self._current_volume -= volume_incr
471
+
472
+ def ok_to_add_volume(self, volume_incr: float) -> bool:
473
+ return self.current_volume + volume_incr <= self.working_volume
474
+
475
+ def ok_to_push_out(self, push_out_dist_mm: float) -> bool:
476
+ return push_out_dist_mm <= (
477
+ self.plunger_positions.blow_out - self.plunger_positions.bottom
478
+ )
479
+
480
+ def update_nozzle_configuration(
481
+ self,
482
+ back_left_nozzle: str,
483
+ front_right_nozzle: str,
484
+ starting_nozzle: Optional[str] = None,
485
+ ) -> None:
486
+ """
487
+ Update nozzle configuration manager.
488
+ """
489
+ self._nozzle_manager.update_nozzle_configuration(
490
+ back_left_nozzle, front_right_nozzle, starting_nozzle
491
+ )
492
+
493
+ def reset_nozzle_configuration(self) -> None:
494
+ """
495
+ Reset nozzle configuration manager.
496
+ """
497
+ self._nozzle_manager.reset_to_default_configuration()
498
+
499
+ def add_tip(self, tip_length: float) -> None:
500
+ """
501
+ Add a tip to the pipette for position tracking and validation
502
+ (effectively updates the pipette's critical point)
503
+
504
+ :param tip_length: a positive, non-zero float presenting the distance
505
+ in Z from the end of the pipette nozzle to the end of the tip
506
+ :return:
507
+ """
508
+ assert tip_length > 0.0, "tip_length must be greater than 0"
509
+ assert not self.has_tip_length
510
+ self._current_tip_length = tip_length
511
+ self._has_tip_length = True
512
+
513
+ def remove_tip(self) -> None:
514
+ """
515
+ Remove the tip from the pipette (effectively updates the pipette's
516
+ critical point)
517
+ """
518
+ self._current_tip_length = 0.0
519
+ self._has_tip_length = False
520
+
521
+ @property
522
+ def has_tip(self) -> bool:
523
+ return self.has_tip_length
524
+
525
+ @property
526
+ def has_tip_length(self) -> bool:
527
+ return self.current_tip_length > 0.0
528
+
529
+ @property
530
+ def tip_presence_check_dist_mm(self) -> float:
531
+ return self._config.tip_presence_check_distance_mm
532
+
533
+ @property
534
+ def tip_presence_responses(self) -> int:
535
+ # TODO: put this in shared-data
536
+ return 2 if self.channels > 8 else 1
537
+
538
+ # Cache max is chosen somewhat arbitrarily. With a float is input we don't
539
+ # want this to unbounded.
540
+ @functools.lru_cache(maxsize=100)
541
+ def ul_per_mm(self, ul: float, action: UlPerMmAction) -> float:
542
+ return calculate_ul_per_mm(
543
+ ul,
544
+ action,
545
+ self._active_tip_settings,
546
+ self._pipetting_function_version,
547
+ self._config.shaft_ul_per_mm,
548
+ )
549
+
550
+ def __str__(self) -> str:
551
+ return "{} current volume {}ul critical point: {} at {}".format(
552
+ self._config.display_name,
553
+ self.current_volume,
554
+ "tip end" if self.has_tip_length else "nozzle end",
555
+ 0,
556
+ )
557
+
558
+ def __repr__(self) -> str:
559
+ return "<{}: {} {}>".format(
560
+ self.__class__.__name__, self._config.display_name, id(self)
561
+ )
562
+
563
+ def as_dict(self) -> "Pipette.DictType":
564
+ # TODO (lc 12-05-2022) Kill this code ASAP
565
+ self._config_as_dict.update(
566
+ {
567
+ "current_volume": self.current_volume,
568
+ "available_volume": self.available_volume,
569
+ "name": self.name,
570
+ "model": self.model,
571
+ "pipette_id": self.pipette_id,
572
+ "has_tip": self.has_tip_length,
573
+ "working_volume": self.working_volume,
574
+ "aspirate_flow_rate": self.aspirate_flow_rate,
575
+ "dispense_flow_rate": self.dispense_flow_rate,
576
+ "blow_out_flow_rate": self.blow_out_flow_rate,
577
+ "flow_acceleration": self.flow_acceleration,
578
+ "default_aspirate_flow_rates": self.aspirate_flow_rates_lookup,
579
+ "default_blow_out_flow_rates": self.blow_out_flow_rates_lookup,
580
+ "default_dispense_flow_rates": self.dispense_flow_rates_lookup,
581
+ "default_flow_acceleration": self.active_tip_settings.default_flow_acceleration,
582
+ "tip_length": self.current_tip_length,
583
+ "return_tip_height": self.active_tip_settings.default_return_tip_height,
584
+ "tip_overlap": self.tip_overlap["v0"],
585
+ "versioned_tip_overlap": self.tip_overlap,
586
+ "back_compat_names": self._config.pipette_backcompat_names,
587
+ "supported_tips": self.liquid_class.supported_tips,
588
+ "shaft_ul_per_mm": self._config.shaft_ul_per_mm,
589
+ }
590
+ )
591
+ return self._config_as_dict
592
+
593
+ def set_liquid_class_by_name(self, class_name: str) -> None:
594
+ """Change the currently active liquid class."""
595
+ if self.current_volume > 0:
596
+ raise CommandPreconditionViolated(
597
+ "Cannot switch liquid classes when liquid is in the tip"
598
+ )
599
+ try:
600
+ new_name = pip_types.LiquidClasses[class_name]
601
+ if new_name == self._liquid_class_name:
602
+ return
603
+ new_class = self._config.liquid_properties[new_name]
604
+ except KeyError:
605
+ raise InvalidLiquidClassName(
606
+ message=f"Liquid class {class_name} is not valid for {self._config.display_name}",
607
+ detail={
608
+ "requested-class-name": class_name,
609
+ "pipette-model": str(self._pipette_model),
610
+ },
611
+ )
612
+ if (
613
+ self.has_tip_length
614
+ and self._active_tip_setting_name not in new_class.supported_tips
615
+ ):
616
+ raise CommandPreconditionViolated(
617
+ message=f"Requested liquid class {class_name} does not support the currently attached tip",
618
+ detail={
619
+ "requested-class-name": class_name,
620
+ "current-tip": str(self._active_tip_setting_name),
621
+ },
622
+ )
623
+ self._liquid_class_name = new_name
624
+ self._liquid_class = new_class
625
+ if not self.has_tip_length:
626
+ new_tip_class = sorted(
627
+ [tip for tip in self._liquid_class.supported_tips.keys()],
628
+ key=lambda tt: tt.value,
629
+ )[0]
630
+ else:
631
+ new_tip_class = self._active_tip_setting_name
632
+ self.set_tip_type(new_tip_class)
633
+
634
+ self.ready_to_aspirate = False
635
+
636
+ def set_tip_type_by_volume(self, tip_volume: float) -> None:
637
+ """Change the currently active tip type."""
638
+ intified = float(int(tip_volume))
639
+ try:
640
+ new_name = pip_types.PipetteTipType(int(intified))
641
+ except (ValueError, KeyError) as e:
642
+ raise InvalidLiquidClassName(
643
+ message=f"There is no configuration for tips of volume {intified} in liquid class {str(self._liquid_class_name)}",
644
+ detail={
645
+ "current-liquid-class": str(self._liquid_class_name),
646
+ "requested-volume": str(intified),
647
+ },
648
+ wrapping=[PythonException(e)],
649
+ ) from e
650
+ self.set_tip_type(new_name)
651
+
652
+ def set_tip_type(self, tip_type: pip_types.PipetteTipType) -> None:
653
+ """Change the currently active tip by its exact type."""
654
+ try:
655
+ new_tips = self._liquid_class.supported_tips[tip_type]
656
+ except KeyError as e:
657
+ raise InvalidInstrumentData(
658
+ message=f"There is no configuration for {tip_type.name} in the pick up tip configurations for a {self._config.display_name}",
659
+ wrapping=[PythonException(e)],
660
+ ) from e
661
+
662
+ self._active_tip_setting_name = tip_type
663
+ self._active_tip_settings = new_tips
664
+
665
+ self._aspirate_flow_rate = (
666
+ self._active_tip_settings.default_aspirate_flowrate.default
667
+ )
668
+ self._dispense_flow_rate = (
669
+ self._active_tip_settings.default_dispense_flowrate.default
670
+ )
671
+ self._blow_out_flow_rate = (
672
+ self._active_tip_settings.default_blowout_flowrate.default
673
+ )
674
+ self._flow_acceleration = self._active_tip_settings.default_flow_acceleration
675
+
676
+ self._fallback_tip_length = self._active_tip_settings.default_tip_length
677
+ self._versioned_tip_overlap_dictionary = (
678
+ self.get_nominal_tip_overlap_dictionary_by_configuration()
679
+ )
680
+ self._working_volume = min(tip_type.value, self.liquid_class.max_volume)
681
+
682
+ def get_pick_up_configuration( # noqa: C901
683
+ self,
684
+ ) -> Union[CamActionPickUpTipConfiguration, PressFitPickUpTipConfiguration]:
685
+ for config in (
686
+ self._config.pick_up_tip_configurations.press_fit,
687
+ self._config.pick_up_tip_configurations.cam_action,
688
+ ):
689
+ if not config:
690
+ continue
691
+ config_values = None
692
+ try:
693
+ config_values = config.configuration_by_nozzle_map[
694
+ self._nozzle_manager.current_configuration.valid_map_key
695
+ ][self._active_tip_setting_name.name]
696
+ except KeyError:
697
+ try:
698
+ config_values = config.configuration_by_nozzle_map[
699
+ self._nozzle_manager.current_configuration.valid_map_key
700
+ ].get("default")
701
+ if config_values is None:
702
+ raise KeyError(
703
+ f"Default tip type configuration values do not exist for Nozzle Map {self._nozzle_manager.current_configuration.valid_map_key}."
704
+ )
705
+ except KeyError:
706
+ # No valid key found for the approved nozzle map under this configuration - try the next
707
+ continue
708
+ if config_values is not None:
709
+ if isinstance(config, PressFitPickUpTipConfiguration) and all(
710
+ [
711
+ config_values.speed,
712
+ config_values.distance,
713
+ config_values.current,
714
+ ]
715
+ ):
716
+ return config
717
+ elif config_values.current is not None:
718
+ return config
719
+
720
+ raise CommandPreconditionViolated(
721
+ message="No valid pick up tip configuration values found in instrument definition.",
722
+ )
723
+
724
+ def get_pick_up_speed_by_configuration(
725
+ self,
726
+ config: Union[CamActionPickUpTipConfiguration, PressFitPickUpTipConfiguration],
727
+ ) -> float:
728
+ return pick_up_speed_by_configuration(
729
+ config,
730
+ self._nozzle_manager.current_configuration.valid_map_key,
731
+ self._active_tip_setting_name,
732
+ )
733
+
734
+ def get_pick_up_distance_by_configuration(
735
+ self,
736
+ config: Union[CamActionPickUpTipConfiguration, PressFitPickUpTipConfiguration],
737
+ ) -> float:
738
+ return pick_up_distance_by_configuration(
739
+ config,
740
+ self._nozzle_manager.current_configuration.valid_map_key,
741
+ self._active_tip_setting_name,
742
+ )
743
+
744
+ def get_pick_up_current_by_configuration(
745
+ self,
746
+ config: Union[CamActionPickUpTipConfiguration, PressFitPickUpTipConfiguration],
747
+ ) -> float:
748
+ return pick_up_current_by_configuration(
749
+ config,
750
+ self._nozzle_manager.current_configuration.valid_map_key,
751
+ self._active_tip_setting_name,
752
+ )
753
+
754
+ def get_nominal_tip_overlap_dictionary_by_configuration(
755
+ self,
756
+ ) -> Dict[str, Dict[str, float]]:
757
+ return nominal_tip_overlap_dictionary_by_configuration(
758
+ self._config,
759
+ self._nozzle_manager.current_configuration.valid_map_key,
760
+ self._active_tip_setting_name,
761
+ )
762
+
763
+
764
+ def _reload_and_check_skip(
765
+ new_config: PipetteConfigurations,
766
+ attached_instr: Pipette,
767
+ pipette_offset: PipetteOffsetByPipetteMount,
768
+ use_old_aspiration_functions: bool,
769
+ ) -> Tuple[Pipette, bool]:
770
+ # Once we have determined that the new and attached pipettes
771
+ # are similar enough that we might skip, see if the configs
772
+ # match closely enough.
773
+ # Returns a pipette object and True if we may skip hw reconfig
774
+ # TODO this can potentially be removed in a follow-up refactor.
775
+ if new_config == attached_instr.config:
776
+ # Same config, good enough
777
+ return attached_instr, True
778
+ else:
779
+ newdict = new_config.model_dump()
780
+ olddict = attached_instr.config.model_dump()
781
+ changed: Set[str] = set()
782
+ for k in newdict.keys():
783
+ if newdict[k] != olddict[k]:
784
+ changed.add(k)
785
+ if changed.intersection("quirks"):
786
+ # Something has changed that requires reconfig
787
+ p = Pipette(
788
+ new_config,
789
+ pipette_offset,
790
+ attached_instr._pipette_id,
791
+ use_old_aspiration_functions,
792
+ )
793
+ p.act_as(attached_instr.acting_as)
794
+ return p, False
795
+ # Good to skip, just need to update calibration offset and update_info
796
+ attached_instr._pipette_offset = pipette_offset
797
+ return attached_instr, True
798
+
799
+
800
+ def load_from_config_and_check_skip(
801
+ config: Optional[PipetteConfigurations],
802
+ attached: Optional[Pipette],
803
+ requested: Optional[PipetteName],
804
+ serial: Optional[str],
805
+ pipette_offset: PipetteOffsetByPipetteMount,
806
+ use_old_aspiration_functions: bool,
807
+ ) -> Tuple[Optional[Pipette], bool]:
808
+ """
809
+ Given the pipette config for an attached pipette (if any) freshly read
810
+ from disk, and any attached instruments,
811
+
812
+ - Compare the new and configured pipette configs
813
+ - Load the new configs if they differ
814
+ - Return a bool indicating whether hardware reconfiguration may be
815
+ skipped
816
+ """
817
+
818
+ if not config and not attached:
819
+ # nothing attached now, nothing used to be attached, nothing
820
+ # to reconfigure
821
+ return attached, True
822
+
823
+ if config and attached:
824
+ # something was attached and something is attached. are they
825
+ # the same? we can tell by comparing serials
826
+ if serial == attached.pipette_id:
827
+ if requested:
828
+ # if there is an explicit instrument request, in addition
829
+ # to checking if the old and new responses are the same
830
+ # we also have to make sure the old pipette is properly
831
+ # configured to the request
832
+ if requested == attached.acting_as:
833
+ # similar enough to check
834
+ return _reload_and_check_skip(
835
+ config,
836
+ attached,
837
+ pipette_offset,
838
+ use_old_aspiration_functions,
839
+ )
840
+ else:
841
+ # if there is no request, make sure that the old pipette
842
+ # did not have backcompat applied
843
+ if attached.acting_as == attached.name:
844
+ # similar enough to check
845
+ return _reload_and_check_skip(
846
+ config,
847
+ attached,
848
+ pipette_offset,
849
+ use_old_aspiration_functions,
850
+ )
851
+
852
+ if config:
853
+ return (
854
+ Pipette(config, pipette_offset, serial, use_old_aspiration_functions),
855
+ False,
856
+ )
857
+ else:
858
+ return None, False