opentrons 8.6.0a1__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (600) hide show
  1. opentrons/__init__.py +150 -0
  2. opentrons/_version.py +34 -0
  3. opentrons/calibration_storage/__init__.py +54 -0
  4. opentrons/calibration_storage/deck_configuration.py +62 -0
  5. opentrons/calibration_storage/encoder_decoder.py +31 -0
  6. opentrons/calibration_storage/file_operators.py +142 -0
  7. opentrons/calibration_storage/helpers.py +103 -0
  8. opentrons/calibration_storage/ot2/__init__.py +34 -0
  9. opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
  10. opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
  11. opentrons/calibration_storage/ot2/models/__init__.py +0 -0
  12. opentrons/calibration_storage/ot2/models/v1.py +149 -0
  13. opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
  14. opentrons/calibration_storage/ot2/tip_length.py +281 -0
  15. opentrons/calibration_storage/ot3/__init__.py +31 -0
  16. opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
  17. opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
  18. opentrons/calibration_storage/ot3/models/__init__.py +0 -0
  19. opentrons/calibration_storage/ot3/models/v1.py +122 -0
  20. opentrons/calibration_storage/ot3/module_offset.py +138 -0
  21. opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
  22. opentrons/calibration_storage/types.py +45 -0
  23. opentrons/cli/__init__.py +21 -0
  24. opentrons/cli/__main__.py +5 -0
  25. opentrons/cli/analyze.py +501 -0
  26. opentrons/config/__init__.py +631 -0
  27. opentrons/config/advanced_settings.py +871 -0
  28. opentrons/config/defaults_ot2.py +214 -0
  29. opentrons/config/defaults_ot3.py +499 -0
  30. opentrons/config/feature_flags.py +86 -0
  31. opentrons/config/gripper_config.py +55 -0
  32. opentrons/config/reset.py +203 -0
  33. opentrons/config/robot_configs.py +187 -0
  34. opentrons/config/types.py +183 -0
  35. opentrons/drivers/__init__.py +0 -0
  36. opentrons/drivers/absorbance_reader/__init__.py +11 -0
  37. opentrons/drivers/absorbance_reader/abstract.py +72 -0
  38. opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
  39. opentrons/drivers/absorbance_reader/driver.py +81 -0
  40. opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
  41. opentrons/drivers/absorbance_reader/simulator.py +84 -0
  42. opentrons/drivers/asyncio/__init__.py +0 -0
  43. opentrons/drivers/asyncio/communication/__init__.py +22 -0
  44. opentrons/drivers/asyncio/communication/async_serial.py +183 -0
  45. opentrons/drivers/asyncio/communication/errors.py +88 -0
  46. opentrons/drivers/asyncio/communication/serial_connection.py +552 -0
  47. opentrons/drivers/command_builder.py +102 -0
  48. opentrons/drivers/flex_stacker/__init__.py +13 -0
  49. opentrons/drivers/flex_stacker/abstract.py +214 -0
  50. opentrons/drivers/flex_stacker/driver.py +768 -0
  51. opentrons/drivers/flex_stacker/errors.py +68 -0
  52. opentrons/drivers/flex_stacker/simulator.py +309 -0
  53. opentrons/drivers/flex_stacker/types.py +367 -0
  54. opentrons/drivers/flex_stacker/utils.py +19 -0
  55. opentrons/drivers/heater_shaker/__init__.py +5 -0
  56. opentrons/drivers/heater_shaker/abstract.py +76 -0
  57. opentrons/drivers/heater_shaker/driver.py +204 -0
  58. opentrons/drivers/heater_shaker/simulator.py +94 -0
  59. opentrons/drivers/mag_deck/__init__.py +6 -0
  60. opentrons/drivers/mag_deck/abstract.py +44 -0
  61. opentrons/drivers/mag_deck/driver.py +208 -0
  62. opentrons/drivers/mag_deck/simulator.py +63 -0
  63. opentrons/drivers/rpi_drivers/__init__.py +33 -0
  64. opentrons/drivers/rpi_drivers/dev_types.py +94 -0
  65. opentrons/drivers/rpi_drivers/gpio.py +282 -0
  66. opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
  67. opentrons/drivers/rpi_drivers/interfaces.py +15 -0
  68. opentrons/drivers/rpi_drivers/types.py +364 -0
  69. opentrons/drivers/rpi_drivers/usb.py +102 -0
  70. opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
  71. opentrons/drivers/serial_communication.py +151 -0
  72. opentrons/drivers/smoothie_drivers/__init__.py +4 -0
  73. opentrons/drivers/smoothie_drivers/connection.py +51 -0
  74. opentrons/drivers/smoothie_drivers/constants.py +121 -0
  75. opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
  76. opentrons/drivers/smoothie_drivers/errors.py +49 -0
  77. opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
  78. opentrons/drivers/smoothie_drivers/simulator.py +99 -0
  79. opentrons/drivers/smoothie_drivers/types.py +16 -0
  80. opentrons/drivers/temp_deck/__init__.py +10 -0
  81. opentrons/drivers/temp_deck/abstract.py +54 -0
  82. opentrons/drivers/temp_deck/driver.py +197 -0
  83. opentrons/drivers/temp_deck/simulator.py +57 -0
  84. opentrons/drivers/thermocycler/__init__.py +12 -0
  85. opentrons/drivers/thermocycler/abstract.py +99 -0
  86. opentrons/drivers/thermocycler/driver.py +395 -0
  87. opentrons/drivers/thermocycler/simulator.py +126 -0
  88. opentrons/drivers/types.py +107 -0
  89. opentrons/drivers/utils.py +222 -0
  90. opentrons/execute.py +742 -0
  91. opentrons/hardware_control/__init__.py +65 -0
  92. opentrons/hardware_control/__main__.py +77 -0
  93. opentrons/hardware_control/adapters.py +98 -0
  94. opentrons/hardware_control/api.py +1347 -0
  95. opentrons/hardware_control/backends/__init__.py +7 -0
  96. opentrons/hardware_control/backends/controller.py +400 -0
  97. opentrons/hardware_control/backends/errors.py +9 -0
  98. opentrons/hardware_control/backends/estop_state.py +164 -0
  99. opentrons/hardware_control/backends/flex_protocol.py +497 -0
  100. opentrons/hardware_control/backends/ot3controller.py +1930 -0
  101. opentrons/hardware_control/backends/ot3simulator.py +900 -0
  102. opentrons/hardware_control/backends/ot3utils.py +664 -0
  103. opentrons/hardware_control/backends/simulator.py +442 -0
  104. opentrons/hardware_control/backends/status_bar_state.py +240 -0
  105. opentrons/hardware_control/backends/subsystem_manager.py +431 -0
  106. opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
  107. opentrons/hardware_control/backends/types.py +14 -0
  108. opentrons/hardware_control/constants.py +6 -0
  109. opentrons/hardware_control/dev_types.py +125 -0
  110. opentrons/hardware_control/emulation/__init__.py +0 -0
  111. opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
  112. opentrons/hardware_control/emulation/app.py +56 -0
  113. opentrons/hardware_control/emulation/connection_handler.py +38 -0
  114. opentrons/hardware_control/emulation/heater_shaker.py +150 -0
  115. opentrons/hardware_control/emulation/magdeck.py +60 -0
  116. opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
  117. opentrons/hardware_control/emulation/module_server/client.py +78 -0
  118. opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
  119. opentrons/hardware_control/emulation/module_server/models.py +31 -0
  120. opentrons/hardware_control/emulation/module_server/server.py +110 -0
  121. opentrons/hardware_control/emulation/parser.py +74 -0
  122. opentrons/hardware_control/emulation/proxy.py +241 -0
  123. opentrons/hardware_control/emulation/run_emulator.py +68 -0
  124. opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
  125. opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
  126. opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
  127. opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
  128. opentrons/hardware_control/emulation/settings.py +119 -0
  129. opentrons/hardware_control/emulation/simulations.py +133 -0
  130. opentrons/hardware_control/emulation/smoothie.py +192 -0
  131. opentrons/hardware_control/emulation/tempdeck.py +69 -0
  132. opentrons/hardware_control/emulation/thermocycler.py +128 -0
  133. opentrons/hardware_control/emulation/types.py +10 -0
  134. opentrons/hardware_control/emulation/util.py +38 -0
  135. opentrons/hardware_control/errors.py +43 -0
  136. opentrons/hardware_control/execution_manager.py +164 -0
  137. opentrons/hardware_control/instruments/__init__.py +5 -0
  138. opentrons/hardware_control/instruments/instrument_abc.py +39 -0
  139. opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
  140. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
  141. opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
  142. opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
  143. opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
  144. opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
  145. opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
  146. opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
  147. opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
  148. opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
  149. opentrons/hardware_control/module_control.py +332 -0
  150. opentrons/hardware_control/modules/__init__.py +69 -0
  151. opentrons/hardware_control/modules/absorbance_reader.py +373 -0
  152. opentrons/hardware_control/modules/errors.py +7 -0
  153. opentrons/hardware_control/modules/flex_stacker.py +948 -0
  154. opentrons/hardware_control/modules/heater_shaker.py +426 -0
  155. opentrons/hardware_control/modules/lid_temp_status.py +35 -0
  156. opentrons/hardware_control/modules/magdeck.py +233 -0
  157. opentrons/hardware_control/modules/mod_abc.py +245 -0
  158. opentrons/hardware_control/modules/module_calibration.py +93 -0
  159. opentrons/hardware_control/modules/plate_temp_status.py +61 -0
  160. opentrons/hardware_control/modules/tempdeck.py +299 -0
  161. opentrons/hardware_control/modules/thermocycler.py +731 -0
  162. opentrons/hardware_control/modules/types.py +417 -0
  163. opentrons/hardware_control/modules/update.py +255 -0
  164. opentrons/hardware_control/modules/utils.py +73 -0
  165. opentrons/hardware_control/motion_utilities.py +318 -0
  166. opentrons/hardware_control/nozzle_manager.py +422 -0
  167. opentrons/hardware_control/ot3_calibration.py +1171 -0
  168. opentrons/hardware_control/ot3api.py +3227 -0
  169. opentrons/hardware_control/pause_manager.py +31 -0
  170. opentrons/hardware_control/poller.py +112 -0
  171. opentrons/hardware_control/protocols/__init__.py +106 -0
  172. opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
  173. opentrons/hardware_control/protocols/calibratable.py +45 -0
  174. opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
  175. opentrons/hardware_control/protocols/configurable.py +48 -0
  176. opentrons/hardware_control/protocols/event_sourcer.py +18 -0
  177. opentrons/hardware_control/protocols/execution_controllable.py +33 -0
  178. opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
  179. opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
  180. opentrons/hardware_control/protocols/gripper_controller.py +55 -0
  181. opentrons/hardware_control/protocols/hardware_manager.py +51 -0
  182. opentrons/hardware_control/protocols/identifiable.py +16 -0
  183. opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
  184. opentrons/hardware_control/protocols/liquid_handler.py +266 -0
  185. opentrons/hardware_control/protocols/module_provider.py +16 -0
  186. opentrons/hardware_control/protocols/motion_controller.py +243 -0
  187. opentrons/hardware_control/protocols/position_estimator.py +45 -0
  188. opentrons/hardware_control/protocols/simulatable.py +10 -0
  189. opentrons/hardware_control/protocols/stoppable.py +9 -0
  190. opentrons/hardware_control/protocols/types.py +27 -0
  191. opentrons/hardware_control/robot_calibration.py +224 -0
  192. opentrons/hardware_control/scripts/README.md +28 -0
  193. opentrons/hardware_control/scripts/__init__.py +1 -0
  194. opentrons/hardware_control/scripts/gripper_control.py +208 -0
  195. opentrons/hardware_control/scripts/ot3gripper +7 -0
  196. opentrons/hardware_control/scripts/ot3repl +7 -0
  197. opentrons/hardware_control/scripts/repl.py +187 -0
  198. opentrons/hardware_control/scripts/tc_control.py +97 -0
  199. opentrons/hardware_control/simulator_setup.py +260 -0
  200. opentrons/hardware_control/thread_manager.py +431 -0
  201. opentrons/hardware_control/threaded_async_lock.py +97 -0
  202. opentrons/hardware_control/types.py +792 -0
  203. opentrons/hardware_control/util.py +234 -0
  204. opentrons/legacy_broker.py +53 -0
  205. opentrons/legacy_commands/__init__.py +1 -0
  206. opentrons/legacy_commands/commands.py +483 -0
  207. opentrons/legacy_commands/helpers.py +153 -0
  208. opentrons/legacy_commands/module_commands.py +215 -0
  209. opentrons/legacy_commands/protocol_commands.py +54 -0
  210. opentrons/legacy_commands/publisher.py +155 -0
  211. opentrons/legacy_commands/robot_commands.py +51 -0
  212. opentrons/legacy_commands/types.py +1115 -0
  213. opentrons/motion_planning/__init__.py +32 -0
  214. opentrons/motion_planning/adjacent_slots_getters.py +168 -0
  215. opentrons/motion_planning/deck_conflict.py +396 -0
  216. opentrons/motion_planning/errors.py +35 -0
  217. opentrons/motion_planning/types.py +42 -0
  218. opentrons/motion_planning/waypoints.py +218 -0
  219. opentrons/ordered_set.py +138 -0
  220. opentrons/protocol_api/__init__.py +105 -0
  221. opentrons/protocol_api/_liquid.py +157 -0
  222. opentrons/protocol_api/_liquid_properties.py +814 -0
  223. opentrons/protocol_api/_nozzle_layout.py +31 -0
  224. opentrons/protocol_api/_parameter_context.py +300 -0
  225. opentrons/protocol_api/_parameters.py +31 -0
  226. opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
  227. opentrons/protocol_api/_types.py +43 -0
  228. opentrons/protocol_api/config.py +23 -0
  229. opentrons/protocol_api/core/__init__.py +23 -0
  230. opentrons/protocol_api/core/common.py +33 -0
  231. opentrons/protocol_api/core/core_map.py +74 -0
  232. opentrons/protocol_api/core/engine/__init__.py +22 -0
  233. opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
  234. opentrons/protocol_api/core/engine/deck_conflict.py +348 -0
  235. opentrons/protocol_api/core/engine/exceptions.py +19 -0
  236. opentrons/protocol_api/core/engine/instrument.py +2391 -0
  237. opentrons/protocol_api/core/engine/labware.py +238 -0
  238. opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
  239. opentrons/protocol_api/core/engine/module_core.py +1025 -0
  240. opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
  241. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
  242. opentrons/protocol_api/core/engine/point_calculations.py +64 -0
  243. opentrons/protocol_api/core/engine/protocol.py +1153 -0
  244. opentrons/protocol_api/core/engine/robot.py +139 -0
  245. opentrons/protocol_api/core/engine/stringify.py +74 -0
  246. opentrons/protocol_api/core/engine/transfer_components_executor.py +990 -0
  247. opentrons/protocol_api/core/engine/well.py +241 -0
  248. opentrons/protocol_api/core/instrument.py +459 -0
  249. opentrons/protocol_api/core/labware.py +151 -0
  250. opentrons/protocol_api/core/legacy/__init__.py +11 -0
  251. opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
  252. opentrons/protocol_api/core/legacy/deck.py +369 -0
  253. opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
  254. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
  255. opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
  256. opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
  257. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
  258. opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
  259. opentrons/protocol_api/core/legacy/load_info.py +67 -0
  260. opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
  261. opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
  262. opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
  263. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
  264. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
  265. opentrons/protocol_api/core/module.py +484 -0
  266. opentrons/protocol_api/core/protocol.py +311 -0
  267. opentrons/protocol_api/core/robot.py +51 -0
  268. opentrons/protocol_api/core/well.py +116 -0
  269. opentrons/protocol_api/core/well_grid.py +45 -0
  270. opentrons/protocol_api/create_protocol_context.py +177 -0
  271. opentrons/protocol_api/deck.py +223 -0
  272. opentrons/protocol_api/disposal_locations.py +244 -0
  273. opentrons/protocol_api/instrument_context.py +3212 -0
  274. opentrons/protocol_api/labware.py +1579 -0
  275. opentrons/protocol_api/module_contexts.py +1425 -0
  276. opentrons/protocol_api/module_validation_and_errors.py +61 -0
  277. opentrons/protocol_api/protocol_context.py +1688 -0
  278. opentrons/protocol_api/robot_context.py +303 -0
  279. opentrons/protocol_api/validation.py +761 -0
  280. opentrons/protocol_engine/__init__.py +155 -0
  281. opentrons/protocol_engine/actions/__init__.py +65 -0
  282. opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
  283. opentrons/protocol_engine/actions/action_handler.py +13 -0
  284. opentrons/protocol_engine/actions/actions.py +302 -0
  285. opentrons/protocol_engine/actions/get_state_update.py +38 -0
  286. opentrons/protocol_engine/clients/__init__.py +5 -0
  287. opentrons/protocol_engine/clients/sync_client.py +174 -0
  288. opentrons/protocol_engine/clients/transports.py +197 -0
  289. opentrons/protocol_engine/commands/__init__.py +757 -0
  290. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
  291. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
  292. opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
  293. opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
  294. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
  295. opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
  296. opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
  297. opentrons/protocol_engine/commands/aspirate.py +244 -0
  298. opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
  299. opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
  300. opentrons/protocol_engine/commands/blow_out.py +146 -0
  301. opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
  302. opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
  303. opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
  304. opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
  305. opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
  306. opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
  307. opentrons/protocol_engine/commands/command.py +308 -0
  308. opentrons/protocol_engine/commands/command_unions.py +974 -0
  309. opentrons/protocol_engine/commands/comment.py +57 -0
  310. opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
  311. opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
  312. opentrons/protocol_engine/commands/custom.py +67 -0
  313. opentrons/protocol_engine/commands/dispense.py +194 -0
  314. opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
  315. opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
  316. opentrons/protocol_engine/commands/drop_tip.py +232 -0
  317. opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
  318. opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
  319. opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
  320. opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
  321. opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
  322. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
  323. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
  324. opentrons/protocol_engine/commands/flex_stacker/store.py +326 -0
  325. opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
  326. opentrons/protocol_engine/commands/get_next_tip.py +134 -0
  327. opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
  328. opentrons/protocol_engine/commands/hash_command_params.py +38 -0
  329. opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
  330. opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
  331. opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
  332. opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
  333. opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
  334. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
  335. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
  336. opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
  337. opentrons/protocol_engine/commands/home.py +100 -0
  338. opentrons/protocol_engine/commands/identify_module.py +86 -0
  339. opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
  340. opentrons/protocol_engine/commands/liquid_probe.py +464 -0
  341. opentrons/protocol_engine/commands/load_labware.py +210 -0
  342. opentrons/protocol_engine/commands/load_lid.py +154 -0
  343. opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
  344. opentrons/protocol_engine/commands/load_liquid.py +95 -0
  345. opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
  346. opentrons/protocol_engine/commands/load_module.py +223 -0
  347. opentrons/protocol_engine/commands/load_pipette.py +167 -0
  348. opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
  349. opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
  350. opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
  351. opentrons/protocol_engine/commands/move_labware.py +546 -0
  352. opentrons/protocol_engine/commands/move_relative.py +102 -0
  353. opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
  354. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
  355. opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
  356. opentrons/protocol_engine/commands/move_to_well.py +119 -0
  357. opentrons/protocol_engine/commands/movement_common.py +338 -0
  358. opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
  359. opentrons/protocol_engine/commands/pipetting_common.py +443 -0
  360. opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
  361. opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
  362. opentrons/protocol_engine/commands/reload_labware.py +90 -0
  363. opentrons/protocol_engine/commands/retract_axis.py +75 -0
  364. opentrons/protocol_engine/commands/robot/__init__.py +70 -0
  365. opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -0
  366. opentrons/protocol_engine/commands/robot/common.py +18 -0
  367. opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
  368. opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
  369. opentrons/protocol_engine/commands/robot/move_to.py +94 -0
  370. opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +86 -0
  371. opentrons/protocol_engine/commands/save_position.py +109 -0
  372. opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
  373. opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
  374. opentrons/protocol_engine/commands/set_status_bar.py +89 -0
  375. opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
  376. opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
  377. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
  378. opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
  379. opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
  380. opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
  381. opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
  382. opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
  383. opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
  384. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
  385. opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
  386. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
  387. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
  388. opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
  389. opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
  390. opentrons/protocol_engine/commands/touch_tip.py +189 -0
  391. opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
  392. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
  393. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
  394. opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
  395. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
  396. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
  397. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
  398. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
  399. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
  400. opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
  401. opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
  402. opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
  403. opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
  404. opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
  405. opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
  406. opentrons/protocol_engine/create_protocol_engine.py +193 -0
  407. opentrons/protocol_engine/engine_support.py +28 -0
  408. opentrons/protocol_engine/error_recovery_policy.py +81 -0
  409. opentrons/protocol_engine/errors/__init__.py +191 -0
  410. opentrons/protocol_engine/errors/error_occurrence.py +182 -0
  411. opentrons/protocol_engine/errors/exceptions.py +1308 -0
  412. opentrons/protocol_engine/execution/__init__.py +50 -0
  413. opentrons/protocol_engine/execution/command_executor.py +216 -0
  414. opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
  415. opentrons/protocol_engine/execution/door_watcher.py +119 -0
  416. opentrons/protocol_engine/execution/equipment.py +819 -0
  417. opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
  418. opentrons/protocol_engine/execution/gantry_mover.py +686 -0
  419. opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
  420. opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
  421. opentrons/protocol_engine/execution/labware_movement.py +297 -0
  422. opentrons/protocol_engine/execution/movement.py +349 -0
  423. opentrons/protocol_engine/execution/pipetting.py +607 -0
  424. opentrons/protocol_engine/execution/queue_worker.py +86 -0
  425. opentrons/protocol_engine/execution/rail_lights.py +25 -0
  426. opentrons/protocol_engine/execution/run_control.py +33 -0
  427. opentrons/protocol_engine/execution/status_bar.py +34 -0
  428. opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
  429. opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
  430. opentrons/protocol_engine/execution/tip_handler.py +550 -0
  431. opentrons/protocol_engine/labware_offset_standardization.py +194 -0
  432. opentrons/protocol_engine/notes/__init__.py +17 -0
  433. opentrons/protocol_engine/notes/notes.py +59 -0
  434. opentrons/protocol_engine/plugins.py +104 -0
  435. opentrons/protocol_engine/protocol_engine.py +683 -0
  436. opentrons/protocol_engine/resources/__init__.py +26 -0
  437. opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
  438. opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
  439. opentrons/protocol_engine/resources/file_provider.py +161 -0
  440. opentrons/protocol_engine/resources/fixture_validation.py +58 -0
  441. opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
  442. opentrons/protocol_engine/resources/labware_validation.py +73 -0
  443. opentrons/protocol_engine/resources/model_utils.py +32 -0
  444. opentrons/protocol_engine/resources/module_data_provider.py +44 -0
  445. opentrons/protocol_engine/resources/ot3_validation.py +21 -0
  446. opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
  447. opentrons/protocol_engine/slot_standardization.py +128 -0
  448. opentrons/protocol_engine/state/__init__.py +1 -0
  449. opentrons/protocol_engine/state/_abstract_store.py +27 -0
  450. opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
  451. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  452. opentrons/protocol_engine/state/_move_types.py +83 -0
  453. opentrons/protocol_engine/state/_well_math.py +193 -0
  454. opentrons/protocol_engine/state/addressable_areas.py +699 -0
  455. opentrons/protocol_engine/state/command_history.py +309 -0
  456. opentrons/protocol_engine/state/commands.py +1158 -0
  457. opentrons/protocol_engine/state/config.py +39 -0
  458. opentrons/protocol_engine/state/files.py +57 -0
  459. opentrons/protocol_engine/state/fluid_stack.py +138 -0
  460. opentrons/protocol_engine/state/geometry.py +2359 -0
  461. opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
  462. opentrons/protocol_engine/state/labware.py +1459 -0
  463. opentrons/protocol_engine/state/liquid_classes.py +82 -0
  464. opentrons/protocol_engine/state/liquids.py +73 -0
  465. opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
  466. opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
  467. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
  468. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
  469. opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
  470. opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
  471. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
  472. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
  473. opentrons/protocol_engine/state/modules.py +1500 -0
  474. opentrons/protocol_engine/state/motion.py +373 -0
  475. opentrons/protocol_engine/state/pipettes.py +905 -0
  476. opentrons/protocol_engine/state/state.py +421 -0
  477. opentrons/protocol_engine/state/state_summary.py +36 -0
  478. opentrons/protocol_engine/state/tips.py +420 -0
  479. opentrons/protocol_engine/state/update_types.py +904 -0
  480. opentrons/protocol_engine/state/wells.py +290 -0
  481. opentrons/protocol_engine/types/__init__.py +308 -0
  482. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  483. opentrons/protocol_engine/types/command_annotations.py +53 -0
  484. opentrons/protocol_engine/types/deck_configuration.py +81 -0
  485. opentrons/protocol_engine/types/execution.py +96 -0
  486. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  487. opentrons/protocol_engine/types/instrument.py +47 -0
  488. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  489. opentrons/protocol_engine/types/labware.py +131 -0
  490. opentrons/protocol_engine/types/labware_movement.py +22 -0
  491. opentrons/protocol_engine/types/labware_offset_location.py +111 -0
  492. opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
  493. opentrons/protocol_engine/types/liquid.py +40 -0
  494. opentrons/protocol_engine/types/liquid_class.py +59 -0
  495. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  496. opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
  497. opentrons/protocol_engine/types/location.py +194 -0
  498. opentrons/protocol_engine/types/module.py +303 -0
  499. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  500. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  501. opentrons/protocol_engine/types/tip.py +18 -0
  502. opentrons/protocol_engine/types/util.py +21 -0
  503. opentrons/protocol_engine/types/well_position.py +124 -0
  504. opentrons/protocol_reader/__init__.py +37 -0
  505. opentrons/protocol_reader/extract_labware_definitions.py +66 -0
  506. opentrons/protocol_reader/file_format_validator.py +152 -0
  507. opentrons/protocol_reader/file_hasher.py +27 -0
  508. opentrons/protocol_reader/file_identifier.py +284 -0
  509. opentrons/protocol_reader/file_reader_writer.py +90 -0
  510. opentrons/protocol_reader/input_file.py +16 -0
  511. opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
  512. opentrons/protocol_reader/protocol_reader.py +188 -0
  513. opentrons/protocol_reader/protocol_source.py +124 -0
  514. opentrons/protocol_reader/role_analyzer.py +86 -0
  515. opentrons/protocol_runner/__init__.py +26 -0
  516. opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
  517. opentrons/protocol_runner/json_file_reader.py +55 -0
  518. opentrons/protocol_runner/json_translator.py +314 -0
  519. opentrons/protocol_runner/legacy_command_mapper.py +848 -0
  520. opentrons/protocol_runner/legacy_context_plugin.py +116 -0
  521. opentrons/protocol_runner/protocol_runner.py +530 -0
  522. opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
  523. opentrons/protocol_runner/run_orchestrator.py +496 -0
  524. opentrons/protocol_runner/task_queue.py +95 -0
  525. opentrons/protocols/__init__.py +6 -0
  526. opentrons/protocols/advanced_control/__init__.py +0 -0
  527. opentrons/protocols/advanced_control/common.py +38 -0
  528. opentrons/protocols/advanced_control/mix.py +60 -0
  529. opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
  530. opentrons/protocols/advanced_control/transfers/common.py +180 -0
  531. opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
  532. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
  533. opentrons/protocols/api_support/__init__.py +0 -0
  534. opentrons/protocols/api_support/constants.py +8 -0
  535. opentrons/protocols/api_support/deck_type.py +110 -0
  536. opentrons/protocols/api_support/definitions.py +18 -0
  537. opentrons/protocols/api_support/instrument.py +151 -0
  538. opentrons/protocols/api_support/labware_like.py +233 -0
  539. opentrons/protocols/api_support/tip_tracker.py +175 -0
  540. opentrons/protocols/api_support/types.py +32 -0
  541. opentrons/protocols/api_support/util.py +403 -0
  542. opentrons/protocols/bundle.py +89 -0
  543. opentrons/protocols/duration/__init__.py +4 -0
  544. opentrons/protocols/duration/errors.py +5 -0
  545. opentrons/protocols/duration/estimator.py +628 -0
  546. opentrons/protocols/execution/__init__.py +0 -0
  547. opentrons/protocols/execution/dev_types.py +181 -0
  548. opentrons/protocols/execution/errors.py +40 -0
  549. opentrons/protocols/execution/execute.py +84 -0
  550. opentrons/protocols/execution/execute_json_v3.py +275 -0
  551. opentrons/protocols/execution/execute_json_v4.py +359 -0
  552. opentrons/protocols/execution/execute_json_v5.py +28 -0
  553. opentrons/protocols/execution/execute_python.py +169 -0
  554. opentrons/protocols/execution/json_dispatchers.py +87 -0
  555. opentrons/protocols/execution/types.py +7 -0
  556. opentrons/protocols/geometry/__init__.py +0 -0
  557. opentrons/protocols/geometry/planning.py +297 -0
  558. opentrons/protocols/labware.py +312 -0
  559. opentrons/protocols/models/__init__.py +0 -0
  560. opentrons/protocols/models/json_protocol.py +679 -0
  561. opentrons/protocols/parameters/__init__.py +0 -0
  562. opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
  563. opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
  564. opentrons/protocols/parameters/exceptions.py +34 -0
  565. opentrons/protocols/parameters/parameter_definition.py +272 -0
  566. opentrons/protocols/parameters/types.py +17 -0
  567. opentrons/protocols/parameters/validation.py +267 -0
  568. opentrons/protocols/parse.py +671 -0
  569. opentrons/protocols/types.py +159 -0
  570. opentrons/py.typed +0 -0
  571. opentrons/resources/scripts/lpc21isp +0 -0
  572. opentrons/resources/smoothie-edge-8414642.hex +23010 -0
  573. opentrons/simulate.py +1065 -0
  574. opentrons/system/__init__.py +6 -0
  575. opentrons/system/camera.py +51 -0
  576. opentrons/system/log_control.py +59 -0
  577. opentrons/system/nmcli.py +856 -0
  578. opentrons/system/resin.py +24 -0
  579. opentrons/system/smoothie_update.py +15 -0
  580. opentrons/system/wifi.py +204 -0
  581. opentrons/tools/__init__.py +0 -0
  582. opentrons/tools/args_handler.py +22 -0
  583. opentrons/tools/write_pipette_memory.py +157 -0
  584. opentrons/types.py +618 -0
  585. opentrons/util/__init__.py +1 -0
  586. opentrons/util/async_helpers.py +166 -0
  587. opentrons/util/broker.py +84 -0
  588. opentrons/util/change_notifier.py +47 -0
  589. opentrons/util/entrypoint_util.py +278 -0
  590. opentrons/util/get_union_elements.py +26 -0
  591. opentrons/util/helpers.py +6 -0
  592. opentrons/util/linal.py +178 -0
  593. opentrons/util/logging_config.py +265 -0
  594. opentrons/util/logging_queue_handler.py +61 -0
  595. opentrons/util/performance_helpers.py +157 -0
  596. opentrons-8.6.0a1.dist-info/METADATA +37 -0
  597. opentrons-8.6.0a1.dist-info/RECORD +600 -0
  598. opentrons-8.6.0a1.dist-info/WHEEL +4 -0
  599. opentrons-8.6.0a1.dist-info/entry_points.txt +3 -0
  600. opentrons-8.6.0a1.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,1425 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from typing import List, Dict, Optional, Union, cast, Iterator, Sequence
