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,819 @@
1
+ """Equipment command side-effect logic."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Optional, overload, List
5
+
6
+ from opentrons_shared_data.labware.labware_definition import LabwareDefinition
7
+ from opentrons_shared_data.pipette.types import PipetteNameType
8
+
9
+ from opentrons.calibration_storage.helpers import uri_from_details
10
+ from opentrons.types import MountType
11
+ from opentrons.hardware_control import HardwareControlAPI
12
+ from opentrons.hardware_control.modules import (
13
+ AbstractModule,
14
+ MagDeck,
15
+ HeaterShaker,
16
+ TempDeck,
17
+ Thermocycler,
18
+ AbsorbanceReader,
19
+ FlexStacker,
20
+ )
21
+ from opentrons.hardware_control.nozzle_manager import NozzleMap
22
+ from opentrons.protocol_engine.state.module_substates import (
23
+ MagneticModuleId,
24
+ HeaterShakerModuleId,
25
+ TemperatureModuleId,
26
+ ThermocyclerModuleId,
27
+ AbsorbanceReaderId,
28
+ FlexStackerId,
29
+ )
30
+ from ..errors import (
31
+ FailedToLoadPipetteError,
32
+ LabwareDefinitionDoesNotExistError,
33
+ ModuleNotAttachedError,
34
+ )
35
+ from ..resources import (
36
+ LabwareDataProvider,
37
+ ModuleDataProvider,
38
+ ModelUtils,
39
+ pipette_data_provider,
40
+ )
41
+ from ..state.state import StateStore
42
+ from ..state.modules import HardwareModule
43
+ from ..types import (
44
+ LabwareLocation,
45
+ DeckSlotLocation,
46
+ LabwareOffset,
47
+ ModuleModel,
48
+ ModuleDefinition,
49
+ AddressableAreaLocation,
50
+ LoadedLabware,
51
+ OnLabwareLocation,
52
+ )
53
+
54
+
55
+ @dataclass(frozen=True)
56
+ class LoadedLabwareData:
57
+ """The result of a load labware procedure."""
58
+
59
+ labware_id: str
60
+ definition: LabwareDefinition
61
+ offsetId: Optional[str]
62
+
63
+
64
+ @dataclass(frozen=True)
65
+ class ReloadedLabwareData:
66
+ """The result of a reload labware procedure."""
67
+
68
+ location: LabwareLocation
69
+ offsetId: Optional[str]
70
+
71
+
72
+ @dataclass(frozen=True)
73
+ class LoadedPipetteData:
74
+ """The result of a load pipette procedure."""
75
+
76
+ pipette_id: str
77
+ serial_number: str
78
+ static_config: pipette_data_provider.LoadedStaticPipetteData
79
+
80
+
81
+ @dataclass(frozen=True)
82
+ class LoadedModuleData:
83
+ """The result of a load module procedure."""
84
+
85
+ module_id: str
86
+ serial_number: Optional[str]
87
+ definition: ModuleDefinition
88
+
89
+
90
+ @dataclass(frozen=True)
91
+ class LoadedConfigureForVolumeData:
92
+ """The result of a load liquid class procedure."""
93
+
94
+ pipette_id: str
95
+ serial_number: str
96
+ volume: float
97
+ static_config: pipette_data_provider.LoadedStaticPipetteData
98
+
99
+
100
+ @dataclass(frozen=True)
101
+ class LoadedLabwarePoolData:
102
+ """The result of loading a labware pool with details for batch loads and location sequencing."""
103
+
104
+ primary_labware: LoadedLabware
105
+ adapter_labware: Optional[LoadedLabware] = None
106
+ lid_labware: Optional[LoadedLabware] = None
107
+
108
+
109
+ class EquipmentHandler:
110
+ """Implementation logic for labware, pipette, and module loading."""
111
+
112
+ _hardware_api: HardwareControlAPI
113
+ _state_store: StateStore
114
+ _labware_data_provider: LabwareDataProvider
115
+ _module_data_provider: ModuleDataProvider
116
+ _model_utils: ModelUtils
117
+ _virtual_pipette_data_provider: pipette_data_provider.VirtualPipetteDataProvider
118
+
119
+ def __init__(
120
+ self,
121
+ hardware_api: HardwareControlAPI,
122
+ state_store: StateStore,
123
+ labware_data_provider: Optional[LabwareDataProvider] = None,
124
+ module_data_provider: Optional[ModuleDataProvider] = None,
125
+ model_utils: Optional[ModelUtils] = None,
126
+ virtual_pipette_data_provider: Optional[
127
+ pipette_data_provider.VirtualPipetteDataProvider
128
+ ] = None,
129
+ ) -> None:
130
+ """Initialize an EquipmentHandler instance."""
131
+ self._hardware_api = hardware_api
132
+ self._state_store = state_store
133
+ self._labware_data_provider = labware_data_provider or LabwareDataProvider()
134
+ self._module_data_provider = module_data_provider or ModuleDataProvider()
135
+ self._model_utils = model_utils or ModelUtils()
136
+ self._virtual_pipette_data_provider = (
137
+ virtual_pipette_data_provider
138
+ or pipette_data_provider.VirtualPipetteDataProvider()
139
+ )
140
+
141
+ async def load_definition_for_details(
142
+ self, load_name: str, namespace: str, version: int
143
+ ) -> tuple[LabwareDefinition, str]:
144
+ """Load the definition for a labware from the parameters passed for it to a command.
145
+
146
+ Args:
147
+ load_name: The labware's load name.
148
+ namespace: The labware's namespace.
149
+ version: The labware's version.
150
+
151
+ Returns:
152
+ A tuple of the loaded LabwareDefinition object and its definition URI.
153
+ """
154
+ definition_uri = uri_from_details(
155
+ load_name=load_name,
156
+ namespace=namespace,
157
+ version=version,
158
+ )
159
+
160
+ try:
161
+ # Try to use existing definition in state.
162
+ return (
163
+ self._state_store.labware.get_definition_by_uri(definition_uri),
164
+ definition_uri,
165
+ )
166
+ except LabwareDefinitionDoesNotExistError:
167
+ definition = await self._labware_data_provider.get_labware_definition(
168
+ load_name=load_name,
169
+ namespace=namespace,
170
+ version=version,
171
+ )
172
+ return definition, definition_uri
173
+
174
+ async def load_labware_from_definition(
175
+ self,
176
+ definition: LabwareDefinition,
177
+ location: LabwareLocation,
178
+ labware_id: Optional[str],
179
+ labware_pending_load: dict[str, LoadedLabware] | None = None,
180
+ ) -> LoadedLabwareData:
181
+ """Load labware from already-found definition."""
182
+ definition_uri = uri_from_details(
183
+ load_name=definition.parameters.loadName,
184
+ namespace=definition.namespace,
185
+ version=definition.version,
186
+ )
187
+ return await self._load_labware_from_def_and_uri(
188
+ definition, definition_uri, location, labware_id, labware_pending_load
189
+ )
190
+
191
+ async def _load_labware_from_def_and_uri(
192
+ self,
193
+ definition: LabwareDefinition,
194
+ definition_uri: str,
195
+ location: LabwareLocation,
196
+ labware_id: str | None,
197
+ labware_pending_load: dict[str, LoadedLabware] | None,
198
+ ) -> LoadedLabwareData:
199
+ labware_id = (
200
+ labware_id if labware_id is not None else self._model_utils.generate_id()
201
+ )
202
+
203
+ # Allow propagation of ModuleNotLoadedError.
204
+ offset_id = self.find_applicable_labware_offset_id(
205
+ labware_definition_uri=definition_uri,
206
+ labware_location=location,
207
+ labware_pending_load=labware_pending_load,
208
+ )
209
+
210
+ return LoadedLabwareData(
211
+ labware_id=labware_id, definition=definition, offsetId=offset_id
212
+ )
213
+
214
+ async def load_labware_pool_from_definitions(
215
+ self,
216
+ pool_primary_definition: LabwareDefinition,
217
+ pool_adapter_definition: Optional[LabwareDefinition],
218
+ pool_lid_definition: Optional[LabwareDefinition],
219
+ location: LabwareLocation,
220
+ primary_id: Optional[str],
221
+ adapter_id: Optional[str],
222
+ lid_id: Optional[str],
223
+ ) -> LoadedLabwarePoolData:
224
+ """Load a pool of labware from already-found definitions."""
225
+ adapter_labware: LoadedLabware | None = None
226
+ lid_labware: LoadedLabware | None = None
227
+ adapter_lw = None
228
+ labware_by_id: dict[str, LoadedLabware] = {}
229
+ if pool_adapter_definition is not None:
230
+ adapter_location = location
231
+ adapter_lw = await self.load_labware_from_definition(
232
+ definition=pool_adapter_definition,
233
+ location=adapter_location,
234
+ labware_id=adapter_id,
235
+ labware_pending_load=labware_by_id,
236
+ )
237
+ adapter_uri = str(
238
+ uri_from_details(
239
+ namespace=adapter_lw.definition.namespace,
240
+ load_name=adapter_lw.definition.parameters.loadName,
241
+ version=adapter_lw.definition.version,
242
+ )
243
+ )
244
+ adapter_labware = LoadedLabware.model_construct(
245
+ id=adapter_lw.labware_id,
246
+ location=adapter_location,
247
+ loadName=adapter_lw.definition.parameters.loadName,
248
+ definitionUri=adapter_uri,
249
+ offsetId=None,
250
+ )
251
+ labware_by_id[adapter_labware.id] = adapter_labware
252
+
253
+ primary_location: LabwareLocation = (
254
+ location
255
+ if adapter_lw is None
256
+ else OnLabwareLocation(labwareId=adapter_lw.labware_id)
257
+ )
258
+ loaded_labware = await self.load_labware_from_definition(
259
+ definition=pool_primary_definition,
260
+ location=primary_location,
261
+ labware_id=primary_id,
262
+ labware_pending_load={lw_id: lw for lw_id, lw in labware_by_id.items()},
263
+ )
264
+ primary_uri = str(
265
+ uri_from_details(
266
+ namespace=loaded_labware.definition.namespace,
267
+ load_name=loaded_labware.definition.parameters.loadName,
268
+ version=loaded_labware.definition.version,
269
+ )
270
+ )
271
+ primary_labware = LoadedLabware.model_construct(
272
+ id=loaded_labware.labware_id,
273
+ location=primary_location,
274
+ loadName=loaded_labware.definition.parameters.loadName,
275
+ definitionUri=primary_uri,
276
+ )
277
+ labware_by_id[primary_labware.id] = primary_labware
278
+
279
+ # If there is a lid load it
280
+ if pool_lid_definition is not None:
281
+ lid_location = OnLabwareLocation(labwareId=loaded_labware.labware_id)
282
+ lid_lw = await self.load_labware_from_definition(
283
+ definition=pool_lid_definition,
284
+ location=lid_location,
285
+ labware_id=lid_id,
286
+ labware_pending_load={lw_id: lw for lw_id, lw in labware_by_id.items()},
287
+ )
288
+ lid_uri = str(
289
+ uri_from_details(
290
+ namespace=lid_lw.definition.namespace,
291
+ load_name=lid_lw.definition.parameters.loadName,
292
+ version=lid_lw.definition.version,
293
+ )
294
+ )
295
+ lid_labware = LoadedLabware.model_construct(
296
+ id=lid_lw.labware_id,
297
+ location=lid_location,
298
+ loadName=lid_lw.definition.parameters.loadName,
299
+ definitionUri=lid_uri,
300
+ offsetId=None,
301
+ )
302
+ labware_by_id[lid_labware.id] = lid_labware
303
+ return LoadedLabwarePoolData(
304
+ primary_labware=primary_labware,
305
+ adapter_labware=adapter_labware,
306
+ lid_labware=lid_labware,
307
+ )
308
+
309
+ async def load_labware(
310
+ self,
311
+ load_name: str,
312
+ namespace: str,
313
+ version: int,
314
+ location: LabwareLocation,
315
+ labware_id: Optional[str],
316
+ ) -> LoadedLabwareData:
317
+ """Load labware by assigning an identifier and pulling required data.
318
+
319
+ Args:
320
+ load_name: The labware's load name.
321
+ namespace: The labware's namespace.
322
+ version: The labware's version.
323
+ location: The deck location at which labware is placed.
324
+ labware_id: An optional identifier to assign the labware. If None, an
325
+ identifier will be generated.
326
+
327
+ Raises:
328
+ ModuleNotLoadedError: If `location` references a module ID
329
+ that doesn't point to a valid loaded module.
330
+
331
+ Returns:
332
+ A LoadedLabwareData object.
333
+ """
334
+ definition, definition_uri = await self.load_definition_for_details(
335
+ load_name, namespace, version
336
+ )
337
+ return await self._load_labware_from_def_and_uri(
338
+ definition, definition_uri, location, labware_id, None
339
+ )
340
+
341
+ async def reload_labware(self, labware_id: str) -> ReloadedLabwareData:
342
+ """Reload an already-loaded labware. This cannot change the labware location.
343
+
344
+ Args:
345
+ labware_id: The ID of the already-loaded labware.
346
+
347
+ Raises:
348
+ LabwareNotLoadedError: If `labware_id` does not reference a loaded labware.
349
+
350
+ """
351
+ location = self._state_store.labware.get_location(labware_id)
352
+ definition_uri = self._state_store.labware.get_definition_uri(labware_id)
353
+ offset_id = self.find_applicable_labware_offset_id(
354
+ labware_definition_uri=definition_uri,
355
+ labware_location=location,
356
+ )
357
+
358
+ return ReloadedLabwareData(location=location, offsetId=offset_id)
359
+
360
+ async def load_pipette(
361
+ self,
362
+ pipette_name: PipetteNameType,
363
+ mount: MountType,
364
+ pipette_id: Optional[str],
365
+ tip_overlap_version: Optional[str],
366
+ ) -> LoadedPipetteData:
367
+ """Ensure the requested pipette is attached.
368
+
369
+ Args:
370
+ pipette_name: The pipette name.
371
+ mount: The mount on which pipette must be attached.
372
+ pipette_id: An optional identifier to assign the pipette. If None, an
373
+ identifier will be generated.
374
+ tip_overlap_version: An optional specifier for the version of tip overlap data to use.
375
+ If None, defaults to v0. Does not need to be format checked - this function does it.
376
+
377
+ Returns:
378
+ A LoadedPipetteData object.
379
+ """
380
+ # TODO (spp, 2023-05-10): either raise error if using MountType.EXTENSION in
381
+ # load pipettes command, or change the mount type used to be a restricted
382
+ # PipetteMountType which has only pipette mounts and not the extension mount.
383
+ use_virtual_pipettes = self._state_store.config.use_virtual_pipettes
384
+
385
+ pipette_name_value = (
386
+ pipette_name.value
387
+ if isinstance(pipette_name, PipetteNameType)
388
+ else pipette_name
389
+ )
390
+ sanitized_overlap_version = (
391
+ pipette_data_provider.validate_and_default_tip_overlap_version(
392
+ tip_overlap_version
393
+ )
394
+ )
395
+
396
+ pipette_id = pipette_id or self._model_utils.generate_id()
397
+ if not use_virtual_pipettes:
398
+ cache_request = {mount.to_hw_mount(): pipette_name_value}
399
+
400
+ # TODO(mc, 2022-12-09): putting the other pipette in the cache request
401
+ # is only to support protocol analysis, since the hardware simulator
402
+ # does not cache requested virtual instruments. Remove per
403
+ # https://opentrons.atlassian.net/browse/RLIQ-258
404
+ other_mount = mount.other_mount()
405
+ other_pipette = self._state_store.pipettes.get_by_mount(other_mount)
406
+ if other_pipette is not None:
407
+ cache_request[other_mount.to_hw_mount()] = (
408
+ other_pipette.pipetteName.value
409
+ if isinstance(other_pipette.pipetteName, PipetteNameType)
410
+ else other_pipette.pipetteName
411
+ )
412
+
413
+ # TODO(mc, 2020-10-18): calling `cache_instruments` mirrors the
414
+ # behavior of protocol_context.load_instrument, and is used here as a
415
+ # pipette existence check
416
+ try:
417
+ await self._hardware_api.cache_instruments(cache_request)
418
+ except RuntimeError as e:
419
+ raise FailedToLoadPipetteError(str(e)) from e
420
+
421
+ pipette_dict = self._hardware_api.get_attached_instrument(
422
+ mount.to_hw_mount()
423
+ )
424
+
425
+ serial_number = pipette_dict["pipette_id"]
426
+ static_pipette_config = pipette_data_provider.get_pipette_static_config(
427
+ pipette_dict=pipette_dict, tip_overlap_version=sanitized_overlap_version
428
+ )
429
+
430
+ else:
431
+ serial_number = self._model_utils.generate_id(prefix="fake-serial-number-")
432
+ static_pipette_config = (
433
+ self._virtual_pipette_data_provider.get_virtual_pipette_static_config(
434
+ pipette_name=pipette_name_value,
435
+ pipette_id=pipette_id,
436
+ tip_overlap_version=sanitized_overlap_version,
437
+ )
438
+ )
439
+ serial = serial_number or ""
440
+ return LoadedPipetteData(
441
+ pipette_id=pipette_id,
442
+ serial_number=serial,
443
+ static_config=static_pipette_config,
444
+ )
445
+
446
+ async def load_magnetic_block(
447
+ self,
448
+ model: ModuleModel,
449
+ location: AddressableAreaLocation,
450
+ module_id: Optional[str],
451
+ ) -> LoadedModuleData:
452
+ """Ensure the required magnetic block is attached.
453
+
454
+ Args:
455
+ model: The model name of the module.
456
+ location: The deck location of the module
457
+ module_id: Optional ID assigned to the module.
458
+ If None, an ID will be generated.
459
+
460
+ Returns:
461
+ A LoadedModuleData object.
462
+
463
+ Raises:
464
+ ModuleAlreadyPresentError: A module of a different type is already
465
+ assigned to the requested location.
466
+ """
467
+ assert ModuleModel.is_magnetic_block(
468
+ model
469
+ ), f"Expected Magnetic block and got {model.name}"
470
+ definition = self._module_data_provider.get_definition(model)
471
+ return LoadedModuleData(
472
+ module_id=self._model_utils.ensure_id(module_id),
473
+ serial_number=None,
474
+ definition=definition,
475
+ )
476
+
477
+ async def load_module(
478
+ self,
479
+ model: ModuleModel,
480
+ location: AddressableAreaLocation,
481
+ module_id: Optional[str],
482
+ ) -> LoadedModuleData:
483
+ """Ensure the required module is attached.
484
+
485
+ Args:
486
+ model: The model name of the module.
487
+ location: The deck location of the module
488
+ module_id: Optional ID assigned to the module.
489
+ If None, an ID will be generated.
490
+
491
+ Returns:
492
+ A LoadedModuleData object.
493
+
494
+ Raises:
495
+ ModuleNotAttachedError: A not-yet-assigned module matching the requested
496
+ parameters could not be found in the attached modules list.
497
+ ModuleAlreadyPresentError: A module of a different type is already
498
+ assigned to the requested location.
499
+ """
500
+ # TODO(mc, 2022-02-09): validate module location given deck definition
501
+ use_virtual_modules = self._state_store.config.use_virtual_modules
502
+
503
+ if not use_virtual_modules:
504
+ attached_modules = [
505
+ HardwareModule(
506
+ serial_number=hw_mod.device_info["serial"],
507
+ definition=self._module_data_provider.get_definition(
508
+ ModuleModel(hw_mod.model())
509
+ ),
510
+ )
511
+ for hw_mod in self._hardware_api.attached_modules
512
+ ]
513
+
514
+ serial_number_at_locaiton = self._state_store.geometry._addressable_areas.get_fixture_serial_from_deck_configuration_by_addressable_area(
515
+ addressable_area_name=location.addressableAreaName
516
+ )
517
+ cutout_id = self._state_store.geometry._addressable_areas.get_cutout_id_by_deck_slot_name(
518
+ slot_name=self._state_store.geometry._addressable_areas.get_addressable_area_base_slot(
519
+ location.addressableAreaName
520
+ )
521
+ )
522
+
523
+ attached_module = self._state_store.modules.select_hardware_module_to_load(
524
+ model=model,
525
+ location=cutout_id,
526
+ attached_modules=attached_modules,
527
+ expected_serial_number=serial_number_at_locaiton,
528
+ )
529
+
530
+ else:
531
+ attached_module = HardwareModule(
532
+ serial_number=self._model_utils.generate_id(
533
+ prefix="fake-serial-number-"
534
+ ),
535
+ definition=self._module_data_provider.get_definition(model),
536
+ )
537
+
538
+ return LoadedModuleData(
539
+ module_id=self._model_utils.ensure_id(module_id),
540
+ serial_number=attached_module.serial_number,
541
+ definition=attached_module.definition,
542
+ )
543
+
544
+ async def load_lids(
545
+ self,
546
+ load_name: str,
547
+ namespace: str,
548
+ version: int,
549
+ location: LabwareLocation,
550
+ quantity: int,
551
+ labware_ids: Optional[List[str]] = None,
552
+ ) -> List[LoadedLabwareData]:
553
+ """Load one or many lid labware by assigning an identifier and pulling required data.
554
+
555
+ Args:
556
+ load_name: The lid labware's load name.
557
+ namespace: The lid labware's namespace.
558
+ version: The lid labware's version.
559
+ location: The deck location at which lid(s) will be placed.
560
+ quantity: The quantity of lids to load at a location.
561
+ labware_ids: An optional list of identifiers to assign the labware. If None,
562
+ an identifier will be generated.
563
+
564
+ Raises:
565
+ ModuleNotLoadedError: If `location` references a module ID
566
+ that doesn't point to a valid loaded module.
567
+
568
+ Returns:
569
+ A list of LoadedLabwareData objects.
570
+ """
571
+ definition_uri = uri_from_details(
572
+ load_name=load_name,
573
+ namespace=namespace,
574
+ version=version,
575
+ )
576
+ try:
577
+ # Try to use existing definition in state.
578
+ definition = self._state_store.labware.get_definition_by_uri(definition_uri)
579
+ except LabwareDefinitionDoesNotExistError:
580
+ definition = await self._labware_data_provider.get_labware_definition(
581
+ load_name=load_name,
582
+ namespace=namespace,
583
+ version=version,
584
+ )
585
+
586
+ stack_limit = definition.stackLimit if definition.stackLimit is not None else 1
587
+ if quantity > stack_limit:
588
+ raise ValueError(
589
+ f"Requested quantity {quantity} is greater than the stack limit of {stack_limit} provided by definition for {load_name}."
590
+ )
591
+
592
+ is_deck_slot_compatible = (
593
+ True
594
+ if definition.parameters.isDeckSlotCompatible is None
595
+ else definition.parameters.isDeckSlotCompatible
596
+ )
597
+
598
+ if isinstance(location, DeckSlotLocation) and not is_deck_slot_compatible:
599
+ raise ValueError(
600
+ f"Lid Labware {load_name} cannot be loaded onto a Deck Slot."
601
+ )
602
+
603
+ load_labware_data_list: list[LoadedLabwareData] = []
604
+ ids: list[str] = []
605
+ if labware_ids is not None:
606
+ if len(labware_ids) < quantity:
607
+ raise ValueError(
608
+ f"Requested quantity {quantity} is greater than the number of labware lid IDs provided for {load_name}."
609
+ )
610
+ ids = labware_ids
611
+ else:
612
+ for i in range(quantity):
613
+ ids.append(self._model_utils.generate_id())
614
+ for id in ids:
615
+ load_labware_data_list.append(
616
+ LoadedLabwareData(
617
+ labware_id=id,
618
+ definition=definition,
619
+ offsetId=None,
620
+ )
621
+ )
622
+
623
+ return load_labware_data_list
624
+
625
+ async def configure_for_volume(
626
+ self, pipette_id: str, volume: float, tip_overlap_version: Optional[str]
627
+ ) -> LoadedConfigureForVolumeData:
628
+ """Ensure the requested volume can be configured for the given pipette.
629
+
630
+ Args:
631
+ pipette_id: The identifier for the pipette.
632
+ volume: The volume to configure the pipette for
633
+
634
+ Returns:
635
+ A LoadedConfiguredVolumeData object.
636
+ """
637
+ use_virtual_pipettes = self._state_store.config.use_virtual_pipettes
638
+ sanitized_overlap_version = (
639
+ pipette_data_provider.validate_and_default_tip_overlap_version(
640
+ tip_overlap_version
641
+ )
642
+ )
643
+
644
+ if not use_virtual_pipettes:
645
+ mount = self._state_store.pipettes.get_mount(pipette_id).to_hw_mount()
646
+
647
+ await self._hardware_api.configure_for_volume(mount, volume)
648
+ pipette_dict = self._hardware_api.get_attached_instrument(mount)
649
+
650
+ serial_number = pipette_dict["pipette_id"]
651
+ static_pipette_config = pipette_data_provider.get_pipette_static_config(
652
+ pipette_dict=pipette_dict, tip_overlap_version=sanitized_overlap_version
653
+ )
654
+
655
+ else:
656
+ model = self._state_store.pipettes.get_model_name(pipette_id)
657
+ self._virtual_pipette_data_provider.configure_virtual_pipette_for_volume(
658
+ pipette_id, volume, model
659
+ )
660
+
661
+ serial_number = self._model_utils.generate_id(prefix="fake-serial-number-")
662
+ static_pipette_config = self._virtual_pipette_data_provider.get_virtual_pipette_static_config_by_model_string(
663
+ pipette_model_string=model,
664
+ pipette_id=pipette_id,
665
+ tip_overlap_version=sanitized_overlap_version,
666
+ )
667
+
668
+ return LoadedConfigureForVolumeData(
669
+ pipette_id=pipette_id,
670
+ serial_number=serial_number,
671
+ volume=volume,
672
+ static_config=static_pipette_config,
673
+ )
674
+
675
+ async def configure_nozzle_layout(
676
+ self,
677
+ pipette_id: str,
678
+ primary_nozzle: Optional[str] = None,
679
+ front_right_nozzle: Optional[str] = None,
680
+ back_left_nozzle: Optional[str] = None,
681
+ ) -> NozzleMap:
682
+ """Ensure the requested nozzle layout is compatible with the current pipette.
683
+
684
+ Args:
685
+ pipette_id: The identifier for the pipette.
686
+ primary_nozzle: The nozzle which will be used as the
687
+ front_right_nozzle
688
+ back_left_nozzle
689
+
690
+ Returns:
691
+ A NozzleMap object or None.
692
+ """
693
+ use_virtual_pipettes = self._state_store.config.use_virtual_pipettes
694
+
695
+ if not use_virtual_pipettes:
696
+ mount = self._state_store.pipettes.get_mount(pipette_id).to_hw_mount()
697
+
698
+ await self._hardware_api.update_nozzle_configuration_for_mount(
699
+ mount,
700
+ back_left_nozzle if back_left_nozzle else primary_nozzle,
701
+ front_right_nozzle if front_right_nozzle else primary_nozzle,
702
+ primary_nozzle if back_left_nozzle else None,
703
+ )
704
+ pipette_dict = self._hardware_api.get_attached_instrument(mount)
705
+ nozzle_map = pipette_dict["current_nozzle_map"]
706
+
707
+ else:
708
+ model = self._state_store.pipettes.get_model_name(pipette_id)
709
+ self._virtual_pipette_data_provider.configure_virtual_pipette_nozzle_layout(
710
+ pipette_id,
711
+ model,
712
+ back_left_nozzle if back_left_nozzle else primary_nozzle,
713
+ front_right_nozzle if front_right_nozzle else primary_nozzle,
714
+ primary_nozzle if back_left_nozzle else None,
715
+ )
716
+ nozzle_map = (
717
+ self._virtual_pipette_data_provider.get_nozzle_layout_for_pipette(
718
+ pipette_id
719
+ )
720
+ )
721
+
722
+ return nozzle_map
723
+
724
+ @overload
725
+ def get_module_hardware_api(
726
+ self,
727
+ module_id: MagneticModuleId,
728
+ ) -> Optional[MagDeck]:
729
+ ...
730
+
731
+ @overload
732
+ def get_module_hardware_api(
733
+ self,
734
+ module_id: HeaterShakerModuleId,
735
+ ) -> Optional[HeaterShaker]:
736
+ ...
737
+
738
+ @overload
739
+ def get_module_hardware_api(
740
+ self,
741
+ module_id: TemperatureModuleId,
742
+ ) -> Optional[TempDeck]:
743
+ ...
744
+
745
+ @overload
746
+ def get_module_hardware_api(
747
+ self,
748
+ module_id: ThermocyclerModuleId,
749
+ ) -> Optional[Thermocycler]:
750
+ ...
751
+
752
+ @overload
753
+ def get_module_hardware_api(
754
+ self,
755
+ module_id: AbsorbanceReaderId,
756
+ ) -> Optional[AbsorbanceReader]:
757
+ ...
758
+
759
+ @overload
760
+ def get_module_hardware_api(
761
+ self,
762
+ module_id: FlexStackerId,
763
+ ) -> Optional[FlexStacker]:
764
+ ...
765
+
766
+ def get_module_hardware_api(self, module_id: str) -> Optional[AbstractModule]:
767
+ """Get the hardware API for a given module."""
768
+ use_virtual_modules = self._state_store.config.use_virtual_modules
769
+ if use_virtual_modules:
770
+ return None
771
+
772
+ attached_modules = self._hardware_api.attached_modules
773
+ serial_number = self._state_store.modules.get_serial_number(module_id)
774
+ for mod in attached_modules:
775
+ if mod.device_info["serial"] == serial_number:
776
+ return mod
777
+
778
+ raise ModuleNotAttachedError(
779
+ f'No module attached with serial number "{serial_number}"'
780
+ f' for module ID "{module_id}".'
781
+ )
782
+
783
+ def find_applicable_labware_offset_id(
784
+ self,
785
+ labware_definition_uri: str,
786
+ labware_location: LabwareLocation,
787
+ labware_pending_load: dict[str, LoadedLabware] | None = None,
788
+ ) -> str | None:
789
+ """Figure out what offset would apply to a labware in the given location.
790
+
791
+ Raises:
792
+ ModuleNotLoadedError: If `labware_location` references a module ID
793
+ that doesn't point to a valid loaded module.
794
+
795
+ Returns:
796
+ The ID of the labware offset that will apply,
797
+ or None if no labware offset will apply.
798
+ """
799
+ labware_offset_location = (
800
+ self._state_store.geometry.get_projected_offset_location(
801
+ labware_location, labware_pending_load
802
+ )
803
+ )
804
+
805
+ if labware_offset_location is None:
806
+ # No offset for off-deck location.
807
+ # Returning None instead of raising an exception allows loading a labware
808
+ # with 'offDeck' as valid location.
809
+ # Also allows using `moveLabware` with 'offDeck' location.
810
+ return None
811
+ offset = self._state_store.labware.find_applicable_labware_offset(
812
+ definition_uri=labware_definition_uri,
813
+ location=labware_offset_location,
814
+ )
815
+ return self._get_id_from_offset(offset)
816
+
817
+ @staticmethod
818
+ def _get_id_from_offset(labware_offset: Optional[LabwareOffset]) -> Optional[str]:
819
+ return None if labware_offset is None else labware_offset.id