5
+
6
+ from opentrons_shared_data.errors.exceptions import CommandPreconditionViolated
7
+
8
+ from opentrons.protocol_engine.types import ABSMeasureMode
9
+ from opentrons_shared_data.labware.types import LabwareDefinition
10
+ from opentrons_shared_data.module.types import ModuleModel, ModuleType
11
+
12
+ from opentrons.legacy_broker import LegacyBroker
13
+ from opentrons.legacy_commands import module_commands as cmds
14
+ from opentrons.legacy_commands.publisher import CommandPublisher, publish
15
+ from opentrons.protocols.api_support.types import APIVersion, ThermocyclerStep
16
+ from opentrons.protocols.api_support.util import (
17
+ APIVersionError,
18
+ requires_version,
19
+ UnsupportedAPIError,
20
+ )
21
+
22
+ from .core.common import (
23
+ ProtocolCore,
24
+ LabwareCore,
25
+ ModuleCore,
26
+ TemperatureModuleCore,
27
+ MagneticModuleCore,
28
+ ThermocyclerCore,
29
+ HeaterShakerCore,
30
+ MagneticBlockCore,
31
+ AbsorbanceReaderCore,
32
+ FlexStackerCore,
33
+ )
34
+ from .core.core_map import LoadedCoreMap
35
+ from .core.engine import ENGINE_CORE_API_VERSION
36
+ from .core.legacy.legacy_module_core import LegacyModuleCore
37
+ from .core.legacy.module_geometry import ModuleGeometry as LegacyModuleGeometry
38
+ from .core.legacy.legacy_labware_core import LegacyLabwareCore as LegacyLabwareCore
39
+
40
+ from .module_validation_and_errors import (
41
+ validate_heater_shaker_temperature,
42
+ validate_heater_shaker_speed,
43
+ )
44
+ from .labware import Labware
45
+ from . import validation
46
+
47
+
48
+ _MAGNETIC_MODULE_HEIGHT_PARAM_REMOVED_IN = APIVersion(2, 14)
49
+
50
+
51
+ _log = logging.getLogger(__name__)
52
+
53
+
54
+ class ModuleContext(CommandPublisher):
55
+ """A connected module in the protocol.
56
+
57
+ .. versionadded:: 2.0
58
+ """
59
+
60
+ def __init__(
61
+ self,
62
+ core: ModuleCore,
63
+ protocol_core: ProtocolCore,
64
+ core_map: LoadedCoreMap,
65
+ api_version: APIVersion,
66
+ broker: LegacyBroker,
67
+ ) -> None:
68
+ super().__init__(broker=broker)
69
+ self._core = core
70
+ self._protocol_core = protocol_core
71
+ self._core_map = core_map
72
+ self._api_version = api_version
73
+
74
+ @property
75
+ @requires_version(2, 0)
76
+ def api_version(self) -> APIVersion:
77
+ return self._api_version
78
+
79
+ @property
80
+ @requires_version(2, 14)
81
+ def model(self) -> ModuleModel:
82
+ """Get the module's model identifier."""
83
+ return cast(ModuleModel, self._core.get_model().value)
84
+
85
+ @property
86
+ @requires_version(2, 14)
87
+ def type(self) -> ModuleType:
88
+ """Get the module's general type identifier."""
89
+ return self._get_type()
90
+
91
+ def _get_type(self) -> ModuleType:
92
+ return cast(ModuleType, self._core.MODULE_TYPE.value)
93
+
94
+ @requires_version(2, 0)
95
+ def load_labware_object(self, labware: Labware) -> Labware:
96
+ """Specify the presence of a piece of labware on the module.
97
+
98
+ :param labware: The labware object. This object should be already
99
+ initialized and its parent should be set to this
100
+ module's geometry. To initialize and load a labware
101
+ onto the module in one step, see
102
+ :py:meth:`load_labware`.
103
+ :returns: The properly-linked labware object
104
+
105
+ .. deprecated:: 2.14
106
+ Use :py:meth:`load_labware` or :py:meth:`load_labware_by_definition`.
107
+ """
108
+ if not isinstance(self._core, LegacyModuleCore):
109
+ raise UnsupportedAPIError(
110
+ api_element="`ModuleContext.load_labware_object`",
111
+ since_version="2.14",
112
+ extra_message="Use `ModuleContext.load_labware` or `load_labware_by_definition` instead.",
113
+ )
114
+
115
+ _log.warning(
116
+ "`ModuleContext.load_labware_object` is an internal, deprecated method. Use `ModuleContext.load_labware` or `load_labware_by_definition` instead."
117
+ )
118
+ core = cast(LegacyModuleCore, self._core)
119
+
120
+ assert (
121
+ labware.parent == core.geometry
122
+ ), "Labware is not configured with this module as its parent"
123
+
124
+ return core.geometry.add_labware(labware)
125
+
126
+ def load_labware(
127
+ self,
128
+ name: str,
129
+ label: Optional[str] = None,
130
+ namespace: Optional[str] = None,
131
+ version: Optional[int] = None,
132
+ adapter: Optional[str] = None,
133
+ lid: Optional[str] = None,
134
+ ) -> Labware:
135
+ """Load a labware onto the module using its load parameters.
136
+
137
+ The parameters of this function behave like those of
138
+ :py:obj:`ProtocolContext.load_labware` (which loads labware directly
139
+ onto the deck). Note that the parameter ``name`` here corresponds to
140
+ ``load_name`` on the ``ProtocolContext`` function.
141
+
142
+ :returns: The initialized and loaded labware object.
143
+
144
+ .. versionadded:: 2.1
145
+ The *label,* *namespace,* and *version* parameters.
146
+ """
147
+ if self._api_version < APIVersion(2, 1) and (
148
+ label is not None or namespace is not None or version != 1
149
+ ):
150
+ _log.warning(
151
+ f"You have specified API {self.api_version}, but you "
152
+ "are trying to utilize new load_labware parameters in 2.1"
153
+ )
154
+
155
+ load_location: Union[ModuleCore, LabwareCore]
156
+ if adapter is not None:
157
+ if self._api_version < APIVersion(2, 15):
158
+ raise APIVersionError(
159
+ api_element="Loading a labware on an adapter",
160
+ until_version="2.15",
161
+ current_version=f"{self._api_version}",
162
+ )
163
+ loaded_adapter = self.load_adapter(
164
+ name=adapter,
165
+ namespace=namespace,
166
+ )
167
+ load_location = loaded_adapter._core
168
+ else:
169
+ load_location = self._core
170
+
171
+ name = validation.ensure_lowercase_name(name)
172
+
173
+ # todo(mm, 2024-11-08): This check belongs in opentrons.protocol_api.core.engine.deck_conflict.
174
+ # We're currently doing it here, at the ModuleContext level, for consistency with what
175
+ # ProtocolContext.load_labware() does. (It should also be moved to the deck_conflict module.)
176
+ if self._get_type() == "absorbanceReaderType":
177
+ if cast(AbsorbanceReaderCore, self._core).is_lid_on():
178
+ raise CommandPreconditionViolated(
179
+ f"Cannot load {name} onto the Absorbance Reader Module when its lid is closed."
180
+ )
181
+
182
+ labware_core = self._protocol_core.load_labware(
183
+ load_name=name,
184
+ label=label if label is None else str(label),
185
+ namespace=namespace,
186
+ version=version,
187
+ location=load_location,
188
+ )
189
+ if lid is not None:
190
+ if self._api_version < validation.LID_STACK_VERSION_GATE:
191
+ raise APIVersionError(
192
+ api_element="Loading a lid on a Labware",
193
+ until_version="2.23",
194
+ current_version=f"{self._api_version}",
195
+ )
196
+ self._protocol_core.load_lid(
197
+ load_name=lid,
198
+ location=labware_core,
199
+ namespace=namespace,
200
+ version=version,
201
+ )
202
+
203
+ if isinstance(self._core, LegacyModuleCore):
204
+ labware = cast(LegacyModuleCore, self._core).add_labware_core(
205
+ cast(LegacyLabwareCore, labware_core)
206
+ )
207
+ else:
208
+ labware = Labware(
209
+ core=labware_core,
210
+ api_version=self._api_version,
211
+ protocol_core=self._protocol_core,
212
+ core_map=self._core_map,
213
+ )
214
+
215
+ self._core_map.add(labware_core, labware)
216
+
217
+ return labware
218
+
219
+ @requires_version(2, 0)
220
+ def load_labware_from_definition(
221
+ self, definition: LabwareDefinition, label: Optional[str] = None
222
+ ) -> Labware:
223
+ """Load a labware onto the module using an inline definition.
224
+
225
+ :param definition: The labware definition.
226
+ :param str label: An optional special name to give the labware. If
227
+ specified, this is the name the labware will appear
228
+ as in the run log and the calibration view in the
229
+ Opentrons app.
230
+ :returns: The initialized and loaded labware object.
231
+ """
232
+ load_params = self._protocol_core.add_labware_definition(definition)
233
+
234
+ return self.load_labware(
235
+ name=load_params.load_name,
236
+ namespace=load_params.namespace,
237
+ version=load_params.version,
238
+ label=label,
239
+ )
240
+
241
+ @requires_version(2, 1)
242
+ def load_labware_by_name(
243
+ self,
244
+ name: str,
245
+ label: Optional[str] = None,
246
+ namespace: Optional[str] = None,
247
+ version: Optional[int] = None,
248
+ ) -> Labware:
249
+ """
250
+ .. deprecated:: 2.0
251
+ Use :py:meth:`load_labware` instead.
252
+ """
253
+ _log.warning("load_labware_by_name is deprecated. Use load_labware instead.")
254
+ return self.load_labware(
255
+ name=name,
256
+ label=label,
257
+ namespace=namespace,
258
+ version=version,
259
+ )
260
+
261
+ @requires_version(2, 15)
262
+ def load_adapter(
263
+ self,
264
+ name: str,
265
+ namespace: Optional[str] = None,
266
+ version: Optional[int] = None,
267
+ ) -> Labware:
268
+ """Load an adapter onto the module using its load parameters.
269
+
270
+ The parameters of this function behave like those of
271
+ :py:obj:`ProtocolContext.load_adapter` (which loads adapters directly
272
+ onto the deck). Note that the parameter ``name`` here corresponds to
273
+ ``load_name`` on the ``ProtocolContext`` function.
274
+
275
+ :returns: The initialized and loaded adapter object.
276
+ """
277
+ labware_core = self._protocol_core.load_adapter(
278
+ load_name=name,
279
+ namespace=namespace,
280
+ version=version,
281
+ location=self._core,
282
+ )
283
+
284
+ if isinstance(self._core, LegacyModuleCore):
285
+ adapter = cast(LegacyModuleCore, self._core).add_labware_core(
286
+ cast(LegacyLabwareCore, labware_core)
287
+ )
288
+ else:
289
+ adapter = Labware(
290
+ core=labware_core,
291
+ api_version=self._api_version,
292
+ protocol_core=self._protocol_core,
293
+ core_map=self._core_map,
294
+ )
295
+
296
+ self._core_map.add(labware_core, adapter)
297
+
298
+ return adapter
299
+
300
+ @requires_version(2, 15)
301
+ def load_adapter_from_definition(self, definition: LabwareDefinition) -> Labware:
302
+ """Load an adapter onto the module using an inline definition.
303
+
304
+ :param definition: The labware definition.
305
+ :returns: The initialized and loaded labware object.
306
+ """
307
+ load_params = self._protocol_core.add_labware_definition(definition)
308
+
309
+ return self.load_adapter(
310
+ name=load_params.load_name,
311
+ namespace=load_params.namespace,
312
+ version=load_params.version,
313
+ )
314
+
315
+ @property
316
+ @requires_version(2, 0)
317
+ def labware(self) -> Optional[Labware]:
318
+ """The labware (if any) present on this module."""
319
+ labware_core = self._protocol_core.get_labware_on_module(self._core)
320
+ return self._core_map.get(labware_core)
321
+
322
+ @property
323
+ @requires_version(2, 14)
324
+ def parent(self) -> str:
325
+ """The name of the slot the module is on.
326
+
327
+ On a Flex, this will be like ``"D1"``. On an OT-2, this will be like ``"1"``.
328
+ See :ref:`deck-slots`.
329
+ """
330
+ return self._core.get_deck_slot_id()
331
+
332
+ @property
333
+ @requires_version(2, 0)
334
+ def geometry(self) -> LegacyModuleGeometry:
335
+ """The object representing the module as an item on the deck.
336
+
337
+ .. deprecated:: 2.14
338
+ Use properties of the :py:class:`ModuleContext` instead,
339
+ like :py:meth:`model` and :py:meth:`type`
340
+ """
341
+ if isinstance(self._core, LegacyModuleCore):
342
+ return cast(LegacyModuleCore, self._core).geometry
343
+
344
+ raise UnsupportedAPIError(
345
+ api_element="`ModuleContext.geometry`",
346
+ since_version="2.14",
347
+ extra_message="Use properties of the `ModuleContext` itself.",
348
+ )
349
+
350
+ def __repr__(self) -> str:
351
+ class_name = self.__class__.__name__
352
+ display_name = self._core.get_display_name()
353
+ location = self._core.get_deck_slot().id
354
+
355
+ return f"{class_name} at {display_name} on {location} lw {self.labware}"
356
+
357
+
358
+ class TemperatureModuleContext(ModuleContext):
359
+ """An object representing a connected Temperature Module.
360
+
361
+ It should not be instantiated directly; instead, it should be
362
+ created through :py:meth:`.ProtocolContext.load_module`.
363
+
364
+ .. versionadded:: 2.0
365
+
366
+ """
367
+
368
+ _core: TemperatureModuleCore
369
+
370
+ @property
371
+ @requires_version(2, 14)
372
+ def serial_number(self) -> str:
373
+ """Get the module's unique hardware serial number."""
374
+ return self._core.get_serial_number()
375
+
376
+ @publish(command=cmds.tempdeck_set_temp)
377
+ @requires_version(2, 0)
378
+ def set_temperature(self, celsius: float) -> None:
379
+ """Set a target temperature and wait until the module reaches the target.
380
+
381
+ No other protocol commands will execute while waiting for the temperature.
382
+
383
+ :param celsius: A value between 4 and 95, representing the target temperature in °C.
384
+ """
385
+ self._core.set_target_temperature(celsius)
386
+ self._core.wait_for_target_temperature()
387
+
388
+ @publish(command=cmds.tempdeck_set_temp)
389
+ @requires_version(2, 3)
390
+ def start_set_temperature(self, celsius: float) -> None:
391
+ """Set the target temperature without waiting for the target to be hit.
392
+
393
+ :param celsius: A value between 4 and 95, representing the target temperature in °C.
394
+ """
395
+ self._core.set_target_temperature(celsius)
396
+
397
+ @publish(command=cmds.tempdeck_await_temp)
398
+ @requires_version(2, 3)
399
+ def await_temperature(self, celsius: float) -> None:
400
+ """Wait until module reaches temperature.
401
+
402
+ :param celsius: A value between 4 and 95, representing the target temperature in °C.
403
+ """
404
+ self._core.wait_for_target_temperature(celsius)
405
+
406
+ @publish(command=cmds.tempdeck_deactivate)
407
+ @requires_version(2, 0)
408
+ def deactivate(self) -> None:
409
+ """Stop heating or cooling, and turn off the fan."""
410
+ self._core.deactivate()
411
+
412
+ @property
413
+ @requires_version(2, 0)
414
+ def temperature(self) -> float:
415
+ """The current temperature of the Temperature Module's deck in °C.
416
+
417
+ Returns ``0`` in simulation if no target temperature has been set.
418
+ """
419
+ return self._core.get_current_temperature()
420
+
421
+ @property
422
+ @requires_version(2, 0)
423
+ def target(self) -> Optional[float]:
424
+ """The target temperature of the Temperature Module's deck in °C.
425
+
426
+ Returns ``None`` if no target has been set.
427
+ """
428
+ return self._core.get_target_temperature()
429
+
430
+ @property
431
+ @requires_version(2, 3)
432
+ def status(self) -> str:
433
+ """One of four possible temperature statuses:
434
+
435
+ - ``holding at target`` – The module has reached its target temperature
436
+ and is actively maintaining that temperature.
437
+ - ``cooling`` – The module is cooling to a target temperature.
438
+ - ``heating`` – The module is heating to a target temperature.
439
+ - ``idle`` – The module has been deactivated.
440
+ """
441
+ return self._core.get_status().value
442
+
443
+
444
+ class MagneticModuleContext(ModuleContext):
445
+ """An object representing a connected Magnetic Module.
446
+
447
+ It should not be instantiated directly; instead, it should be
448
+ created through :py:meth:`.ProtocolContext.load_module`.
449
+
450
+ .. versionadded:: 2.0
451
+ """
452
+
453
+ _core: MagneticModuleCore
454
+
455
+ @property
456
+ @requires_version(2, 14)
457
+ def serial_number(self) -> str:
458
+ """Get the module's unique hardware serial number."""
459
+ return self._core.get_serial_number()
460
+
461
+ @publish(command=cmds.magdeck_calibrate)
462
+ @requires_version(2, 0)
463
+ def calibrate(self) -> None:
464
+ """Calibrate the Magnetic Module.
465
+
466
+ .. deprecated:: 2.14
467
+ This method is unnecessary; remove any usage.
468
+ """
469
+ if self._api_version < ENGINE_CORE_API_VERSION:
470
+ _log.warning(
471
+ "`MagneticModuleContext.calibrate` doesn't do anything useful"
472
+ " and will be removed in Protocol API version 2.14 and higher."
473
+ )
474
+ self._core._sync_module_hardware.calibrate() # type: ignore[attr-defined]
475
+ else:
476
+ raise UnsupportedAPIError(
477
+ api_element="`MagneticModuleContext.calibrate`",
478
+ since_version="2.14",
479
+ )
480
+
481
+ @publish(command=cmds.magdeck_engage)
482
+ @requires_version(2, 0)
483
+ def engage(
484
+ self,
485
+ height: Optional[float] = None,
486
+ offset: Optional[float] = None,
487
+ height_from_base: Optional[float] = None,
488
+ ) -> None:
489
+ """Raise the Magnetic Module's magnets. You can specify how high the magnets
490
+ should move:
491
+
492
+ - No parameter: Move to the default height for the loaded labware. If
493
+ the loaded labware has no default, or if no labware is loaded, this will
494
+ raise an error.
495
+
496
+ - ``height_from_base`` – Move this many millimeters above the bottom
497
+ of the labware. Acceptable values are between ``0`` and ``25``.
498
+
499
+ This is the recommended way to adjust the magnets' height.
500
+
501
+ .. versionadded:: 2.2
502
+
503
+ - ``offset`` – Move this many millimeters above (positive value) or below
504
+ (negative value) the default height for the loaded labware. The sum of
505
+ the default height and ``offset`` must be between 0 and 25.
506
+
507
+ - ``height`` – Intended to move this many millimeters above the magnets'
508
+ home position. However, depending on the generation of module and the loaded
509
+ labware, this may produce unpredictable results. You should normally use
510
+ ``height_from_base`` instead.
511
+
512
+ .. versionchanged:: 2.14
513
+ This parameter has been removed.
514
+
515
+ You shouldn't specify more than one of these parameters. However, if you do,
516
+ their order of precedence is ``height``, then ``height_from_base``, then ``offset``.
517
+ """
518
+ if height is not None:
519
+ if self._api_version >= _MAGNETIC_MODULE_HEIGHT_PARAM_REMOVED_IN:
520
+ raise UnsupportedAPIError(
521
+ api_element="The height parameter of MagneticModuleContext.engage()",
522
+ since_version=f"{_MAGNETIC_MODULE_HEIGHT_PARAM_REMOVED_IN}",
523
+ current_version=f"{self._api_version}",
524
+ extra_message="Use offset or height_from_base.",
525
+ )
526
+ self._core.engage(height_from_home=height)
527
+
528
+ # This version check has a bug:
529
+ # if the caller sets height_from_base in an API version that's too low,
530
+ # we will silently ignore it instead of raising APIVersionError.
531
+ # Leaving this unfixed because we haven't thought through
532
+ # how to do backwards-compatible fixes to our version checking itself.
533
+ elif height_from_base is not None and self._api_version >= APIVersion(2, 2):
534
+ self._core.engage(height_from_base=height_from_base)
535
+
536
+ else:
537
+ self._core.engage_to_labware(
538
+ offset=offset or 0,
539
+ preserve_half_mm=self._api_version < APIVersion(2, 3),
540
+ )
541
+
542
+ @publish(command=cmds.magdeck_disengage)
543
+ @requires_version(2, 0)
544
+ def disengage(self) -> None:
545
+ """Lower the magnets back into the Magnetic Module."""
546
+ self._core.disengage()
547
+
548
+ @property
549
+ @requires_version(2, 0)
550
+ def status(self) -> str:
551
+ """The status of the module, either ``engaged`` or ``disengaged``."""
552
+ return self._core.get_status().value
553
+
554
+
555
+ class ThermocyclerContext(ModuleContext):
556
+ """An object representing a connected Thermocycler Module.
557
+
558
+ It should not be instantiated directly; instead, it should be
559
+ created through :py:meth:`.ProtocolContext.load_module`.
560
+
561
+ .. versionadded:: 2.0
562
+ """
563
+
564
+ _core: ThermocyclerCore
565
+
566
+ @property
567
+ @requires_version(2, 14)
568
+ def serial_number(self) -> str:
569
+ """Get the module's unique hardware serial number."""
570
+ return self._core.get_serial_number()
571
+
572
+ @publish(command=cmds.thermocycler_open)
573
+ @requires_version(2, 0)
574
+ def open_lid(self) -> str:
575
+ """Open the lid."""
576
+ return self._core.open_lid().value
577
+
578
+ @publish(command=cmds.thermocycler_close)
579
+ @requires_version(2, 0)
580
+ def close_lid(self) -> str:
581
+ """Close the lid."""
582
+ return self._core.close_lid().value
583
+
584
+ @publish(command=cmds.thermocycler_set_block_temp)
585
+ @requires_version(2, 0)
586
+ def set_block_temperature(
587
+ self,
588
+ temperature: float,
589
+ hold_time_seconds: Optional[float] = None,
590
+ hold_time_minutes: Optional[float] = None,
591
+ ramp_rate: Optional[float] = None,
592
+ block_max_volume: Optional[float] = None,
593
+ ) -> None:
594
+ """Set the target temperature for the well block, in °C.
595
+
596
+ :param temperature: A value between 4 and 99, representing the target
597
+ temperature in °C.
598
+ :param hold_time_minutes: The number of minutes to hold, after reaching
599
+ ``temperature``, before proceeding to the
600
+ next command. If ``hold_time_seconds`` is also
601
+ specified, the times are added together.
602
+ :param hold_time_seconds: The number of seconds to hold, after reaching
603
+ ``temperature``, before proceeding to the
604
+ next command. If ``hold_time_minutes`` is also
605
+ specified, the times are added together.
606
+ :param block_max_volume: The greatest volume of liquid contained in any
607
+ individual well of the loaded labware, in µL.
608
+ If not specified, the default is 25 µL.
609
+
610
+ .. note::
611
+
612
+ If ``hold_time_minutes`` and ``hold_time_seconds`` are not
613
+ specified, the Thermocycler will proceed to the next command
614
+ immediately after ``temperature`` is reached.
615
+ """
616
+ seconds = validation.ensure_hold_time_seconds(
617
+ seconds=hold_time_seconds, minutes=hold_time_minutes
618
+ )
619
+ self._core.set_target_block_temperature(
620
+ celsius=temperature,
621
+ hold_time_seconds=seconds,
622
+ block_max_volume=block_max_volume,
623
+ )
624
+ self._core.wait_for_block_temperature()
625
+
626
+ @publish(command=cmds.thermocycler_set_lid_temperature)
627
+ @requires_version(2, 0)
628
+ def set_lid_temperature(self, temperature: float) -> None:
629
+ """Set the target temperature for the heated lid, in °C.
630
+
631
+ :param temperature: A value between 37 and 110, representing the target
632
+ temperature in °C.
633
+
634
+ .. note::
635
+
636
+ The Thermocycler will proceed to the next command immediately after
637
+ ``temperature`` is reached.
638
+
639
+ """
640
+ self._core.set_target_lid_temperature(celsius=temperature)
641
+ self._core.wait_for_lid_temperature()
642
+
643
+ @publish(command=cmds.thermocycler_execute_profile)
644
+ @requires_version(2, 0)
645
+ def execute_profile(
646
+ self,
647
+ steps: List[ThermocyclerStep],
648
+ repetitions: int,
649
+ block_max_volume: Optional[float] = None,
650
+ ) -> None:
651
+ """Execute a Thermocycler profile, defined as a cycle of
652
+ ``steps``, for a given number of ``repetitions``.
653
+
654
+ :param steps: List of steps that make up a single cycle.
655
+ Each list item should be a dictionary that maps to the parameters
656
+ of the :py:meth:`set_block_temperature` method. The dictionary's
657
+ keys must be ``temperature`` and one or both of
658
+ ``hold_time_seconds`` and ``hold_time_minutes``.
659
+ :param repetitions: The number of times to repeat the cycled steps.
660
+ :param block_max_volume: The greatest volume of liquid contained in any
661
+ individual well of the loaded labware, in µL.
662
+ If not specified, the default is 25 µL.
663
+
664
+ .. versionchanged:: 2.21
665
+ Fixed run log listing number of steps instead of number of repetitions.
666
+
667
+ """
668
+ repetitions = validation.ensure_thermocycler_repetition_count(repetitions)
669
+ validated_steps = validation.ensure_thermocycler_profile_steps(steps)
670
+ self._core.execute_profile(
671
+ steps=validated_steps,
672
+ repetitions=repetitions,
673
+ block_max_volume=block_max_volume,
674
+ )
675
+
676
+ @publish(command=cmds.thermocycler_deactivate_lid)
677
+ @requires_version(2, 0)
678
+ def deactivate_lid(self) -> None:
679
+ """Turn off the lid heater."""
680
+ self._core.deactivate_lid()
681
+
682
+ @publish(command=cmds.thermocycler_deactivate_block)
683
+ @requires_version(2, 0)
684
+ def deactivate_block(self) -> None:
685
+ """Turn off the well block temperature controller."""
686
+ self._core.deactivate_block()
687
+
688
+ @publish(command=cmds.thermocycler_deactivate)
689
+ @requires_version(2, 0)
690
+ def deactivate(self) -> None:
691
+ """Turn off both the well block temperature controller and the lid heater."""
692
+ self._core.deactivate()
693
+
694
+ @property
695
+ @requires_version(2, 0)
696
+ def lid_position(self) -> Optional[str]:
697
+ """One of these possible lid statuses:
698
+
699
+ - ``closed`` – The lid is closed.
700
+ - ``in_between`` – The lid is neither open nor closed.
701
+ - ``open`` – The lid is open.
702
+ - ``unknown`` – The lid position can't be determined.
703
+ """
704
+ status = self._core.get_lid_position()
705
+ return status.value if status is not None else None
706
+
707
+ @property
708
+ @requires_version(2, 0)
709
+ def block_temperature_status(self) -> str:
710
+ """One of five possible temperature statuses:
711
+
712
+ - ``holding at target`` – The block has reached its target temperature
713
+ and is actively maintaining that temperature.
714
+ - ``cooling`` – The block is cooling to a target temperature.
715
+ - ``heating`` – The block is heating to a target temperature.
716
+ - ``idle`` – The block is not currently heating or cooling.
717
+ - ``error`` – The temperature status can't be determined.
718
+ """
719
+ return self._core.get_block_temperature_status().value
720
+
721
+ @property
722
+ @requires_version(2, 0)
723
+ def lid_temperature_status(self) -> Optional[str]:
724
+ """One of five possible temperature statuses:
725
+
726
+ - ``holding at target`` – The lid has reached its target temperature
727
+ and is actively maintaining that temperature.
728
+ - ``cooling`` – The lid has previously heated and is now passively cooling.
729
+ `The Thermocycler lid does not have active cooling.`
730
+ - ``heating`` – The lid is heating to a target temperature.
731
+ - ``idle`` – The lid has not heated since the beginning of the protocol.
732
+ - ``error`` – The temperature status can't be determined.
733
+ """
734
+ status = self._core.get_lid_temperature_status()
735
+ return status.value if status is not None else None
736
+
737
+ @property
738
+ @requires_version(2, 0)
739
+ def block_temperature(self) -> Optional[float]:
740
+ """The current temperature of the well block in °C."""
741
+ return self._core.get_block_temperature()
742
+
743
+ @property
744
+ @requires_version(2, 0)
745
+ def block_target_temperature(self) -> Optional[float]:
746
+ """The target temperature of the well block in °C."""
747
+ return self._core.get_block_target_temperature()
748
+
749
+ @property
750
+ @requires_version(2, 0)
751
+ def lid_temperature(self) -> Optional[float]:
752
+ """The current temperature of the lid in °C."""
753
+ return self._core.get_lid_temperature()
754
+
755
+ @property
756
+ @requires_version(2, 0)
757
+ def lid_target_temperature(self) -> Optional[float]:
758
+ """The target temperature of the lid in °C."""
759
+ return self._core.get_lid_target_temperature()
760
+
761
+ @property
762
+ @requires_version(2, 0)
763
+ def ramp_rate(self) -> Optional[float]:
764
+ """The current ramp rate in °C/s."""
765
+ return self._core.get_ramp_rate()
766
+
767
+ @property
768
+ @requires_version(2, 0)
769
+ def hold_time(self) -> Optional[float]:
770
+ """Remaining hold time in seconds."""
771
+ return self._core.get_hold_time()
772
+
773
+ @property
774
+ @requires_version(2, 0)
775
+ def total_cycle_count(self) -> Optional[int]:
776
+ """Number of repetitions for current set cycle"""
777
+ return self._core.get_total_cycle_count()
778
+
779
+ @property
780
+ @requires_version(2, 0)
781
+ def current_cycle_index(self) -> Optional[int]:
782
+ """Index of the current set cycle repetition"""
783
+ return self._core.get_current_cycle_index()
784
+
785
+ @property
786
+ @requires_version(2, 0)
787
+ def total_step_count(self) -> Optional[int]:
788
+ """Number of steps within the current cycle"""
789
+ return self._core.get_total_step_count()
790
+
791
+ @property
792
+ @requires_version(2, 0)
793
+ def current_step_index(self) -> Optional[int]:
794
+ """Index of the current step within the current cycle"""
795
+ return self._core.get_current_step_index()
796
+
797
+
798
+ class HeaterShakerContext(ModuleContext):
799
+ """An object representing a connected Heater-Shaker Module.
800
+
801
+ It should not be instantiated directly; instead, it should be
802
+ created through :py:meth:`.ProtocolContext.load_module`.
803
+
804
+ .. versionadded:: 2.13
805
+ """
806
+
807
+ _core: HeaterShakerCore
808
+
809
+ @property
810
+ @requires_version(2, 14)
811
+ def serial_number(self) -> str:
812
+ """Get the module's unique hardware serial number."""
813
+ return self._core.get_serial_number()
814
+
815
+ @property
816
+ @requires_version(2, 13)
817
+ def target_temperature(self) -> Optional[float]:
818
+ """The target temperature of the Heater-Shaker's plate in °C.
819
+
820
+ Returns ``None`` if no target has been set.
821
+ """
822
+ return self._core.get_target_temperature()
823
+
824
+ @property
825
+ @requires_version(2, 13)
826
+ def current_temperature(self) -> float:
827
+ """The current temperature of the Heater-Shaker's plate in °C.
828
+
829
+ Returns ``23`` in simulation if no target temperature has been set.
830
+ """
831
+ return self._core.get_current_temperature()
832
+
833
+ @property
834
+ @requires_version(2, 13)
835
+ def current_speed(self) -> int:
836
+ """The current speed of the Heater-Shaker's plate in rpm."""
837
+ return self._core.get_current_speed()
838
+
839
+ @property
840
+ @requires_version(2, 13)
841
+ def target_speed(self) -> Optional[int]:
842
+ """Target speed of the Heater-Shaker's plate in rpm."""
843
+ return self._core.get_target_speed()
844
+
845
+ @property
846
+ @requires_version(2, 13)
847
+ def temperature_status(self) -> str:
848
+ """One of five possible temperature statuses:
849
+
850
+ - ``holding at target`` – The module has reached its target temperature
851
+ and is actively maintaining that temperature.
852
+ - ``cooling`` – The module has previously heated and is now passively cooling.
853
+ `The Heater-Shaker does not have active cooling.`
854
+ - ``heating`` – The module is heating to a target temperature.
855
+ - ``idle`` – The module has not heated since the beginning of the protocol.
856
+ - ``error`` – The temperature status can't be determined.
857
+ """
858
+ return self._core.get_temperature_status().value
859
+
860
+ @property
861
+ @requires_version(2, 13)
862
+ def speed_status(self) -> str:
863
+ """One of five possible shaking statuses:
864
+
865
+ - ``holding at target`` – The module has reached its target shake speed
866
+ and is actively maintaining that speed.
867
+ - ``speeding up`` – The module is increasing its shake speed towards a target.
868
+ - ``slowing down`` – The module was previously shaking at a faster speed
869
+ and is currently reducing its speed to a lower target or to deactivate.
870
+ - ``idle`` – The module is not shaking.
871
+ - ``error`` – The shaking status can't be determined.
872
+ """
873
+ return self._core.get_speed_status().value
874
+
875
+ @property
876
+ @requires_version(2, 13)
877
+ def labware_latch_status(self) -> str:
878
+ """One of six possible latch statuses:
879
+
880
+ - ``opening`` – The latch is currently opening (in motion).
881
+ - ``idle_open`` – The latch is open and not moving.
882
+ - ``closing`` – The latch is currently closing (in motion).
883
+ - ``idle_closed`` – The latch is closed and not moving.
884
+ - ``idle_unknown`` – The default status upon reset, regardless of physical latch position.
885
+ Use :py:meth:`~HeaterShakerContext.close_labware_latch` before other commands
886
+ requiring confirmation that the latch is closed.
887
+ - ``unknown`` – The latch status can't be determined.
888
+ """
889
+ return self._core.get_labware_latch_status().value
890
+
891
+ @requires_version(2, 13)
892
+ def set_and_wait_for_temperature(self, celsius: float) -> None:
893
+ """Set a target temperature and wait until the module reaches the target.
894
+
895
+ No other protocol commands will execute while waiting for the temperature.
896
+
897
+ .. versionchanged:: 2.25
898
+ Removed the minimum temperature limit of 37 °C. Note that temperatures under ambient are
899
+ not achievable.
900
+
901
+ :param celsius: A value under 95, representing the target temperature in °C.
902
+ Values are automatically truncated to two decimal places,
903
+ and the Heater-Shaker module has a temperature accuracy of ±0.5 °C.
904
+ """
905
+ self.set_target_temperature(celsius=celsius)
906
+ self.wait_for_temperature()
907
+
908
+ @requires_version(2, 13)
909
+ @publish(command=cmds.heater_shaker_set_target_temperature)
910
+ def set_target_temperature(self, celsius: float) -> None:
911
+ """Set target temperature and return immediately.
912
+
913
+ Sets the Heater-Shaker's target temperature and returns immediately without
914
+ waiting for the target to be reached. Does not delay the protocol until
915
+ target temperature has reached.
916
+ Use :py:meth:`~.HeaterShakerContext.wait_for_temperature` to delay
917
+ protocol execution.
918
+
919
+ .. versionchanged:: 2.25
920
+ Removed the minimum temperature limit of 37 °C. Note that temperatures under ambient are
921
+ not achievable.
922
+
923
+ :param celsius: A value under 95, representing the target temperature in °C.
924
+ Values are automatically truncated to two decimal places,
925
+ and the Heater-Shaker module has a temperature accuracy of ±0.5 °C.
926
+ """
927
+ validated_temp = validate_heater_shaker_temperature(
928
+ celsius=celsius, api_version=self.api_version
929
+ )
930
+ self._core.set_target_temperature(celsius=validated_temp)
931
+
932
+ @requires_version(2, 13)
933
+ @publish(command=cmds.heater_shaker_wait_for_temperature)
934
+ def wait_for_temperature(self) -> None:
935
+ """Delays protocol execution until the Heater-Shaker has reached its target
936
+ temperature.
937
+
938
+ Raises an error if no target temperature was previously set.
939
+ """
940
+ self._core.wait_for_target_temperature()
941
+
942
+ @requires_version(2, 13)
943
+ @publish(command=cmds.heater_shaker_set_and_wait_for_shake_speed)
944
+ def set_and_wait_for_shake_speed(self, rpm: int) -> None:
945
+ """Set a shake speed in rpm and block execution of further commands until the module reaches the target.
946
+
947
+ Reaching a target shake speed typically only takes a few seconds.
948
+
949
+ .. note::
950
+
951
+ Before shaking, this command will retract the pipettes upward if they are parked adjacent to the Heater-Shaker.
952
+
953
+ :param rpm: A value between 200 and 3000, representing the target shake speed in revolutions per minute.
954
+ """
955
+ validated_speed = validate_heater_shaker_speed(rpm=rpm)
956
+ self._core.set_and_wait_for_shake_speed(rpm=validated_speed)
957
+
958
+ @requires_version(2, 13)
959
+ @publish(command=cmds.heater_shaker_open_labware_latch)
960
+ def open_labware_latch(self) -> None:
961
+ """Open the Heater-Shaker's labware latch.
962
+
963
+ The labware latch needs to be closed before:
964
+ * Shaking
965
+ * Pipetting to or from the labware on the Heater-Shaker
966
+ * Pipetting to or from labware to the left or right of the Heater-Shaker
967
+
968
+ Attempting to open the latch while the Heater-Shaker is shaking will raise an error.
969
+
970
+ .. note::
971
+
972
+ Before opening the latch, this command will retract the pipettes upward
973
+ if they are parked adjacent to the left or right of the Heater-Shaker.
974
+ """
975
+ self._core.open_labware_latch()
976
+
977
+ @requires_version(2, 13)
978
+ @publish(command=cmds.heater_shaker_close_labware_latch)
979
+ def close_labware_latch(self) -> None:
980
+ """Closes the labware latch.
981
+
982
+ The labware latch needs to be closed using this method before sending a shake command,
983
+ even if the latch was manually closed before starting the protocol.
984
+ """
985
+ self._core.close_labware_latch()
986
+
987
+ @requires_version(2, 13)
988
+ @publish(command=cmds.heater_shaker_deactivate_shaker)
989
+ def deactivate_shaker(self) -> None:
990
+ """Stops shaking.
991
+
992
+ Decelerating to 0 rpm typically only takes a few seconds.
993
+ """
994
+ self._core.deactivate_shaker()
995
+
996
+ @requires_version(2, 13)
997
+ @publish(command=cmds.heater_shaker_deactivate_heater)
998
+ def deactivate_heater(self) -> None:
999
+ """Stops heating.
1000
+
1001
+ The module will passively cool to room temperature.
1002
+ The Heater-Shaker does not have active cooling.
1003
+ """
1004
+ self._core.deactivate_heater()
1005
+
1006
+
1007
+ class MagneticBlockContext(ModuleContext):
1008
+ """An object representing a Magnetic Block.
1009
+
1010
+ It should not be instantiated directly; instead, it should be
1011
+ created through :py:meth:`.ProtocolContext.load_module`.
1012
+
1013
+ .. versionadded:: 2.15
1014
+ """
1015
+
1016
+ _core: MagneticBlockCore
1017
+
1018
+
1019
+ class AbsorbanceReaderContext(ModuleContext):
1020
+ """An object representing a connected Absorbance Plate Reader Module.
1021
+
1022
+ It should not be instantiated directly; instead, it should be
1023
+ created through :py:meth:`.ProtocolContext.load_module`.
1024
+
1025
+ .. versionadded:: 2.21
1026
+ """
1027
+
1028
+ _core: AbsorbanceReaderCore
1029
+
1030
+ @property
1031
+ @requires_version(2, 21)
1032
+ def serial_number(self) -> str:
1033
+ """Get the module's unique hardware serial number."""
1034
+ return self._core.get_serial_number()
1035
+
1036
+ @requires_version(2, 21)
1037
+ def close_lid(self) -> None:
1038
+ """Use the Flex Gripper to close the lid of the Absorbance Plate Reader.
1039
+
1040
+ You must call this method before initializing the reader, even if the reader was
1041
+ in the closed position at the start of the protocol.
1042
+ """
1043
+ self._core.close_lid()
1044
+
1045
+ @requires_version(2, 21)
1046
+ def open_lid(self) -> None:
1047
+ """Use the Flex Gripper to open the lid of the Absorbance Plate Reader."""
1048
+ self._core.open_lid()
1049
+
1050
+ @requires_version(2, 21)
1051
+ def is_lid_on(self) -> bool:
1052
+ """Return ``True`` if the Absorbance Plate Reader's lid is currently closed."""
1053
+ return self._core.is_lid_on()
1054
+
1055
+ @requires_version(2, 21)
1056
+ def initialize(
1057
+ self,
1058
+ mode: ABSMeasureMode,
1059
+ wavelengths: List[int],
1060
+ reference_wavelength: Optional[int] = None,
1061
+ ) -> None:
1062
+ """Prepare the Absorbance Plate Reader to read a plate.
1063
+
1064
+ See :ref:`absorbance-initialization` for examples.
1065
+
1066
+ :param mode: Either ``"single"`` or ``"multi"``.
1067
+
1068
+ - In single measurement mode, :py:meth:`.AbsorbanceReaderContext.read` uses
1069
+ one sample wavelength and an optional reference wavelength.
1070
+ - In multiple measurement mode, :py:meth:`.AbsorbanceReaderContext.read` uses
1071
+ a list of up to six sample wavelengths.
1072
+ :param wavelengths: A list of wavelengths, in nm, to measure.
1073
+
1074
+ - In the default hardware configuration, each wavelength must be one of
1075
+ ``450`` (blue), ``562`` (green), ``600`` (orange), or ``650`` (red). In
1076
+ custom hardware configurations, the module may accept other integers
1077
+ between 350 and 1000.
1078
+ - The list must contain only one item when initializing a single measurement.
1079
+ - The list can contain one to six items when initializing a multiple measurement.
1080
+ :param reference_wavelength: An optional reference wavelength, in nm. If provided,
1081
+ :py:meth:`.AbsorbanceReaderContext.read` will read at the reference
1082
+ wavelength and then subtract the reference wavelength values from the
1083
+ measurement wavelength values. Can only be used with single measurements.
1084
+ """
1085
+ self._core.initialize(
1086
+ mode, wavelengths, reference_wavelength=reference_wavelength
1087
+ )
1088
+
1089
+ @requires_version(2, 21)
1090
+ def read(
1091
+ self, export_filename: Optional[str] = None
1092
+ ) -> Dict[int, Dict[str, float]]:
1093
+ """Read a plate on the Absorbance Plate Reader.
1094
+
1095
+ This method always returns a dictionary of measurement data. It optionally will
1096
+ save a CSV file of the results to the Flex filesystem, which you can access from
1097
+ the Recent Protocol Runs screen in the Opentrons App. These files are `only` saved
1098
+ if you specify ``export_filename``.
1099
+
1100
+ In simulation, the values for each well key in the dictionary are set to zero, and
1101
+ no files are written.
1102
+
1103
+ .. note::
1104
+
1105
+ Avoid divide-by-zero errors when simulating and using the results of this
1106
+ method later in the protocol. If you divide by any of the measurement
1107
+ values, use :py:meth:`.ProtocolContext.is_simulating` to use alternate dummy
1108
+ data or skip the division step.
1109
+
1110
+ :param export_filename: An optional file basename. If provided, this method
1111
+ will write a CSV file for each measurement in the read operation. File
1112
+ names will use the value of this parameter, the measurement wavelength
1113
+ supplied in :py:meth:`~.AbsorbanceReaderContext.initialize`, and a
1114
+ ``.csv`` extension. For example, when reading at wavelengths 450 and 562
1115
+ with ``export_filename="my_data"``, there will be two output files:
1116
+ ``my_data_450.csv`` and ``my_data_562.csv``.
1117
+
1118
+ See :ref:`absorbance-csv` for information on working with these CSV files.
1119
+
1120
+ :returns: A dictionary of wavelengths to dictionary of values ordered by well name.
1121
+ """
1122
+ return self._core.read(filename=export_filename)
1123
+
1124
+
1125
+ class FlexStackerContext(ModuleContext):
1126
+ """An object representing a connected Flex Stacker module.
1127
+
1128
+ It should not be instantiated directly; instead, it should be
1129
+ created through :py:meth:`.ProtocolContext.load_module`.
1130
+
1131
+ .. versionadded:: 2.25
1132
+ """
1133
+
1134
+ _core: FlexStackerCore
1135
+
1136
+ @property
1137
+ @requires_version(2, 25)
1138
+ def serial_number(self) -> str:
1139
+ """Get the module's unique hardware serial number."""
1140
+ return self._core.get_serial_number()
1141
+
1142
+ @requires_version(2, 25)
1143
+ def retrieve(self) -> Labware:
1144
+ """Retrieve a labware from the Flex Stacker and place it on the shuttle.
1145
+
1146
+ :returns: The retrieved :py:class:`Labware` object. This will always be the main labware,
1147
+ even if the Flex Stacker contains labware on an adapter. To get the adapter object,
1148
+ call :py:class:`Labware.parent` on the returned labware.
1149
+
1150
+ """
1151
+ labware_core = self._core.retrieve()
1152
+
1153
+ return self._core_map.get_or_add(
1154
+ labware_core,
1155
+ Labware._builder_for_core_map(
1156
+ self._api_version, self._protocol_core, self._core_map
1157
+ ),
1158
+ )
1159
+
1160
+ @requires_version(2, 25)
1161
+ def store(self) -> None:
1162
+ """Move the labware currently on the Flex Stacker shuttle into the Flex Stacker."""
1163
+ self._core.store()
1164
+
1165
+ def _labware_to_cores(self, labware: Sequence[Labware]) -> list[LabwareCore]:
1166
+ return [labware._core for labware in labware]
1167
+
1168
+ def _cores_to_labware(self, cores: Sequence[LabwareCore]) -> list[Labware]:
1169
+ def _convert() -> Iterator[Labware]:
1170
+ for core in cores:
1171
+ yield self._core_map.get_or_add(
1172
+ core,
1173
+ Labware._builder_for_core_map(
1174
+ self._api_version, self._protocol_core, self._core_map
1175
+ ),
1176
+ )
1177
+
1178
+ return list(_convert())
1179
+
1180
+ @requires_version(2, 25)
1181
+ def get_max_storable_labware_from_list(
1182
+ self,
1183
+ labware: list[Labware],
1184
+ stacking_offset_z: float | None = None,
1185
+ ) -> list[Labware]:
1186
+ """Limit a list of labware instances to the number that can be stored in a Flex Stacker.
1187
+
1188
+ A Flex Stacker has a limited amount of internal space and computes the number of labware
1189
+ (or labware with lids or adapters) that it can store based on the heights of the labware
1190
+ and the amount they overlap when placed on top of each other. To know how many of a given
1191
+ labware the Flex Stacker can store, the Flex Stacker must know what labware it is.
1192
+
1193
+ You can use this function to take a list of labware and return the elements that the
1194
+ stacker can currently store from it. The returned list is then guaranteed to be suitable
1195
+ for passing to :py:meth:`.set_stored_labware_items`.
1196
+
1197
+ This function limits the list of labware based on the overall maximum number the stacker
1198
+ can hold and will not change as labware is added or removed. To limit a list of labware to
1199
+ the amount that will currently fit in the Flex Stacker, use
1200
+ :py:meth:`.get_current_storable_labware_from_list`.
1201
+
1202
+ .. note::
1203
+
1204
+ If a stacking offset is provided, make sure the same value is used when
1205
+ configuring the Flex Stacker with :py:meth:`.set_stored_labware_items`.
1206
+
1207
+ See :py:meth:`.set_stored_labware_items` for more details on stacking offset.
1208
+
1209
+ """
1210
+ return self._cores_to_labware(
1211
+ self._core.get_max_storable_labware_from_list(
1212
+ self._labware_to_cores(labware), stacking_offset_z
1213
+ ),
1214
+ )
1215
+
1216
+ @requires_version(2, 25)
1217
+ def get_current_storable_labware_from_list(
1218
+ self, labware: list[Labware]
1219
+ ) -> list[Labware]:
1220
+ """Limit a list of labware instances to the number that the Flex Stacker currently has space for,
1221
+ based on the labware that is already stored in the Flex Stacker.
1222
+
1223
+ You can use this function to take a list of labware and return the elements that the
1224
+ stacker can currently store from it. The returned list is then guaranteed to be suitable
1225
+ for passing to :py:meth:`.fill`.
1226
+
1227
+ The number of elements in the returned list will change as labware is added to or removed from
1228
+ the Flex Stacker. To get a list limited to the overall maximum number of labware the Flex Stacker
1229
+ can store, use :py:meth:`.get_max_storable_labware_from_list`.
1230
+ """
1231
+ return self._cores_to_labware(
1232
+ self._core.get_current_storable_labware_from_list(
1233
+ self._labware_to_cores(labware)
1234
+ )
1235
+ )
1236
+
1237
+ @requires_version(2, 25)
1238
+ def get_max_storable_labware(self) -> int:
1239
+ """Get the number of labware that the Flex Stacker can store with its current stored labware configuration.
1240
+
1241
+ You can use this function to get the total number of labware that the Flex Stacker can store. This
1242
+ number is the overall maximum and will not change as labware is added or removed. To get the space
1243
+ currently available in the Flex Stacker, use :py:meth:`.get_current_storable_labware`.
1244
+ """
1245
+ return self._core.get_max_storable_labware()
1246
+
1247
+ @requires_version(2, 25)
1248
+ def get_current_storable_labware(self) -> int:
1249
+ """Get the number of labware that the Flex Stacker currently has space for.
1250
+
1251
+ The number will change as labware is added or removed. To get the overall maximum number of labware the
1252
+ Flex Stacker can store, use :py:meth:`.get_max_storable_labware`.
1253
+ """
1254
+ return self._core.get_current_storable_labware()
1255
+
1256
+ @requires_version(2, 25)
1257
+ def set_stored_labware_items(
1258
+ self,
1259
+ labware: list[Labware],
1260
+ stacking_offset_z: float | None,
1261
+ ) -> None:
1262
+ """Configure a Flex Stacker by providing an initial list of stored labware objects.
1263
+
1264
+ The kind of labware stored by the Flex Stacker will be calculated from the list of labware
1265
+ specified here. You can use this to store labware objects that you have already created
1266
+ so that, for instance, you can set their liquid state or nicknames. There are several
1267
+ restrictions on the values of the ``labware`` argument:
1268
+ - ``labware`` must have at least one element
1269
+ - Elements of ``labware`` will be stored along with their lid, if any, and an adapter they
1270
+ rest on, if any. These must be compatible with the Flex Stacker.
1271
+ - All elements of ``labware`` must be loaded :py:obj:`OFF_DECK`.
1272
+ - All elements of ``labware`` must be the same kind of labware. If any of them have lids, they
1273
+ must all have lids, and the lids must be the same. If any of them are on adapters, they all
1274
+ must be on adapters, and the adapters must be the same.
1275
+ - The number of labware objects must fit in the stacker physically. To make sure the labware
1276
+ will fit, use the return value of :py:method:`.get_max_storable_labware_from_list`.
1277
+
1278
+ :param labware: A list of labware to load into the stacker.
1279
+ :param stacking_offset_z: Stacking offset in mm between labware units to override the
1280
+ calculated value from labware definitions.
1281
+
1282
+ .. note::
1283
+
1284
+ The stacking offset is the amount of vertical overlap (in mm) between the bottomside of a
1285
+ labware unit and the topside of the unit below. This offset is used to determine how many
1286
+ units can fit in the stacker and calculates the Z position of the shuttle when retrieving
1287
+ or storing labware. The stacking offset is calculated automatically from the labware
1288
+ definitions, but you can override it by providing a value here.
1289
+
1290
+ There are four possible stacking configurations, each with a different way of calculating
1291
+ the stacking offset:
1292
+ - Bare labware: labware (bottomside) overlaps with labware (topside)
1293
+ - Labware on adapter: the adapter (bottomside) of the upper unit overlaps with labware (topside)
1294
+ of the unit below.
1295
+ - Labware with lid: the labware (bottomside) of the upper unit overlaps the lid (topside)
1296
+ of the unit below.
1297
+ - Labware with lid and adapter: the adapter (bottomside) of the upper unit overlaps the
1298
+ lid (topside) of the unit below.
1299
+
1300
+ """
1301
+ self._core.set_stored_labware_items(
1302
+ self._labware_to_cores(labware),
1303
+ stacking_offset_z=stacking_offset_z,
1304
+ )
1305
+
1306
+ @requires_version(2, 25)
1307
+ def set_stored_labware(
1308
+ self,
1309
+ load_name: str,
1310
+ namespace: str | None = None,
1311
+ version: int | None = None,
1312
+ adapter: str | None = None,
1313
+ lid: str | None = None,
1314
+ count: int | None = None,
1315
+ stacking_offset_z: float | None = None,
1316
+ ) -> None:
1317
+ """Configure what kind of labware the Flex Stacker will store.
1318
+
1319
+ :param str load_name: A string to use for looking up a labware definition.
1320
+ You can find the ``load_name`` for any Opentrons-verified labware on the
1321
+ `Labware Library <https://labware.opentrons.com>`__.
1322
+ :param str namespace: The namespace that the labware definition belongs to.
1323
+ If unspecified, the API will automatically search two namespaces:
1324
+
1325
+ - ``"opentrons"``, to load standard Opentrons labware definitions.
1326
+ - ``"custom_beta"``, to load custom labware definitions created with the
1327
+ `Custom Labware Creator <https://labware.opentrons.com/create>`__.
1328
+
1329
+ You might need to specify an explicit ``namespace`` if you have a custom
1330
+ definition whose ``load_name`` is the same as an Opentrons-verified
1331
+ definition, and you want to explicitly choose one or the other.
1332
+ :param version: The version of the labware definition. You should normally
1333
+ leave this unspecified to let ``load_labware()`` choose a version
1334
+ automatically.
1335
+ :param adapter: An adapter to load the labware on top of. Accepts the same
1336
+ values as the ``load_name`` parameter of :py:meth:`.load_adapter`. The
1337
+ adapter will use the same namespace as the labware, and the API will
1338
+ choose the adapter's version automatically.
1339
+ :param lid: A lid to load the on top of the main labware. Accepts the same
1340
+ values as the ``load_name`` parameter of :py:meth:`.load_lid_stack`. The
1341
+ lid will use the same namespace as the labware, and the API will
1342
+ choose the lid's version automatically.
1343
+ :param count: The number of labware that the Flex Stacker should start the protocol
1344
+ storing. If not specified, this will be the maximum amount of this kind of
1345
+ labware that the Flex Stacker is capable of storing.
1346
+ :param stacking_offset_z: Stacking offset in mm between labware units to override the
1347
+ calculated value from labware definitions.
1348
+
1349
+ .. note::
1350
+
1351
+ The stacking offset is the amount of vertical overlap (in mm) between the bottomside of a
1352
+ labware unit and the topside of the unit below. This offset is used to determine how many
1353
+ units can fit in the stacker and calculates the Z position of the shuttle when retrieving
1354
+ or storing labware. The stacking offset is calculated automatically from the labware
1355
+ definitions, but you can override it by providing a value here.
1356
+
1357
+ There are four possible stacking configurations, each with a different way of calculating
1358
+ the stacking offset:
1359
+ - Bare labware: labware (bottomside) overlaps with labware (topside)
1360
+ - Labware on adapter: the adapter (bottomside) of the upper unit overlaps with labware (topside)
1361
+ of the unit below.
1362
+ - Labware with lid: the labware (bottomside) of the upper unit overlaps the lid (topside)
1363
+ of the unit below.
1364
+ - Labware with lid and adapter: the adapter (bottomside) of the upper unit overlaps the
1365
+ lid (topside) of the unit below.
1366
+
1367
+ """
1368
+ self._core.set_stored_labware(
1369
+ main_load_name=load_name,
1370
+ main_namespace=namespace,
1371
+ main_version=version,
1372
+ lid_load_name=lid,
1373
+ lid_namespace=namespace,
1374
+ lid_version=version,
1375
+ adapter_load_name=adapter,
1376
+ adapter_namespace=namespace,
1377
+ adapter_version=version,
1378
+ count=count,
1379
+ stacking_offset_z=stacking_offset_z,
1380
+ )
1381
+
1382
+ @requires_version(2, 25)
1383
+ def fill(self, count: int | None = None, message: str | None = None) -> None:
1384
+ """Pause the protocol to add more labware to the Flex Stacker.
1385
+
1386
+ :param message: A message to display in the Opentrons App to note what kind of labware to add.
1387
+ :param count: The amount of labware the Flex Stacker should hold after this command is executed.
1388
+ If not specified, the Flex Stacker should be full after this command is executed.
1389
+ """
1390
+ self._core.fill(count, message)
1391
+
1392
+ @requires_version(2, 25)
1393
+ def fill_items(self, labware: list[Labware], message: str | None = None) -> None:
1394
+ """Pause the protocol to add a specific list of labware to the Flex Stacker.
1395
+
1396
+ The ``labware`` argument must follow certain rules:
1397
+ - It should have at least one item
1398
+ - Its elements should be the same kind of labware previously passed to
1399
+ :py:meth:`.set_stored_labware_items` or loaded by :py:meth:`.set_stored_labware`
1400
+ - Its elements should all be loaded :py:obj:`OFF_DECK`
1401
+
1402
+ :param message: A message to display in the Opentrons App.
1403
+ :param labware: The list of labware to add, following the rules above.
1404
+ """
1405
+ self._core.fill_items(self._labware_to_cores(labware), message)
1406
+
1407
+ @requires_version(2, 25)
1408
+ def empty(self, message: str | None = None) -> None:
1409
+ """Pause the protocol to remove labware from the Flex Stacker.
1410
+
1411
+ :param message: A message to display in the Opentrons App to note what should be removed from
1412
+ the Flex Stacker.
1413
+ """
1414
+ self._core.empty(
1415
+ message,
1416
+ )
1417
+
1418
+ @requires_version(2, 25)
1419
+ def get_stored_labware(self) -> list[Labware]:
1420
+ """Get the list of labware currently stored inside the stacker.
1421
+
1422
+ The first element of the list is on the bottom and will be the item retrieved by a call to
1423
+ :py:meth:`.retrieve`.
1424
+ """
1425
+ return self._cores_to_labware(self._core.get_stored_labware())