opentrons 8.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of opentrons might be problematic. Click here for more details.
- opentrons/__init__.py +150 -0
- opentrons/_version.py +34 -0
- opentrons/calibration_storage/__init__.py +54 -0
- opentrons/calibration_storage/deck_configuration.py +62 -0
- opentrons/calibration_storage/encoder_decoder.py +31 -0
- opentrons/calibration_storage/file_operators.py +142 -0
- opentrons/calibration_storage/helpers.py +103 -0
- opentrons/calibration_storage/ot2/__init__.py +34 -0
- opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
- opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
- opentrons/calibration_storage/ot2/models/__init__.py +0 -0
- opentrons/calibration_storage/ot2/models/v1.py +149 -0
- opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
- opentrons/calibration_storage/ot2/tip_length.py +281 -0
- opentrons/calibration_storage/ot3/__init__.py +31 -0
- opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
- opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
- opentrons/calibration_storage/ot3/models/__init__.py +0 -0
- opentrons/calibration_storage/ot3/models/v1.py +122 -0
- opentrons/calibration_storage/ot3/module_offset.py +138 -0
- opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
- opentrons/calibration_storage/types.py +45 -0
- opentrons/cli/__init__.py +21 -0
- opentrons/cli/__main__.py +5 -0
- opentrons/cli/analyze.py +557 -0
- opentrons/config/__init__.py +631 -0
- opentrons/config/advanced_settings.py +871 -0
- opentrons/config/defaults_ot2.py +214 -0
- opentrons/config/defaults_ot3.py +499 -0
- opentrons/config/feature_flags.py +86 -0
- opentrons/config/gripper_config.py +55 -0
- opentrons/config/reset.py +203 -0
- opentrons/config/robot_configs.py +187 -0
- opentrons/config/types.py +183 -0
- opentrons/drivers/__init__.py +0 -0
- opentrons/drivers/absorbance_reader/__init__.py +11 -0
- opentrons/drivers/absorbance_reader/abstract.py +72 -0
- opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
- opentrons/drivers/absorbance_reader/driver.py +81 -0
- opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
- opentrons/drivers/absorbance_reader/simulator.py +84 -0
- opentrons/drivers/asyncio/__init__.py +0 -0
- opentrons/drivers/asyncio/communication/__init__.py +22 -0
- opentrons/drivers/asyncio/communication/async_serial.py +187 -0
- opentrons/drivers/asyncio/communication/errors.py +88 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +557 -0
- opentrons/drivers/command_builder.py +102 -0
- opentrons/drivers/flex_stacker/__init__.py +13 -0
- opentrons/drivers/flex_stacker/abstract.py +214 -0
- opentrons/drivers/flex_stacker/driver.py +768 -0
- opentrons/drivers/flex_stacker/errors.py +68 -0
- opentrons/drivers/flex_stacker/simulator.py +309 -0
- opentrons/drivers/flex_stacker/types.py +367 -0
- opentrons/drivers/flex_stacker/utils.py +19 -0
- opentrons/drivers/heater_shaker/__init__.py +5 -0
- opentrons/drivers/heater_shaker/abstract.py +76 -0
- opentrons/drivers/heater_shaker/driver.py +204 -0
- opentrons/drivers/heater_shaker/simulator.py +94 -0
- opentrons/drivers/mag_deck/__init__.py +6 -0
- opentrons/drivers/mag_deck/abstract.py +44 -0
- opentrons/drivers/mag_deck/driver.py +208 -0
- opentrons/drivers/mag_deck/simulator.py +63 -0
- opentrons/drivers/rpi_drivers/__init__.py +33 -0
- opentrons/drivers/rpi_drivers/dev_types.py +94 -0
- opentrons/drivers/rpi_drivers/gpio.py +282 -0
- opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
- opentrons/drivers/rpi_drivers/interfaces.py +15 -0
- opentrons/drivers/rpi_drivers/types.py +364 -0
- opentrons/drivers/rpi_drivers/usb.py +102 -0
- opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
- opentrons/drivers/serial_communication.py +151 -0
- opentrons/drivers/smoothie_drivers/__init__.py +4 -0
- opentrons/drivers/smoothie_drivers/connection.py +51 -0
- opentrons/drivers/smoothie_drivers/constants.py +121 -0
- opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
- opentrons/drivers/smoothie_drivers/errors.py +49 -0
- opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
- opentrons/drivers/smoothie_drivers/simulator.py +99 -0
- opentrons/drivers/smoothie_drivers/types.py +16 -0
- opentrons/drivers/temp_deck/__init__.py +10 -0
- opentrons/drivers/temp_deck/abstract.py +54 -0
- opentrons/drivers/temp_deck/driver.py +197 -0
- opentrons/drivers/temp_deck/simulator.py +57 -0
- opentrons/drivers/thermocycler/__init__.py +12 -0
- opentrons/drivers/thermocycler/abstract.py +99 -0
- opentrons/drivers/thermocycler/driver.py +395 -0
- opentrons/drivers/thermocycler/simulator.py +126 -0
- opentrons/drivers/types.py +107 -0
- opentrons/drivers/utils.py +222 -0
- opentrons/execute.py +742 -0
- opentrons/hardware_control/__init__.py +65 -0
- opentrons/hardware_control/__main__.py +77 -0
- opentrons/hardware_control/adapters.py +98 -0
- opentrons/hardware_control/api.py +1347 -0
- opentrons/hardware_control/backends/__init__.py +7 -0
- opentrons/hardware_control/backends/controller.py +400 -0
- opentrons/hardware_control/backends/errors.py +9 -0
- opentrons/hardware_control/backends/estop_state.py +164 -0
- opentrons/hardware_control/backends/flex_protocol.py +497 -0
- opentrons/hardware_control/backends/ot3controller.py +1930 -0
- opentrons/hardware_control/backends/ot3simulator.py +900 -0
- opentrons/hardware_control/backends/ot3utils.py +664 -0
- opentrons/hardware_control/backends/simulator.py +442 -0
- opentrons/hardware_control/backends/status_bar_state.py +240 -0
- opentrons/hardware_control/backends/subsystem_manager.py +431 -0
- opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
- opentrons/hardware_control/backends/types.py +14 -0
- opentrons/hardware_control/constants.py +6 -0
- opentrons/hardware_control/dev_types.py +125 -0
- opentrons/hardware_control/emulation/__init__.py +0 -0
- opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
- opentrons/hardware_control/emulation/app.py +56 -0
- opentrons/hardware_control/emulation/connection_handler.py +38 -0
- opentrons/hardware_control/emulation/heater_shaker.py +150 -0
- opentrons/hardware_control/emulation/magdeck.py +60 -0
- opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
- opentrons/hardware_control/emulation/module_server/client.py +78 -0
- opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
- opentrons/hardware_control/emulation/module_server/models.py +31 -0
- opentrons/hardware_control/emulation/module_server/server.py +110 -0
- opentrons/hardware_control/emulation/parser.py +74 -0
- opentrons/hardware_control/emulation/proxy.py +241 -0
- opentrons/hardware_control/emulation/run_emulator.py +68 -0
- opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
- opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
- opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
- opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
- opentrons/hardware_control/emulation/settings.py +119 -0
- opentrons/hardware_control/emulation/simulations.py +133 -0
- opentrons/hardware_control/emulation/smoothie.py +192 -0
- opentrons/hardware_control/emulation/tempdeck.py +69 -0
- opentrons/hardware_control/emulation/thermocycler.py +128 -0
- opentrons/hardware_control/emulation/types.py +10 -0
- opentrons/hardware_control/emulation/util.py +38 -0
- opentrons/hardware_control/errors.py +43 -0
- opentrons/hardware_control/execution_manager.py +164 -0
- opentrons/hardware_control/instruments/__init__.py +5 -0
- opentrons/hardware_control/instruments/instrument_abc.py +39 -0
- opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
- opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
- opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
- opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
- opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
- opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
- opentrons/hardware_control/module_control.py +332 -0
- opentrons/hardware_control/modules/__init__.py +69 -0
- opentrons/hardware_control/modules/absorbance_reader.py +373 -0
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/flex_stacker.py +948 -0
- opentrons/hardware_control/modules/heater_shaker.py +426 -0
- opentrons/hardware_control/modules/lid_temp_status.py +35 -0
- opentrons/hardware_control/modules/magdeck.py +233 -0
- opentrons/hardware_control/modules/mod_abc.py +245 -0
- opentrons/hardware_control/modules/module_calibration.py +93 -0
- opentrons/hardware_control/modules/plate_temp_status.py +61 -0
- opentrons/hardware_control/modules/tempdeck.py +299 -0
- opentrons/hardware_control/modules/thermocycler.py +731 -0
- opentrons/hardware_control/modules/types.py +417 -0
- opentrons/hardware_control/modules/update.py +255 -0
- opentrons/hardware_control/modules/utils.py +73 -0
- opentrons/hardware_control/motion_utilities.py +318 -0
- opentrons/hardware_control/nozzle_manager.py +422 -0
- opentrons/hardware_control/ot3_calibration.py +1171 -0
- opentrons/hardware_control/ot3api.py +3227 -0
- opentrons/hardware_control/pause_manager.py +31 -0
- opentrons/hardware_control/poller.py +112 -0
- opentrons/hardware_control/protocols/__init__.py +106 -0
- opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
- opentrons/hardware_control/protocols/calibratable.py +45 -0
- opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
- opentrons/hardware_control/protocols/configurable.py +48 -0
- opentrons/hardware_control/protocols/event_sourcer.py +18 -0
- opentrons/hardware_control/protocols/execution_controllable.py +33 -0
- opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
- opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
- opentrons/hardware_control/protocols/gripper_controller.py +55 -0
- opentrons/hardware_control/protocols/hardware_manager.py +51 -0
- opentrons/hardware_control/protocols/identifiable.py +16 -0
- opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
- opentrons/hardware_control/protocols/liquid_handler.py +266 -0
- opentrons/hardware_control/protocols/module_provider.py +16 -0
- opentrons/hardware_control/protocols/motion_controller.py +243 -0
- opentrons/hardware_control/protocols/position_estimator.py +45 -0
- opentrons/hardware_control/protocols/simulatable.py +10 -0
- opentrons/hardware_control/protocols/stoppable.py +9 -0
- opentrons/hardware_control/protocols/types.py +27 -0
- opentrons/hardware_control/robot_calibration.py +224 -0
- opentrons/hardware_control/scripts/README.md +28 -0
- opentrons/hardware_control/scripts/__init__.py +1 -0
- opentrons/hardware_control/scripts/gripper_control.py +208 -0
- opentrons/hardware_control/scripts/ot3gripper +7 -0
- opentrons/hardware_control/scripts/ot3repl +7 -0
- opentrons/hardware_control/scripts/repl.py +187 -0
- opentrons/hardware_control/scripts/tc_control.py +97 -0
- opentrons/hardware_control/scripts/update_module_fw.py +274 -0
- opentrons/hardware_control/simulator_setup.py +260 -0
- opentrons/hardware_control/thread_manager.py +431 -0
- opentrons/hardware_control/threaded_async_lock.py +97 -0
- opentrons/hardware_control/types.py +792 -0
- opentrons/hardware_control/util.py +234 -0
- opentrons/legacy_broker.py +53 -0
- opentrons/legacy_commands/__init__.py +1 -0
- opentrons/legacy_commands/commands.py +483 -0
- opentrons/legacy_commands/helpers.py +153 -0
- opentrons/legacy_commands/module_commands.py +276 -0
- opentrons/legacy_commands/protocol_commands.py +54 -0
- opentrons/legacy_commands/publisher.py +155 -0
- opentrons/legacy_commands/robot_commands.py +51 -0
- opentrons/legacy_commands/types.py +1186 -0
- opentrons/motion_planning/__init__.py +32 -0
- opentrons/motion_planning/adjacent_slots_getters.py +168 -0
- opentrons/motion_planning/deck_conflict.py +501 -0
- opentrons/motion_planning/errors.py +35 -0
- opentrons/motion_planning/types.py +42 -0
- opentrons/motion_planning/waypoints.py +218 -0
- opentrons/ordered_set.py +138 -0
- opentrons/protocol_api/__init__.py +105 -0
- opentrons/protocol_api/_liquid.py +157 -0
- opentrons/protocol_api/_liquid_properties.py +814 -0
- opentrons/protocol_api/_nozzle_layout.py +31 -0
- opentrons/protocol_api/_parameter_context.py +300 -0
- opentrons/protocol_api/_parameters.py +31 -0
- opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
- opentrons/protocol_api/_types.py +43 -0
- opentrons/protocol_api/config.py +23 -0
- opentrons/protocol_api/core/__init__.py +23 -0
- opentrons/protocol_api/core/common.py +33 -0
- opentrons/protocol_api/core/core_map.py +74 -0
- opentrons/protocol_api/core/engine/__init__.py +22 -0
- opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
- opentrons/protocol_api/core/engine/deck_conflict.py +400 -0
- opentrons/protocol_api/core/engine/exceptions.py +19 -0
- opentrons/protocol_api/core/engine/instrument.py +2391 -0
- opentrons/protocol_api/core/engine/labware.py +238 -0
- opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
- opentrons/protocol_api/core/engine/module_core.py +1027 -0
- opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
- opentrons/protocol_api/core/engine/point_calculations.py +64 -0
- opentrons/protocol_api/core/engine/protocol.py +1153 -0
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/stringify.py +74 -0
- opentrons/protocol_api/core/engine/transfer_components_executor.py +1006 -0
- opentrons/protocol_api/core/engine/well.py +241 -0
- opentrons/protocol_api/core/instrument.py +459 -0
- opentrons/protocol_api/core/labware.py +151 -0
- opentrons/protocol_api/core/legacy/__init__.py +11 -0
- opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
- opentrons/protocol_api/core/legacy/deck.py +369 -0
- opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
- opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
- opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
- opentrons/protocol_api/core/legacy/load_info.py +67 -0
- opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
- opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
- opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
- opentrons/protocol_api/core/module.py +484 -0
- opentrons/protocol_api/core/protocol.py +311 -0
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/core/well.py +116 -0
- opentrons/protocol_api/core/well_grid.py +45 -0
- opentrons/protocol_api/create_protocol_context.py +177 -0
- opentrons/protocol_api/deck.py +223 -0
- opentrons/protocol_api/disposal_locations.py +244 -0
- opentrons/protocol_api/instrument_context.py +3272 -0
- opentrons/protocol_api/labware.py +1579 -0
- opentrons/protocol_api/module_contexts.py +1447 -0
- opentrons/protocol_api/module_validation_and_errors.py +61 -0
- opentrons/protocol_api/protocol_context.py +1688 -0
- opentrons/protocol_api/robot_context.py +303 -0
- opentrons/protocol_api/validation.py +761 -0
- opentrons/protocol_engine/__init__.py +155 -0
- opentrons/protocol_engine/actions/__init__.py +65 -0
- opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
- opentrons/protocol_engine/actions/action_handler.py +13 -0
- opentrons/protocol_engine/actions/actions.py +302 -0
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/__init__.py +5 -0
- opentrons/protocol_engine/clients/sync_client.py +174 -0
- opentrons/protocol_engine/clients/transports.py +197 -0
- opentrons/protocol_engine/commands/__init__.py +757 -0
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
- opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
- opentrons/protocol_engine/commands/aspirate.py +244 -0
- opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
- opentrons/protocol_engine/commands/blow_out.py +146 -0
- opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
- opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
- opentrons/protocol_engine/commands/command.py +308 -0
- opentrons/protocol_engine/commands/command_unions.py +974 -0
- opentrons/protocol_engine/commands/comment.py +57 -0
- opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
- opentrons/protocol_engine/commands/custom.py +67 -0
- opentrons/protocol_engine/commands/dispense.py +194 -0
- opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
- opentrons/protocol_engine/commands/drop_tip.py +232 -0
- opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
- opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
- opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
- opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
- opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
- opentrons/protocol_engine/commands/flex_stacker/store.py +339 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
- opentrons/protocol_engine/commands/hash_command_params.py +38 -0
- opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
- opentrons/protocol_engine/commands/home.py +100 -0
- opentrons/protocol_engine/commands/identify_module.py +86 -0
- opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
- opentrons/protocol_engine/commands/liquid_probe.py +464 -0
- opentrons/protocol_engine/commands/load_labware.py +210 -0
- opentrons/protocol_engine/commands/load_lid.py +154 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
- opentrons/protocol_engine/commands/load_liquid.py +95 -0
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +223 -0
- opentrons/protocol_engine/commands/load_pipette.py +167 -0
- opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
- opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
- opentrons/protocol_engine/commands/move_labware.py +546 -0
- opentrons/protocol_engine/commands/move_relative.py +102 -0
- opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
- opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
- opentrons/protocol_engine/commands/move_to_well.py +119 -0
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
- opentrons/protocol_engine/commands/pipetting_common.py +443 -0
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
- opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
- opentrons/protocol_engine/commands/reload_labware.py +90 -0
- opentrons/protocol_engine/commands/retract_axis.py +75 -0
- opentrons/protocol_engine/commands/robot/__init__.py +70 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/save_position.py +109 -0
- opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
- opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
- opentrons/protocol_engine/commands/set_status_bar.py +89 -0
- opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
- opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
- opentrons/protocol_engine/commands/touch_tip.py +189 -0
- opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
- opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
- opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
- opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
- opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
- opentrons/protocol_engine/create_protocol_engine.py +193 -0
- opentrons/protocol_engine/engine_support.py +28 -0
- opentrons/protocol_engine/error_recovery_policy.py +81 -0
- opentrons/protocol_engine/errors/__init__.py +191 -0
- opentrons/protocol_engine/errors/error_occurrence.py +182 -0
- opentrons/protocol_engine/errors/exceptions.py +1308 -0
- opentrons/protocol_engine/execution/__init__.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +216 -0
- opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
- opentrons/protocol_engine/execution/door_watcher.py +119 -0
- opentrons/protocol_engine/execution/equipment.py +819 -0
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +686 -0
- opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
- opentrons/protocol_engine/execution/labware_movement.py +297 -0
- opentrons/protocol_engine/execution/movement.py +350 -0
- opentrons/protocol_engine/execution/pipetting.py +607 -0
- opentrons/protocol_engine/execution/queue_worker.py +86 -0
- opentrons/protocol_engine/execution/rail_lights.py +25 -0
- opentrons/protocol_engine/execution/run_control.py +33 -0
- opentrons/protocol_engine/execution/status_bar.py +34 -0
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
- opentrons/protocol_engine/execution/tip_handler.py +550 -0
- opentrons/protocol_engine/labware_offset_standardization.py +194 -0
- opentrons/protocol_engine/notes/__init__.py +17 -0
- opentrons/protocol_engine/notes/notes.py +59 -0
- opentrons/protocol_engine/plugins.py +104 -0
- opentrons/protocol_engine/protocol_engine.py +683 -0
- opentrons/protocol_engine/resources/__init__.py +26 -0
- opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
- opentrons/protocol_engine/resources/file_provider.py +161 -0
- opentrons/protocol_engine/resources/fixture_validation.py +68 -0
- opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
- opentrons/protocol_engine/resources/labware_validation.py +73 -0
- opentrons/protocol_engine/resources/model_utils.py +32 -0
- opentrons/protocol_engine/resources/module_data_provider.py +44 -0
- opentrons/protocol_engine/resources/ot3_validation.py +21 -0
- opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
- opentrons/protocol_engine/slot_standardization.py +128 -0
- opentrons/protocol_engine/state/__init__.py +1 -0
- opentrons/protocol_engine/state/_abstract_store.py +27 -0
- opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
- opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
- opentrons/protocol_engine/state/_move_types.py +83 -0
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +699 -0
- opentrons/protocol_engine/state/command_history.py +309 -0
- opentrons/protocol_engine/state/commands.py +1164 -0
- opentrons/protocol_engine/state/config.py +39 -0
- opentrons/protocol_engine/state/files.py +57 -0
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/geometry.py +2408 -0
- opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
- opentrons/protocol_engine/state/labware.py +1432 -0
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +73 -0
- opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
- opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
- opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
- opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
- opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
- opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
- opentrons/protocol_engine/state/modules.py +1515 -0
- opentrons/protocol_engine/state/motion.py +373 -0
- opentrons/protocol_engine/state/pipettes.py +905 -0
- opentrons/protocol_engine/state/state.py +421 -0
- opentrons/protocol_engine/state/state_summary.py +36 -0
- opentrons/protocol_engine/state/tips.py +420 -0
- opentrons/protocol_engine/state/update_types.py +904 -0
- opentrons/protocol_engine/state/wells.py +290 -0
- opentrons/protocol_engine/types/__init__.py +310 -0
- opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
- opentrons/protocol_engine/types/command_annotations.py +53 -0
- opentrons/protocol_engine/types/deck_configuration.py +81 -0
- opentrons/protocol_engine/types/execution.py +96 -0
- opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
- opentrons/protocol_engine/types/instrument.py +47 -0
- opentrons/protocol_engine/types/instrument_sensors.py +47 -0
- opentrons/protocol_engine/types/labware.py +131 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +111 -0
- opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
- opentrons/protocol_engine/types/liquid.py +40 -0
- opentrons/protocol_engine/types/liquid_class.py +59 -0
- opentrons/protocol_engine/types/liquid_handling.py +13 -0
- opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
- opentrons/protocol_engine/types/location.py +194 -0
- opentrons/protocol_engine/types/module.py +310 -0
- opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
- opentrons/protocol_engine/types/run_time_parameters.py +133 -0
- opentrons/protocol_engine/types/tip.py +18 -0
- opentrons/protocol_engine/types/util.py +21 -0
- opentrons/protocol_engine/types/well_position.py +124 -0
- opentrons/protocol_reader/__init__.py +37 -0
- opentrons/protocol_reader/extract_labware_definitions.py +66 -0
- opentrons/protocol_reader/file_format_validator.py +152 -0
- opentrons/protocol_reader/file_hasher.py +27 -0
- opentrons/protocol_reader/file_identifier.py +284 -0
- opentrons/protocol_reader/file_reader_writer.py +90 -0
- opentrons/protocol_reader/input_file.py +16 -0
- opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
- opentrons/protocol_reader/protocol_reader.py +188 -0
- opentrons/protocol_reader/protocol_source.py +124 -0
- opentrons/protocol_reader/role_analyzer.py +86 -0
- opentrons/protocol_runner/__init__.py +26 -0
- opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
- opentrons/protocol_runner/json_file_reader.py +55 -0
- opentrons/protocol_runner/json_translator.py +314 -0
- opentrons/protocol_runner/legacy_command_mapper.py +852 -0
- opentrons/protocol_runner/legacy_context_plugin.py +116 -0
- opentrons/protocol_runner/protocol_runner.py +530 -0
- opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
- opentrons/protocol_runner/run_orchestrator.py +496 -0
- opentrons/protocol_runner/task_queue.py +95 -0
- opentrons/protocols/__init__.py +6 -0
- opentrons/protocols/advanced_control/__init__.py +0 -0
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +60 -0
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +180 -0
- opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
- opentrons/protocols/api_support/__init__.py +0 -0
- opentrons/protocols/api_support/constants.py +8 -0
- opentrons/protocols/api_support/deck_type.py +110 -0
- opentrons/protocols/api_support/definitions.py +18 -0
- opentrons/protocols/api_support/instrument.py +151 -0
- opentrons/protocols/api_support/labware_like.py +233 -0
- opentrons/protocols/api_support/tip_tracker.py +175 -0
- opentrons/protocols/api_support/types.py +32 -0
- opentrons/protocols/api_support/util.py +403 -0
- opentrons/protocols/bundle.py +89 -0
- opentrons/protocols/duration/__init__.py +4 -0
- opentrons/protocols/duration/errors.py +5 -0
- opentrons/protocols/duration/estimator.py +628 -0
- opentrons/protocols/execution/__init__.py +0 -0
- opentrons/protocols/execution/dev_types.py +181 -0
- opentrons/protocols/execution/errors.py +40 -0
- opentrons/protocols/execution/execute.py +84 -0
- opentrons/protocols/execution/execute_json_v3.py +275 -0
- opentrons/protocols/execution/execute_json_v4.py +359 -0
- opentrons/protocols/execution/execute_json_v5.py +28 -0
- opentrons/protocols/execution/execute_python.py +169 -0
- opentrons/protocols/execution/json_dispatchers.py +87 -0
- opentrons/protocols/execution/types.py +7 -0
- opentrons/protocols/geometry/__init__.py +0 -0
- opentrons/protocols/geometry/planning.py +297 -0
- opentrons/protocols/labware.py +312 -0
- opentrons/protocols/models/__init__.py +0 -0
- opentrons/protocols/models/json_protocol.py +679 -0
- opentrons/protocols/parameters/__init__.py +0 -0
- opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
- opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
- opentrons/protocols/parameters/exceptions.py +34 -0
- opentrons/protocols/parameters/parameter_definition.py +272 -0
- opentrons/protocols/parameters/types.py +17 -0
- opentrons/protocols/parameters/validation.py +267 -0
- opentrons/protocols/parse.py +671 -0
- opentrons/protocols/types.py +159 -0
- opentrons/py.typed +0 -0
- opentrons/resources/scripts/lpc21isp +0 -0
- opentrons/resources/smoothie-edge-8414642.hex +23010 -0
- opentrons/simulate.py +1065 -0
- opentrons/system/__init__.py +6 -0
- opentrons/system/camera.py +51 -0
- opentrons/system/log_control.py +59 -0
- opentrons/system/nmcli.py +856 -0
- opentrons/system/resin.py +24 -0
- opentrons/system/smoothie_update.py +15 -0
- opentrons/system/wifi.py +204 -0
- opentrons/tools/__init__.py +0 -0
- opentrons/tools/args_handler.py +22 -0
- opentrons/tools/write_pipette_memory.py +157 -0
- opentrons/types.py +618 -0
- opentrons/util/__init__.py +1 -0
- opentrons/util/async_helpers.py +166 -0
- opentrons/util/broker.py +84 -0
- opentrons/util/change_notifier.py +47 -0
- opentrons/util/entrypoint_util.py +278 -0
- opentrons/util/get_union_elements.py +26 -0
- opentrons/util/helpers.py +6 -0
- opentrons/util/linal.py +178 -0
- opentrons/util/logging_config.py +265 -0
- opentrons/util/logging_queue_handler.py +61 -0
- opentrons/util/performance_helpers.py +157 -0
- opentrons-8.6.0.dist-info/METADATA +37 -0
- opentrons-8.6.0.dist-info/RECORD +601 -0
- opentrons-8.6.0.dist-info/WHEEL +4 -0
- opentrons-8.6.0.dist-info/entry_points.txt +3 -0
- opentrons-8.6.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,1688 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from copy import deepcopy
|
|
5
|
+
from typing import (
|
|
6
|
+
Callable,
|
|
7
|
+
Dict,
|
|
8
|
+
List,
|
|
9
|
+
Optional,
|
|
10
|
+
Type,
|
|
11
|
+
Union,
|
|
12
|
+
Mapping,
|
|
13
|
+
cast,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from opentrons_shared_data.labware.types import LabwareDefinition
|
|
17
|
+
from opentrons_shared_data.liquid_classes.liquid_class_definition import (
|
|
18
|
+
TransferProperties as SharedTransferProperties,
|
|
19
|
+
)
|
|
20
|
+
from opentrons_shared_data.liquid_classes import DEFAULT_LC_VERSION, definition_exists
|
|
21
|
+
from opentrons_shared_data.liquid_classes.types import TransferPropertiesDict
|
|
22
|
+
from opentrons_shared_data.pipette.types import PipetteNameType
|
|
23
|
+
|
|
24
|
+
from opentrons.types import Mount, Location, DeckLocation, DeckSlotName, StagingSlotName
|
|
25
|
+
from opentrons.legacy_broker import LegacyBroker
|
|
26
|
+
from opentrons.hardware_control.modules.types import (
|
|
27
|
+
MagneticBlockModel,
|
|
28
|
+
AbsorbanceReaderModel,
|
|
29
|
+
FlexStackerModuleModel,
|
|
30
|
+
)
|
|
31
|
+
from opentrons.legacy_commands import protocol_commands as cmds, types as cmd_types
|
|
32
|
+
from opentrons.legacy_commands.helpers import (
|
|
33
|
+
stringify_labware_movement_command,
|
|
34
|
+
stringify_lid_movement_command,
|
|
35
|
+
)
|
|
36
|
+
from opentrons.legacy_commands.publisher import (
|
|
37
|
+
CommandPublisher,
|
|
38
|
+
publish,
|
|
39
|
+
publish_context,
|
|
40
|
+
)
|
|
41
|
+
from opentrons.protocols.api_support import instrument as instrument_support
|
|
42
|
+
from opentrons.protocols.api_support.deck_type import (
|
|
43
|
+
NoTrashDefinedError,
|
|
44
|
+
should_load_fixed_trash_labware_for_python_protocol,
|
|
45
|
+
should_load_fixed_trash_area_for_python_protocol,
|
|
46
|
+
)
|
|
47
|
+
from opentrons.protocols.api_support.types import APIVersion
|
|
48
|
+
from opentrons.protocols.api_support.util import (
|
|
49
|
+
AxisMaxSpeeds,
|
|
50
|
+
requires_version,
|
|
51
|
+
APIVersionError,
|
|
52
|
+
RobotTypeError,
|
|
53
|
+
UnsupportedAPIError,
|
|
54
|
+
)
|
|
55
|
+
from opentrons_shared_data.errors.exceptions import CommandPreconditionViolated
|
|
56
|
+
from opentrons.protocol_engine.errors import LabwareMovementNotAllowedError
|
|
57
|
+
from ._liquid_properties import build_transfer_properties
|
|
58
|
+
|
|
59
|
+
from ._types import OffDeckType
|
|
60
|
+
from .core.common import ModuleCore, LabwareCore, ProtocolCore
|
|
61
|
+
from .core.core_map import LoadedCoreMap
|
|
62
|
+
from .core.engine.module_core import NonConnectedModuleCore
|
|
63
|
+
from .core.module import (
|
|
64
|
+
AbstractTemperatureModuleCore,
|
|
65
|
+
AbstractMagneticModuleCore,
|
|
66
|
+
AbstractThermocyclerCore,
|
|
67
|
+
AbstractHeaterShakerCore,
|
|
68
|
+
AbstractMagneticBlockCore,
|
|
69
|
+
AbstractAbsorbanceReaderCore,
|
|
70
|
+
AbstractFlexStackerCore,
|
|
71
|
+
)
|
|
72
|
+
from .robot_context import RobotContext, HardwareManager
|
|
73
|
+
from .core.engine import ENGINE_CORE_API_VERSION
|
|
74
|
+
from .core.legacy.legacy_protocol_core import LegacyProtocolCore
|
|
75
|
+
|
|
76
|
+
from . import validation
|
|
77
|
+
from ._liquid import Liquid, LiquidClass
|
|
78
|
+
from .disposal_locations import TrashBin, WasteChute
|
|
79
|
+
from .deck import Deck
|
|
80
|
+
from .instrument_context import InstrumentContext
|
|
81
|
+
from .labware import Labware
|
|
82
|
+
from .module_contexts import (
|
|
83
|
+
MagneticModuleContext,
|
|
84
|
+
TemperatureModuleContext,
|
|
85
|
+
ThermocyclerContext,
|
|
86
|
+
HeaterShakerContext,
|
|
87
|
+
MagneticBlockContext,
|
|
88
|
+
AbsorbanceReaderContext,
|
|
89
|
+
FlexStackerContext,
|
|
90
|
+
ModuleContext,
|
|
91
|
+
)
|
|
92
|
+
from ._parameters import Parameters
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
logger = logging.getLogger(__name__)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
ModuleTypes = Union[
|
|
99
|
+
TemperatureModuleContext,
|
|
100
|
+
MagneticModuleContext,
|
|
101
|
+
ThermocyclerContext,
|
|
102
|
+
HeaterShakerContext,
|
|
103
|
+
MagneticBlockContext,
|
|
104
|
+
AbsorbanceReaderContext,
|
|
105
|
+
FlexStackerContext,
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class _Unset:
|
|
110
|
+
"""A sentinel value for when no value has been supplied for an argument,
|
|
111
|
+
when `None` is already taken for some other meaning.
|
|
112
|
+
|
|
113
|
+
User code should never use this explicitly.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class ProtocolContext(CommandPublisher):
|
|
120
|
+
"""A context for the state of a protocol.
|
|
121
|
+
|
|
122
|
+
The ``ProtocolContext`` class provides the objects, attributes, and methods that
|
|
123
|
+
allow you to configure and control the protocol.
|
|
124
|
+
|
|
125
|
+
Methods generally fall into one of two categories.
|
|
126
|
+
|
|
127
|
+
- They can change the state of the ``ProtocolContext`` object, such as adding
|
|
128
|
+
pipettes, hardware modules, or labware to your protocol.
|
|
129
|
+
- They can control the flow of a running protocol, such as pausing, displaying
|
|
130
|
+
messages, or controlling built-in robot hardware like the ambient lighting.
|
|
131
|
+
|
|
132
|
+
Do not instantiate a ``ProtocolContext`` directly.
|
|
133
|
+
The ``run()`` function of your protocol does that for you.
|
|
134
|
+
See the :ref:`Tutorial <run-function>` for more information.
|
|
135
|
+
|
|
136
|
+
Use :py:meth:`opentrons.execute.get_protocol_api` to instantiate a ``ProtocolContext`` when
|
|
137
|
+
using Jupyter Notebook. See :ref:`advanced-control`.
|
|
138
|
+
|
|
139
|
+
.. versionadded:: 2.0
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def __init__(
|
|
144
|
+
self,
|
|
145
|
+
api_version: APIVersion,
|
|
146
|
+
core: ProtocolCore,
|
|
147
|
+
broker: Optional[LegacyBroker] = None,
|
|
148
|
+
core_map: Optional[LoadedCoreMap] = None,
|
|
149
|
+
deck: Optional[Deck] = None,
|
|
150
|
+
bundled_data: Optional[Dict[str, bytes]] = None,
|
|
151
|
+
) -> None:
|
|
152
|
+
"""Build a :py:class:`.ProtocolContext`.
|
|
153
|
+
|
|
154
|
+
:param api_version: The API version to use.
|
|
155
|
+
:param core: The protocol implementation core.
|
|
156
|
+
:param labware_offset_provider: Where this protocol context and its child
|
|
157
|
+
module contexts will get labware offsets from.
|
|
158
|
+
:param broker: An optional command broker to link to. If not
|
|
159
|
+
specified, a dummy one is used.
|
|
160
|
+
:param bundled_data: A dict mapping filenames to the contents of data
|
|
161
|
+
files. Can be used by the protocol, since it is
|
|
162
|
+
exposed as
|
|
163
|
+
:py:attr:`.ProtocolContext.bundled_data`
|
|
164
|
+
"""
|
|
165
|
+
super().__init__(broker)
|
|
166
|
+
self._api_version = api_version
|
|
167
|
+
self._core = core
|
|
168
|
+
self._core_map = core_map or LoadedCoreMap()
|
|
169
|
+
self._deck = deck or Deck(
|
|
170
|
+
protocol_core=core, core_map=self._core_map, api_version=api_version
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# With the introduction of Extension mount type, this dict initializes to include
|
|
174
|
+
# the extension mount, for both ot2 & 3. While it doesn't seem like it would
|
|
175
|
+
# create an issue in the current PAPI context, it would be much safer to
|
|
176
|
+
# only use mounts available on the robot.
|
|
177
|
+
self._instruments: Dict[Mount, Optional[InstrumentContext]] = {
|
|
178
|
+
mount: None for mount in Mount
|
|
179
|
+
}
|
|
180
|
+
self._bundled_data: Dict[str, bytes] = bundled_data or {}
|
|
181
|
+
|
|
182
|
+
# With the addition of Movable Trashes and Waste Chute support, it is not necessary
|
|
183
|
+
# to ensure that the list of "disposal locations", essentially the list of trashes,
|
|
184
|
+
# is initialized correctly on protocols utilizing former API versions prior to 2.16
|
|
185
|
+
# and also to ensure that any protocols after 2.16 initialize a Fixed Trash for OT-2
|
|
186
|
+
# protocols so that no load trash bin behavior is required within the protocol itself.
|
|
187
|
+
# Protocols prior to 2.16 expect the Fixed Trash to exist as a Labware object, while
|
|
188
|
+
# protocols after 2.16 expect trash to exist as either a TrashBin or WasteChute object.
|
|
189
|
+
|
|
190
|
+
self._load_fixed_trash()
|
|
191
|
+
if should_load_fixed_trash_labware_for_python_protocol(self._api_version):
|
|
192
|
+
self._core.append_disposal_location(self.fixed_trash)
|
|
193
|
+
elif should_load_fixed_trash_area_for_python_protocol(
|
|
194
|
+
self._api_version, self._core.robot_type
|
|
195
|
+
):
|
|
196
|
+
self._core.load_ot2_fixed_trash_bin()
|
|
197
|
+
|
|
198
|
+
self._commands: List[str] = []
|
|
199
|
+
self._params: Parameters = Parameters()
|
|
200
|
+
self._unsubscribe_commands: Optional[Callable[[], None]] = None
|
|
201
|
+
try:
|
|
202
|
+
self._robot: Optional[RobotContext] = RobotContext(
|
|
203
|
+
core=self._core.load_robot(),
|
|
204
|
+
protocol_core=self._core,
|
|
205
|
+
api_version=self._api_version,
|
|
206
|
+
broker=broker,
|
|
207
|
+
)
|
|
208
|
+
except APIVersionError:
|
|
209
|
+
self._robot = None
|
|
210
|
+
self.clear_commands()
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
@requires_version(2, 0)
|
|
214
|
+
def api_version(self) -> APIVersion:
|
|
215
|
+
"""Return the API version specified for this protocol context.
|
|
216
|
+
|
|
217
|
+
This value is set when the protocol context
|
|
218
|
+
is initialized.
|
|
219
|
+
|
|
220
|
+
- When the context is the argument of ``run()``, the ``"apiLevel"`` key of the
|
|
221
|
+
:ref:`metadata <tutorial-metadata>` or :ref:`requirements
|
|
222
|
+
<tutorial-requirements>` dictionary determines ``api_version``.
|
|
223
|
+
- When the context is instantiated with
|
|
224
|
+
:py:meth:`opentrons.execute.get_protocol_api` or
|
|
225
|
+
:py:meth:`opentrons.simulate.get_protocol_api`, the value of its ``version``
|
|
226
|
+
argument determines ``api_version``.
|
|
227
|
+
|
|
228
|
+
It may be lower than the :ref:`maximum version <max-version>` supported by the
|
|
229
|
+
robot software, which is accessible via the
|
|
230
|
+
``protocol_api.MAX_SUPPORTED_VERSION`` constant.
|
|
231
|
+
"""
|
|
232
|
+
return self._api_version
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
@requires_version(2, 22)
|
|
236
|
+
def robot(self) -> RobotContext:
|
|
237
|
+
"""The :py:class:`.RobotContext` for the protocol.
|
|
238
|
+
|
|
239
|
+
:meta private:
|
|
240
|
+
"""
|
|
241
|
+
if self._core.robot_type != "OT-3 Standard" or not self._robot:
|
|
242
|
+
raise RobotTypeError("The RobotContext is only available on Flex robots.")
|
|
243
|
+
return self._robot
|
|
244
|
+
|
|
245
|
+
@property
|
|
246
|
+
def _hw_manager(self) -> HardwareManager:
|
|
247
|
+
# TODO (lc 01-05-2021) remove this once we have a more
|
|
248
|
+
# user facing hardware control http api.
|
|
249
|
+
# HardwareManager(hardware=self._core.get_hardware())
|
|
250
|
+
logger.warning(
|
|
251
|
+
"This function will be deprecated in later versions."
|
|
252
|
+
"Please use with caution."
|
|
253
|
+
)
|
|
254
|
+
if self._robot:
|
|
255
|
+
return self._robot.hardware
|
|
256
|
+
return HardwareManager(hardware=self._core.get_hardware())
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
@requires_version(2, 0)
|
|
260
|
+
def bundled_data(self) -> Dict[str, bytes]:
|
|
261
|
+
"""Accessor for data files bundled with this protocol, if any.
|
|
262
|
+
|
|
263
|
+
This is a dictionary mapping the filenames of bundled datafiles to their
|
|
264
|
+
contents. The filename keys are formatted with extensions but without paths. For
|
|
265
|
+
example, a file stored in the bundle as ``data/mydata/aspirations.csv`` will
|
|
266
|
+
have the key ``"aspirations.csv"``. The values are :py:class:`bytes` objects
|
|
267
|
+
representing the contents of the files.
|
|
268
|
+
"""
|
|
269
|
+
return self._bundled_data
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
@requires_version(2, 18)
|
|
273
|
+
def params(self) -> Parameters:
|
|
274
|
+
"""
|
|
275
|
+
The values of runtime parameters, as set during run setup.
|
|
276
|
+
|
|
277
|
+
Each attribute of this object corresponds to the ``variable_name`` of a parameter.
|
|
278
|
+
See :ref:`using-rtp` for details.
|
|
279
|
+
|
|
280
|
+
Parameter values can only be set during run setup. If you try to alter the value
|
|
281
|
+
of any attribute of ``params``, the API will raise an error.
|
|
282
|
+
"""
|
|
283
|
+
return self._params
|
|
284
|
+
|
|
285
|
+
def cleanup(self) -> None:
|
|
286
|
+
"""Finalize and clean up the protocol context."""
|
|
287
|
+
if self._unsubscribe_commands:
|
|
288
|
+
self._unsubscribe_commands()
|
|
289
|
+
self._unsubscribe_commands = None
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
@requires_version(2, 0)
|
|
293
|
+
def max_speeds(self) -> AxisMaxSpeeds:
|
|
294
|
+
"""Per-axis speed limits for moving instruments.
|
|
295
|
+
|
|
296
|
+
Changing values within this property sets the speed limit for each non-plunger
|
|
297
|
+
axis of the robot. Note that this property only sets upper limits and can't
|
|
298
|
+
exceed the physical speed limits of the movement system.
|
|
299
|
+
|
|
300
|
+
This property is a dict mapping string names of axes to float values
|
|
301
|
+
of maximum speeds in mm/s. To change a speed, set that axis's value. To
|
|
302
|
+
reset an axis's speed to default, delete the entry for that axis
|
|
303
|
+
or assign it to ``None``.
|
|
304
|
+
|
|
305
|
+
See :ref:`axis_speed_limits` for examples.
|
|
306
|
+
|
|
307
|
+
.. note::
|
|
308
|
+
This property is not yet supported in API version 2.14 or higher.
|
|
309
|
+
"""
|
|
310
|
+
if self._api_version >= ENGINE_CORE_API_VERSION:
|
|
311
|
+
# TODO(mc, 2023-02-23): per-axis max speeds not yet supported on the engine
|
|
312
|
+
# See https://opentrons.atlassian.net/browse/RCORE-373
|
|
313
|
+
raise UnsupportedAPIError(
|
|
314
|
+
api_element="ProtocolContext.max_speeds",
|
|
315
|
+
since_version=f"{ENGINE_CORE_API_VERSION}",
|
|
316
|
+
current_version=f"{self._api_version}",
|
|
317
|
+
extra_message="Set speeds using InstrumentContext.default_speed or the per-method 'speed' argument.",
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
return self._core.get_max_speeds()
|
|
321
|
+
|
|
322
|
+
@requires_version(2, 0)
|
|
323
|
+
def commands(self) -> List[str]:
|
|
324
|
+
"""Return the run log.
|
|
325
|
+
|
|
326
|
+
This is a list of human-readable strings representing what's been done in the protocol so
|
|
327
|
+
far. For example, "Aspirating 123 µL from well A1 of 96 well plate in slot 1."
|
|
328
|
+
|
|
329
|
+
The exact format of these entries is not guaranteed. The format here may differ from other
|
|
330
|
+
places that show the run log, such as the Opentrons App or touchscreen.
|
|
331
|
+
"""
|
|
332
|
+
return self._commands
|
|
333
|
+
|
|
334
|
+
@requires_version(2, 0)
|
|
335
|
+
def clear_commands(self) -> None:
|
|
336
|
+
self._commands.clear()
|
|
337
|
+
if self._unsubscribe_commands:
|
|
338
|
+
self._unsubscribe_commands()
|
|
339
|
+
|
|
340
|
+
self._unsubscribe_commands = self.broker.subscribe(
|
|
341
|
+
cmd_types.COMMAND, self._on_command_callback
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
def _on_command_callback(self, message: cmd_types.CommandMessage) -> None:
|
|
345
|
+
"""Callback for command messages."""
|
|
346
|
+
payload = message.get("payload")
|
|
347
|
+
|
|
348
|
+
if payload is None:
|
|
349
|
+
return
|
|
350
|
+
|
|
351
|
+
text = payload.get("text")
|
|
352
|
+
|
|
353
|
+
if text is None:
|
|
354
|
+
return
|
|
355
|
+
|
|
356
|
+
if message["$"] == "before":
|
|
357
|
+
self._commands.append(text)
|
|
358
|
+
|
|
359
|
+
@requires_version(2, 0)
|
|
360
|
+
def is_simulating(self) -> bool:
|
|
361
|
+
"""Returns ``True`` if the protocol is running in simulation.
|
|
362
|
+
|
|
363
|
+
Returns ``False`` if the protocol is running on actual hardware.
|
|
364
|
+
|
|
365
|
+
You can evaluate the result of this method in an ``if`` statement to make your
|
|
366
|
+
protocol behave differently in different environments. For example, you could
|
|
367
|
+
refer to a data file on your computer when simulating and refer to a data file
|
|
368
|
+
stored on the robot when not simulating.
|
|
369
|
+
|
|
370
|
+
You can also use it to skip time-consuming aspects of your protocol. Most Python
|
|
371
|
+
Protocol API methods, like :py:meth:`.delay`, are designed to evaluate
|
|
372
|
+
instantaneously in simulation. But external methods, like those from the
|
|
373
|
+
:py:mod:`time` module, will run at normal speed if not skipped.
|
|
374
|
+
"""
|
|
375
|
+
return self._core.is_simulating()
|
|
376
|
+
|
|
377
|
+
@requires_version(2, 0)
|
|
378
|
+
def load_labware_from_definition(
|
|
379
|
+
self,
|
|
380
|
+
labware_def: "LabwareDefinition",
|
|
381
|
+
location: Union[DeckLocation, OffDeckType],
|
|
382
|
+
label: Optional[str] = None,
|
|
383
|
+
) -> Labware:
|
|
384
|
+
"""Specify the presence of a labware on the deck.
|
|
385
|
+
|
|
386
|
+
This function loads the labware definition specified by ``labware_def``
|
|
387
|
+
to the location specified by ``location``.
|
|
388
|
+
|
|
389
|
+
:param labware_def: The labware's definition.
|
|
390
|
+
:param location: The slot into which to load the labware,
|
|
391
|
+
such as ``1``, ``"1"``, or ``"D1"``. See :ref:`deck-slots`.
|
|
392
|
+
:type location: int or str or :py:obj:`OFF_DECK`
|
|
393
|
+
:param str label: An optional special name to give the labware. If specified,
|
|
394
|
+
this is how the labware will appear in the run log, Labware Position
|
|
395
|
+
Check, and elsewhere in the Opentrons App and on the touchscreen.
|
|
396
|
+
"""
|
|
397
|
+
load_params = self._core.add_labware_definition(labware_def)
|
|
398
|
+
|
|
399
|
+
return self.load_labware(
|
|
400
|
+
load_name=load_params.load_name,
|
|
401
|
+
namespace=load_params.namespace,
|
|
402
|
+
version=load_params.version,
|
|
403
|
+
location=location,
|
|
404
|
+
label=label,
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
@requires_version(2, 0)
|
|
408
|
+
def load_labware(
|
|
409
|
+
self,
|
|
410
|
+
load_name: str,
|
|
411
|
+
location: Union[DeckLocation, OffDeckType],
|
|
412
|
+
label: Optional[str] = None,
|
|
413
|
+
namespace: Optional[str] = None,
|
|
414
|
+
version: Optional[int] = None,
|
|
415
|
+
adapter: Optional[str] = None,
|
|
416
|
+
lid: Optional[str] = None,
|
|
417
|
+
) -> Labware:
|
|
418
|
+
"""Load a labware onto a location.
|
|
419
|
+
|
|
420
|
+
For Opentrons-verified labware, this is a convenient way
|
|
421
|
+
to collapse the two stages of labware initialization (creating
|
|
422
|
+
the labware and adding it to the protocol) into one.
|
|
423
|
+
|
|
424
|
+
This function returns the created and initialized labware for use
|
|
425
|
+
later in the protocol.
|
|
426
|
+
|
|
427
|
+
:param str load_name: A string to use for looking up a labware definition.
|
|
428
|
+
You can find the ``load_name`` for any Opentrons-verified labware on the
|
|
429
|
+
`Labware Library <https://labware.opentrons.com>`__.
|
|
430
|
+
|
|
431
|
+
:param location: Either a :ref:`deck slot <deck-slots>`,
|
|
432
|
+
like ``1``, ``"1"``, or ``"D1"``, or the special value :py:obj:`OFF_DECK`.
|
|
433
|
+
|
|
434
|
+
.. versionchanged:: 2.15
|
|
435
|
+
You can now specify a deck slot as a coordinate, like ``"D1"``.
|
|
436
|
+
|
|
437
|
+
:type location: int or str or :py:obj:`OFF_DECK`
|
|
438
|
+
|
|
439
|
+
:param str label: An optional special name to give the labware. If specified,
|
|
440
|
+
this is how the labware will appear in the run log, Labware Position
|
|
441
|
+
Check, and elsewhere in the Opentrons App and on the touchscreen.
|
|
442
|
+
|
|
443
|
+
:param str namespace: The namespace that the labware definition belongs to.
|
|
444
|
+
If unspecified, the API will automatically search two namespaces:
|
|
445
|
+
|
|
446
|
+
- ``"opentrons"``, to load standard Opentrons labware definitions.
|
|
447
|
+
- ``"custom_beta"``, to load custom labware definitions created with the
|
|
448
|
+
`Custom Labware Creator <https://labware.opentrons.com/create>`__.
|
|
449
|
+
|
|
450
|
+
You might need to specify an explicit ``namespace`` if you have a custom
|
|
451
|
+
definition whose ``load_name`` is the same as an Opentrons-verified
|
|
452
|
+
definition, and you want to explicitly choose one or the other.
|
|
453
|
+
|
|
454
|
+
:param version: The version of the labware definition. You should normally
|
|
455
|
+
leave this unspecified to let ``load_labware()`` choose a version
|
|
456
|
+
automatically.
|
|
457
|
+
:param adapter: An adapter to load the labware on top of. Accepts the same
|
|
458
|
+
values as the ``load_name`` parameter of :py:meth:`.load_adapter`. The
|
|
459
|
+
adapter will use the same namespace as the labware, and the API will
|
|
460
|
+
choose the adapter's version automatically.
|
|
461
|
+
|
|
462
|
+
.. versionadded:: 2.15
|
|
463
|
+
:param lid: A lid to load on the top of the main labware. Accepts the same
|
|
464
|
+
values as the ``load_name`` parameter of :py:meth:`.load_lid_stack`. The
|
|
465
|
+
lid will use the same namespace as the labware, and the API will
|
|
466
|
+
choose the lid's version automatically.
|
|
467
|
+
|
|
468
|
+
.. versionadded:: 2.23
|
|
469
|
+
"""
|
|
470
|
+
|
|
471
|
+
if isinstance(location, OffDeckType) and self._api_version < APIVersion(2, 15):
|
|
472
|
+
raise APIVersionError(
|
|
473
|
+
api_element="Loading a labware off-deck",
|
|
474
|
+
until_version="2.15",
|
|
475
|
+
current_version=f"{self._api_version}",
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
load_name = validation.ensure_lowercase_name(load_name)
|
|
479
|
+
load_location: Union[OffDeckType, DeckSlotName, StagingSlotName, LabwareCore]
|
|
480
|
+
if adapter is not None:
|
|
481
|
+
if self._api_version < APIVersion(2, 15):
|
|
482
|
+
raise APIVersionError(
|
|
483
|
+
api_element="Loading a labware on an adapter",
|
|
484
|
+
until_version="2.15",
|
|
485
|
+
current_version=f"{self._api_version}",
|
|
486
|
+
)
|
|
487
|
+
loaded_adapter = self.load_adapter(
|
|
488
|
+
load_name=adapter,
|
|
489
|
+
location=location,
|
|
490
|
+
namespace=namespace,
|
|
491
|
+
)
|
|
492
|
+
load_location = loaded_adapter._core
|
|
493
|
+
elif isinstance(location, OffDeckType):
|
|
494
|
+
load_location = location
|
|
495
|
+
else:
|
|
496
|
+
load_location = validation.ensure_and_convert_deck_slot(
|
|
497
|
+
location, self._api_version, self._core.robot_type
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
labware_core = self._core.load_labware(
|
|
501
|
+
load_name=load_name,
|
|
502
|
+
location=load_location,
|
|
503
|
+
label=label if label is None else str(label),
|
|
504
|
+
namespace=namespace,
|
|
505
|
+
version=version,
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
if lid is not None:
|
|
509
|
+
if self._api_version < validation.LID_STACK_VERSION_GATE:
|
|
510
|
+
raise APIVersionError(
|
|
511
|
+
api_element="Loading a Lid on a Labware",
|
|
512
|
+
until_version=f"{validation.LID_STACK_VERSION_GATE}",
|
|
513
|
+
current_version=f"{self._api_version}",
|
|
514
|
+
)
|
|
515
|
+
self._core.load_lid(
|
|
516
|
+
load_name=lid,
|
|
517
|
+
location=labware_core,
|
|
518
|
+
namespace=namespace,
|
|
519
|
+
version=version,
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
labware = Labware(
|
|
523
|
+
core=labware_core,
|
|
524
|
+
api_version=self._api_version,
|
|
525
|
+
protocol_core=self._core,
|
|
526
|
+
core_map=self._core_map,
|
|
527
|
+
)
|
|
528
|
+
self._core_map.add(labware_core, labware)
|
|
529
|
+
|
|
530
|
+
return labware
|
|
531
|
+
|
|
532
|
+
@requires_version(2, 0)
|
|
533
|
+
def load_labware_by_name(
|
|
534
|
+
self,
|
|
535
|
+
load_name: str,
|
|
536
|
+
location: DeckLocation,
|
|
537
|
+
label: Optional[str] = None,
|
|
538
|
+
namespace: Optional[str] = None,
|
|
539
|
+
version: int = 1,
|
|
540
|
+
) -> Labware:
|
|
541
|
+
"""
|
|
542
|
+
.. deprecated:: 2.0
|
|
543
|
+
Use :py:meth:`load_labware` instead.
|
|
544
|
+
"""
|
|
545
|
+
logger.warning("load_labware_by_name is deprecated. Use load_labware instead.")
|
|
546
|
+
return self.load_labware(load_name, location, label, namespace, version)
|
|
547
|
+
|
|
548
|
+
@requires_version(2, 15)
|
|
549
|
+
def load_adapter_from_definition(
|
|
550
|
+
self,
|
|
551
|
+
adapter_def: "LabwareDefinition",
|
|
552
|
+
location: Union[DeckLocation, OffDeckType],
|
|
553
|
+
) -> Labware:
|
|
554
|
+
"""Specify the presence of an adapter on the deck.
|
|
555
|
+
|
|
556
|
+
This function loads the adapter definition specified by ``adapter_def``
|
|
557
|
+
to the location specified by ``location``.
|
|
558
|
+
|
|
559
|
+
:param adapter_def: The adapter's labware definition.
|
|
560
|
+
:param location: The slot into which to load the labware,
|
|
561
|
+
such as ``1``, ``"1"``, or ``"D1"``. See :ref:`deck-slots`.
|
|
562
|
+
:type location: int or str or :py:obj:`OFF_DECK`
|
|
563
|
+
"""
|
|
564
|
+
load_params = self._core.add_labware_definition(adapter_def)
|
|
565
|
+
|
|
566
|
+
return self.load_adapter(
|
|
567
|
+
load_name=load_params.load_name,
|
|
568
|
+
namespace=load_params.namespace,
|
|
569
|
+
version=load_params.version,
|
|
570
|
+
location=location,
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
@requires_version(2, 16)
|
|
574
|
+
def load_trash_bin(self, location: DeckLocation) -> TrashBin:
|
|
575
|
+
"""Load a trash bin on the deck of a Flex.
|
|
576
|
+
|
|
577
|
+
See :ref:`configure-trash-bin` for details.
|
|
578
|
+
|
|
579
|
+
If you try to load a trash bin on an OT-2, the API will raise an error.
|
|
580
|
+
|
|
581
|
+
:param location: The :ref:`deck slot <deck-slots>` where the trash bin is. The
|
|
582
|
+
location can be any unoccupied slot in column 1 or 3.
|
|
583
|
+
|
|
584
|
+
If you try to load a trash bin in column 2 or 4, the API will raise an error.
|
|
585
|
+
"""
|
|
586
|
+
slot_name = validation.ensure_and_convert_deck_slot(
|
|
587
|
+
location,
|
|
588
|
+
api_version=self._api_version,
|
|
589
|
+
robot_type=self._core.robot_type,
|
|
590
|
+
)
|
|
591
|
+
if not isinstance(slot_name, DeckSlotName):
|
|
592
|
+
raise ValueError("Staging areas not permitted for trash bin.")
|
|
593
|
+
addressable_area_name = validation.ensure_and_convert_trash_bin_location(
|
|
594
|
+
location,
|
|
595
|
+
api_version=self._api_version,
|
|
596
|
+
robot_type=self._core.robot_type,
|
|
597
|
+
)
|
|
598
|
+
trash_bin = self._core.load_trash_bin(slot_name, addressable_area_name)
|
|
599
|
+
return trash_bin
|
|
600
|
+
|
|
601
|
+
@requires_version(2, 16)
|
|
602
|
+
def load_waste_chute(
|
|
603
|
+
self,
|
|
604
|
+
) -> WasteChute:
|
|
605
|
+
"""Load the waste chute on the deck of a Flex.
|
|
606
|
+
|
|
607
|
+
See :ref:`configure-waste-chute` for details, including the deck configuration
|
|
608
|
+
variants of the waste chute.
|
|
609
|
+
|
|
610
|
+
The deck plate adapter for the waste chute can only go in slot D3. If you try to
|
|
611
|
+
load another item in slot D3 after loading the waste chute, or vice versa, the
|
|
612
|
+
API will raise an error.
|
|
613
|
+
"""
|
|
614
|
+
return self._core.load_waste_chute()
|
|
615
|
+
|
|
616
|
+
@requires_version(2, 15)
|
|
617
|
+
def load_adapter(
|
|
618
|
+
self,
|
|
619
|
+
load_name: str,
|
|
620
|
+
location: Union[DeckLocation, OffDeckType],
|
|
621
|
+
namespace: Optional[str] = None,
|
|
622
|
+
version: Optional[int] = None,
|
|
623
|
+
) -> Labware:
|
|
624
|
+
"""Load an adapter onto a location.
|
|
625
|
+
|
|
626
|
+
For adapters already defined by Opentrons, this is a convenient way
|
|
627
|
+
to collapse the two stages of adapter initialization (creating
|
|
628
|
+
the adapter and adding it to the protocol) into one.
|
|
629
|
+
|
|
630
|
+
This function returns the created and initialized adapter for use
|
|
631
|
+
later in the protocol.
|
|
632
|
+
|
|
633
|
+
:param str load_name: A string to use for looking up a labware definition for the adapter.
|
|
634
|
+
You can find the ``load_name`` for any standard adapter on the Opentrons
|
|
635
|
+
`Labware Library <https://labware.opentrons.com>`_.
|
|
636
|
+
|
|
637
|
+
:param location: Either a :ref:`deck slot <deck-slots>`,
|
|
638
|
+
like ``1``, ``"1"``, or ``"D1"``, or the special value :py:obj:`OFF_DECK`.
|
|
639
|
+
|
|
640
|
+
:type location: int or str or :py:obj:`OFF_DECK`
|
|
641
|
+
|
|
642
|
+
:param str namespace: The namespace that the labware definition belongs to.
|
|
643
|
+
If unspecified, the API will automatically search two namespaces:
|
|
644
|
+
|
|
645
|
+
* ``"opentrons"``, to load standard Opentrons labware definitions.
|
|
646
|
+
* ``"custom_beta"``, to load custom labware definitions created with the
|
|
647
|
+
`Custom Labware Creator <https://labware.opentrons.com/create>`_.
|
|
648
|
+
|
|
649
|
+
You might need to specify an explicit ``namespace`` if you have a custom
|
|
650
|
+
definition whose ``load_name`` is the same as an Opentrons standard
|
|
651
|
+
definition, and you want to explicitly choose one or the other.
|
|
652
|
+
|
|
653
|
+
:param version: The version of the labware definition. You should normally
|
|
654
|
+
leave this unspecified to let ``load_adapter()`` choose a version automatically.
|
|
655
|
+
"""
|
|
656
|
+
load_name = validation.ensure_lowercase_name(load_name)
|
|
657
|
+
load_location: Union[OffDeckType, DeckSlotName, StagingSlotName]
|
|
658
|
+
if isinstance(location, OffDeckType):
|
|
659
|
+
load_location = location
|
|
660
|
+
else:
|
|
661
|
+
load_location = validation.ensure_and_convert_deck_slot(
|
|
662
|
+
location, self._api_version, self._core.robot_type
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
labware_core = self._core.load_adapter(
|
|
666
|
+
load_name=load_name,
|
|
667
|
+
location=load_location,
|
|
668
|
+
namespace=namespace,
|
|
669
|
+
version=version,
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
adapter = Labware(
|
|
673
|
+
core=labware_core,
|
|
674
|
+
api_version=self._api_version,
|
|
675
|
+
protocol_core=self._core,
|
|
676
|
+
core_map=self._core_map,
|
|
677
|
+
)
|
|
678
|
+
self._core_map.add(labware_core, adapter)
|
|
679
|
+
|
|
680
|
+
return adapter
|
|
681
|
+
|
|
682
|
+
# TODO(mm, 2023-06-07): Figure out what to do with this, now that the Flex has non-integer
|
|
683
|
+
# slot names and labware can be stacked. https://opentrons.atlassian.net/browse/RLAB-354
|
|
684
|
+
@property
|
|
685
|
+
@requires_version(2, 0)
|
|
686
|
+
def loaded_labwares(self) -> Dict[int, Labware]:
|
|
687
|
+
"""Get the labwares that have been loaded into the protocol context.
|
|
688
|
+
|
|
689
|
+
Slots with nothing in them will not be present in the return value.
|
|
690
|
+
|
|
691
|
+
.. note::
|
|
692
|
+
|
|
693
|
+
If a module is present on the deck but no labware has been loaded
|
|
694
|
+
into it with ``module.load_labware()``, there will
|
|
695
|
+
be no entry for that slot in this value. That means you should not
|
|
696
|
+
use ``loaded_labwares`` to determine if a slot is available or not,
|
|
697
|
+
only to get a list of labwares. If you want a data structure of all
|
|
698
|
+
objects on the deck regardless of type, use :py:attr:`deck`.
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
:returns: Dict mapping deck slot number to labware, sorted in order of
|
|
702
|
+
the locations.
|
|
703
|
+
"""
|
|
704
|
+
labware_cores = (
|
|
705
|
+
(core.get_deck_slot(), core) for core in self._core.get_labware_cores()
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
return {
|
|
709
|
+
slot.as_int(): self._core_map.get(core)
|
|
710
|
+
for slot, core in labware_cores
|
|
711
|
+
if slot is not None
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
@requires_version(2, 15)
|
|
715
|
+
def move_labware(
|
|
716
|
+
self,
|
|
717
|
+
labware: Labware,
|
|
718
|
+
new_location: Union[
|
|
719
|
+
DeckLocation, Labware, ModuleTypes, OffDeckType, WasteChute, TrashBin
|
|
720
|
+
],
|
|
721
|
+
use_gripper: bool = False,
|
|
722
|
+
pick_up_offset: Optional[Mapping[str, float]] = None,
|
|
723
|
+
drop_offset: Optional[Mapping[str, float]] = None,
|
|
724
|
+
) -> None:
|
|
725
|
+
"""Move a loaded labware to a new location.
|
|
726
|
+
|
|
727
|
+
See :ref:`moving-labware` for more details.
|
|
728
|
+
|
|
729
|
+
:param labware: The labware to move. It should be a labware already loaded
|
|
730
|
+
using :py:meth:`load_labware`.
|
|
731
|
+
|
|
732
|
+
:param new_location: Where to move the labware to. This is either:
|
|
733
|
+
|
|
734
|
+
* A deck slot like ``1``, ``"1"``, or ``"D1"``. See :ref:`deck-slots`.
|
|
735
|
+
* A hardware module that's already been loaded on the deck
|
|
736
|
+
with :py:meth:`load_module`.
|
|
737
|
+
* A labware or adapter that's already been loaded on the deck
|
|
738
|
+
with :py:meth:`load_labware` or :py:meth:`load_adapter`.
|
|
739
|
+
* The special constant :py:obj:`OFF_DECK`.
|
|
740
|
+
|
|
741
|
+
:param use_gripper: Whether to use the Flex Gripper for this movement.
|
|
742
|
+
|
|
743
|
+
* If ``True``, use the gripper to perform an automatic
|
|
744
|
+
movement. This will raise an error in an OT-2 protocol.
|
|
745
|
+
* If ``False``, pause protocol execution until the user
|
|
746
|
+
performs the movement. Protocol execution remains paused until
|
|
747
|
+
the user presses **Confirm and resume**.
|
|
748
|
+
|
|
749
|
+
Gripper-only parameters:
|
|
750
|
+
|
|
751
|
+
:param pick_up_offset: Optional x, y, z vector offset to use when picking up labware.
|
|
752
|
+
:param drop_offset: Optional x, y, z vector offset to use when dropping off labware.
|
|
753
|
+
|
|
754
|
+
Before moving a labware to or from a hardware module, make sure that the labware's
|
|
755
|
+
current and new locations are accessible, i.e., open the Thermocycler lid or
|
|
756
|
+
open the Heater-Shaker's labware latch.
|
|
757
|
+
"""
|
|
758
|
+
|
|
759
|
+
if not isinstance(labware, Labware):
|
|
760
|
+
raise ValueError(
|
|
761
|
+
f"Expected labware of type 'Labware' but got {type(labware)}."
|
|
762
|
+
)
|
|
763
|
+
|
|
764
|
+
# Ensure that when moving to an absorbance reader that the lid is open
|
|
765
|
+
# todo(mm, 2024-11-08): Unify this with opentrons.protocol_api.core.engine.deck_conflict.
|
|
766
|
+
if isinstance(new_location, AbsorbanceReaderContext):
|
|
767
|
+
if new_location.is_lid_on():
|
|
768
|
+
raise CommandPreconditionViolated(
|
|
769
|
+
f"Cannot move {labware.name} onto the Absorbance Reader Module when its lid is closed."
|
|
770
|
+
)
|
|
771
|
+
|
|
772
|
+
location: Union[
|
|
773
|
+
ModuleCore,
|
|
774
|
+
LabwareCore,
|
|
775
|
+
WasteChute,
|
|
776
|
+
OffDeckType,
|
|
777
|
+
DeckSlotName,
|
|
778
|
+
StagingSlotName,
|
|
779
|
+
TrashBin,
|
|
780
|
+
]
|
|
781
|
+
if isinstance(new_location, (Labware, ModuleContext)):
|
|
782
|
+
location = new_location._core
|
|
783
|
+
elif isinstance(new_location, (OffDeckType, WasteChute)):
|
|
784
|
+
location = new_location
|
|
785
|
+
elif isinstance(new_location, TrashBin):
|
|
786
|
+
if labware._core.is_lid():
|
|
787
|
+
location = new_location
|
|
788
|
+
else:
|
|
789
|
+
raise LabwareMovementNotAllowedError(
|
|
790
|
+
"Can only dispose of tips and Lid-type labware in a Trash Bin. Did you mean to use a Waste Chute?"
|
|
791
|
+
)
|
|
792
|
+
else:
|
|
793
|
+
location = validation.ensure_and_convert_deck_slot(
|
|
794
|
+
new_location, self._api_version, self._core.robot_type
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
_pick_up_offset = (
|
|
798
|
+
validation.ensure_valid_labware_offset_vector(pick_up_offset)
|
|
799
|
+
if pick_up_offset
|
|
800
|
+
else None
|
|
801
|
+
)
|
|
802
|
+
_drop_offset = (
|
|
803
|
+
validation.ensure_valid_labware_offset_vector(drop_offset)
|
|
804
|
+
if drop_offset
|
|
805
|
+
else None
|
|
806
|
+
)
|
|
807
|
+
with publish_context(
|
|
808
|
+
broker=self.broker,
|
|
809
|
+
command=cmds.move_labware(
|
|
810
|
+
# This needs to be called from protocol context and not the command for import loop reasons
|
|
811
|
+
text=stringify_labware_movement_command(
|
|
812
|
+
labware, new_location, use_gripper
|
|
813
|
+
)
|
|
814
|
+
),
|
|
815
|
+
):
|
|
816
|
+
self._core.move_labware(
|
|
817
|
+
labware_core=labware._core,
|
|
818
|
+
new_location=location,
|
|
819
|
+
use_gripper=use_gripper,
|
|
820
|
+
pause_for_manual_move=True,
|
|
821
|
+
pick_up_offset=_pick_up_offset,
|
|
822
|
+
drop_offset=_drop_offset,
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
@requires_version(2, 0)
|
|
826
|
+
def load_module(
|
|
827
|
+
self,
|
|
828
|
+
module_name: str,
|
|
829
|
+
location: Optional[DeckLocation] = None,
|
|
830
|
+
configuration: Optional[str] = None,
|
|
831
|
+
) -> ModuleTypes:
|
|
832
|
+
"""Load a module onto the deck, given its name or model.
|
|
833
|
+
|
|
834
|
+
This is the function to call to use a module in your protocol, like
|
|
835
|
+
:py:meth:`load_instrument` is the method to call to use an instrument
|
|
836
|
+
in your protocol. It returns the created and initialized module
|
|
837
|
+
context, which will be a different class depending on the kind of
|
|
838
|
+
module loaded.
|
|
839
|
+
|
|
840
|
+
After loading modules, you can access a map of deck positions to loaded modules
|
|
841
|
+
with :py:attr:`loaded_modules`.
|
|
842
|
+
|
|
843
|
+
:param str module_name: The name or model of the module.
|
|
844
|
+
See :ref:`available_modules` for possible values.
|
|
845
|
+
|
|
846
|
+
:param location: The location of the module.
|
|
847
|
+
|
|
848
|
+
This is usually the name or number of the slot on the deck where you
|
|
849
|
+
will be placing the module, like ``1``, ``"1"``, or ``"D1"``. See :ref:`deck-slots`.
|
|
850
|
+
|
|
851
|
+
The Thermocycler is only valid in one deck location.
|
|
852
|
+
You don't have to specify a location when loading it, but if you do,
|
|
853
|
+
it must be ``7``, ``"7"``, or ``"B1"``. See :ref:`thermocycler-module`.
|
|
854
|
+
|
|
855
|
+
.. versionchanged:: 2.15
|
|
856
|
+
You can now specify a deck slot as a coordinate, like ``"D1"``.
|
|
857
|
+
|
|
858
|
+
:param configuration: Configure a Thermocycler to be in the ``semi`` position.
|
|
859
|
+
This parameter does not work. Do not use it.
|
|
860
|
+
|
|
861
|
+
.. versionchanged:: 2.14
|
|
862
|
+
This parameter dangerously modified the protocol's geometry system,
|
|
863
|
+
and it didn't function properly, so it was removed.
|
|
864
|
+
|
|
865
|
+
:type location: str or int or None
|
|
866
|
+
:returns: The loaded and initialized module---a
|
|
867
|
+
:py:class:`HeaterShakerContext`,
|
|
868
|
+
:py:class:`MagneticBlockContext`,
|
|
869
|
+
:py:class:`MagneticModuleContext`,
|
|
870
|
+
:py:class:`TemperatureModuleContext`, or
|
|
871
|
+
:py:class:`ThermocyclerContext`,
|
|
872
|
+
depending on what you requested with ``module_name``.
|
|
873
|
+
|
|
874
|
+
.. versionchanged:: 2.13
|
|
875
|
+
Added ``HeaterShakerContext`` return value.
|
|
876
|
+
|
|
877
|
+
.. versionchanged:: 2.15
|
|
878
|
+
Added ``MagneticBlockContext`` return value.
|
|
879
|
+
|
|
880
|
+
.. TODO uncomment when 2.23 is ready
|
|
881
|
+
versionchanged:: 2.23
|
|
882
|
+
Added ``FlexStackerModuleContext`` return value.
|
|
883
|
+
"""
|
|
884
|
+
if configuration:
|
|
885
|
+
if self._api_version < APIVersion(2, 4):
|
|
886
|
+
raise APIVersionError(
|
|
887
|
+
api_element="Thermocycler parameters",
|
|
888
|
+
until_version="2.4",
|
|
889
|
+
current_version=f"{self._api_version}",
|
|
890
|
+
)
|
|
891
|
+
if self._api_version >= ENGINE_CORE_API_VERSION:
|
|
892
|
+
raise UnsupportedAPIError(
|
|
893
|
+
api_element="The configuration parameter of load_module",
|
|
894
|
+
since_version=f"{ENGINE_CORE_API_VERSION}",
|
|
895
|
+
current_version=f"{self._api_version}",
|
|
896
|
+
)
|
|
897
|
+
|
|
898
|
+
requested_model = validation.ensure_module_model(module_name)
|
|
899
|
+
if isinstance(
|
|
900
|
+
requested_model, MagneticBlockModel
|
|
901
|
+
) and self._api_version < APIVersion(2, 15):
|
|
902
|
+
raise APIVersionError(
|
|
903
|
+
api_element=f"Module of type {module_name}",
|
|
904
|
+
until_version="2.15",
|
|
905
|
+
current_version=f"{self._api_version}",
|
|
906
|
+
)
|
|
907
|
+
if isinstance(
|
|
908
|
+
requested_model, AbsorbanceReaderModel
|
|
909
|
+
) and self._api_version < APIVersion(2, 21):
|
|
910
|
+
raise APIVersionError(
|
|
911
|
+
api_element=f"Module of type {module_name}",
|
|
912
|
+
until_version="2.21",
|
|
913
|
+
current_version=f"{self._api_version}",
|
|
914
|
+
)
|
|
915
|
+
if (
|
|
916
|
+
isinstance(requested_model, FlexStackerModuleModel)
|
|
917
|
+
and self._api_version < validation.FLEX_STACKER_VERSION_GATE
|
|
918
|
+
):
|
|
919
|
+
raise APIVersionError(
|
|
920
|
+
api_element=f"Module of type {module_name}",
|
|
921
|
+
until_version=f"{validation.FLEX_STACKER_VERSION_GATE}",
|
|
922
|
+
current_version=f"{self._api_version}",
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
deck_slot = (
|
|
926
|
+
None
|
|
927
|
+
if location is None
|
|
928
|
+
else validation.ensure_and_convert_deck_slot(
|
|
929
|
+
location, self._api_version, self._core.robot_type
|
|
930
|
+
)
|
|
931
|
+
)
|
|
932
|
+
if isinstance(deck_slot, StagingSlotName):
|
|
933
|
+
# flex stacker modules can only be loaded into staging slot inside a protocol
|
|
934
|
+
if isinstance(requested_model, FlexStackerModuleModel):
|
|
935
|
+
deck_slot = validation.convert_flex_stacker_load_slot(deck_slot)
|
|
936
|
+
else:
|
|
937
|
+
raise ValueError(f"Cannot load {module_name} onto a staging slot.")
|
|
938
|
+
|
|
939
|
+
module_core = self._core.load_module(
|
|
940
|
+
model=requested_model,
|
|
941
|
+
deck_slot=deck_slot,
|
|
942
|
+
configuration=configuration,
|
|
943
|
+
)
|
|
944
|
+
|
|
945
|
+
module_context = _create_module_context(
|
|
946
|
+
module_core=module_core,
|
|
947
|
+
protocol_core=self._core,
|
|
948
|
+
core_map=self._core_map,
|
|
949
|
+
broker=self._broker,
|
|
950
|
+
api_version=self._api_version,
|
|
951
|
+
)
|
|
952
|
+
|
|
953
|
+
self._core_map.add(module_core, module_context)
|
|
954
|
+
|
|
955
|
+
return module_context
|
|
956
|
+
|
|
957
|
+
# TODO(mm, 2023-06-07): Figure out what to do with this, now that the Flex has non-integer
|
|
958
|
+
# slot names and labware can be stacked. https://opentrons.atlassian.net/browse/RLAB-354
|
|
959
|
+
@property
|
|
960
|
+
@requires_version(2, 0)
|
|
961
|
+
def loaded_modules(self) -> Dict[int, ModuleTypes]:
|
|
962
|
+
"""Get the modules loaded into the protocol context.
|
|
963
|
+
|
|
964
|
+
This is a map of deck positions to modules loaded by previous calls to
|
|
965
|
+
:py:meth:`load_module`. It does not reflect what modules are actually attached
|
|
966
|
+
to the robot. For example, if the robot has a Magnetic Module and a Temperature
|
|
967
|
+
Module attached, but the protocol has only loaded the Temperature Module with
|
|
968
|
+
:py:meth:`load_module`, only the Temperature Module will be included in
|
|
969
|
+
``loaded_modules``.
|
|
970
|
+
|
|
971
|
+
:returns: Dict mapping slot name to module contexts. The elements may not be
|
|
972
|
+
ordered by slot number.
|
|
973
|
+
"""
|
|
974
|
+
return {
|
|
975
|
+
core.get_deck_slot().as_int(): self._core_map.get(core)
|
|
976
|
+
for core in self._core.get_module_cores()
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
@requires_version(2, 0)
|
|
980
|
+
def load_instrument(
|
|
981
|
+
self,
|
|
982
|
+
instrument_name: str,
|
|
983
|
+
mount: Union[Mount, str, None] = None,
|
|
984
|
+
tip_racks: Optional[List[Labware]] = None,
|
|
985
|
+
replace: bool = False,
|
|
986
|
+
liquid_presence_detection: Optional[bool] = None,
|
|
987
|
+
) -> InstrumentContext:
|
|
988
|
+
"""Load a specific instrument for use in the protocol.
|
|
989
|
+
|
|
990
|
+
When analyzing the protocol on the robot, instruments loaded with this method
|
|
991
|
+
are compared against the instruments attached to the robot. You won't be able to
|
|
992
|
+
start the protocol until the correct instruments are attached and calibrated.
|
|
993
|
+
|
|
994
|
+
Currently, this method only loads pipettes. You do not need to load the Flex
|
|
995
|
+
Gripper to use it in protocols. See :ref:`automatic-manual-moves`.
|
|
996
|
+
|
|
997
|
+
:param str instrument_name: The instrument to load. See :ref:`new-pipette-models`
|
|
998
|
+
for the valid values.
|
|
999
|
+
:param mount: The mount where the instrument should be attached.
|
|
1000
|
+
This can either be an instance of :py:class:`.types.Mount` or one
|
|
1001
|
+
of the strings ``"left"`` or ``"right"``. When loading a Flex
|
|
1002
|
+
96-Channel Pipette (``instrument_name="flex_96channel_1000"``),
|
|
1003
|
+
you can leave this unspecified, since it always occupies both
|
|
1004
|
+
mounts; if you do specify a value, it will be ignored.
|
|
1005
|
+
:type mount: types.Mount or str or ``None``
|
|
1006
|
+
:param tip_racks: A list of tip racks from which to pick tips when calling
|
|
1007
|
+
:py:meth:`.InstrumentContext.pick_up_tip` without arguments.
|
|
1008
|
+
:type tip_racks: List[:py:class:`.Labware`]
|
|
1009
|
+
:param bool replace: If ``True``, replace the currently loaded instrument in
|
|
1010
|
+
``mount``, if any. This is intended for :ref:`advanced
|
|
1011
|
+
control <advanced-control>` applications. You cannot
|
|
1012
|
+
replace an instrument in the middle of a protocol being run
|
|
1013
|
+
from the Opentrons App or touchscreen.
|
|
1014
|
+
:param bool liquid_presence_detection: If ``True``, enable automatic
|
|
1015
|
+
:ref:`liquid presence detection <lpd>` for Flex 1-, 8-, or 96-channel pipettes.
|
|
1016
|
+
|
|
1017
|
+
.. versionadded:: 2.20
|
|
1018
|
+
"""
|
|
1019
|
+
instrument_name = validation.ensure_lowercase_name(instrument_name)
|
|
1020
|
+
checked_instrument_name = validation.ensure_pipette_name(instrument_name)
|
|
1021
|
+
checked_mount = validation.ensure_mount_for_pipette(
|
|
1022
|
+
mount, checked_instrument_name
|
|
1023
|
+
)
|
|
1024
|
+
|
|
1025
|
+
is_96_channel = checked_instrument_name in [
|
|
1026
|
+
PipetteNameType.P1000_96,
|
|
1027
|
+
PipetteNameType.P200_96,
|
|
1028
|
+
]
|
|
1029
|
+
|
|
1030
|
+
tip_racks = tip_racks or []
|
|
1031
|
+
|
|
1032
|
+
# TODO (tz, 9-12-23): move validation into PE
|
|
1033
|
+
on_right_mount = self._instruments[Mount.RIGHT]
|
|
1034
|
+
if is_96_channel and on_right_mount is not None:
|
|
1035
|
+
raise RuntimeError(
|
|
1036
|
+
f"Instrument already present on right:"
|
|
1037
|
+
f" {on_right_mount.name}. In order to load a 96-channel pipette, both mounts need to be available."
|
|
1038
|
+
)
|
|
1039
|
+
|
|
1040
|
+
existing_instrument = self._instruments[checked_mount]
|
|
1041
|
+
if existing_instrument is not None and not replace:
|
|
1042
|
+
# TODO(mc, 2022-08-25): create specific exception type
|
|
1043
|
+
raise RuntimeError(
|
|
1044
|
+
f"Instrument already present on {checked_mount.name.lower()}:"
|
|
1045
|
+
f" {existing_instrument.name}"
|
|
1046
|
+
)
|
|
1047
|
+
|
|
1048
|
+
logger.info(
|
|
1049
|
+
f"Loading {checked_instrument_name} on {checked_mount.name.lower()} mount"
|
|
1050
|
+
)
|
|
1051
|
+
|
|
1052
|
+
if (
|
|
1053
|
+
self._api_version < APIVersion(2, 20)
|
|
1054
|
+
and liquid_presence_detection is not None
|
|
1055
|
+
):
|
|
1056
|
+
raise APIVersionError(
|
|
1057
|
+
api_element="Liquid Presence Detection",
|
|
1058
|
+
until_version="2.20",
|
|
1059
|
+
current_version=f"{self._api_version}",
|
|
1060
|
+
)
|
|
1061
|
+
if (
|
|
1062
|
+
self._core.robot_type != "OT-3 Standard"
|
|
1063
|
+
and liquid_presence_detection is not None
|
|
1064
|
+
):
|
|
1065
|
+
raise RobotTypeError(
|
|
1066
|
+
"Liquid presence detection only available on Flex robot."
|
|
1067
|
+
)
|
|
1068
|
+
instrument_core = self._core.load_instrument(
|
|
1069
|
+
instrument_name=checked_instrument_name,
|
|
1070
|
+
mount=checked_mount,
|
|
1071
|
+
liquid_presence_detection=liquid_presence_detection or False,
|
|
1072
|
+
)
|
|
1073
|
+
|
|
1074
|
+
for tip_rack in tip_racks:
|
|
1075
|
+
instrument_support.validate_tiprack(
|
|
1076
|
+
instrument_name=instrument_core.get_pipette_name(),
|
|
1077
|
+
tip_rack=tip_rack,
|
|
1078
|
+
log=logger,
|
|
1079
|
+
)
|
|
1080
|
+
|
|
1081
|
+
trash: Optional[Union[Labware, TrashBin]]
|
|
1082
|
+
try:
|
|
1083
|
+
trash = self.fixed_trash
|
|
1084
|
+
except (NoTrashDefinedError, UnsupportedAPIError):
|
|
1085
|
+
trash = None
|
|
1086
|
+
|
|
1087
|
+
instrument = InstrumentContext(
|
|
1088
|
+
core=instrument_core,
|
|
1089
|
+
protocol_core=self._core,
|
|
1090
|
+
broker=self._broker,
|
|
1091
|
+
api_version=self._api_version,
|
|
1092
|
+
tip_racks=tip_racks,
|
|
1093
|
+
trash=trash,
|
|
1094
|
+
requested_as=instrument_name,
|
|
1095
|
+
core_map=self._core_map,
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1098
|
+
self._instruments[checked_mount] = instrument
|
|
1099
|
+
|
|
1100
|
+
return instrument
|
|
1101
|
+
|
|
1102
|
+
@property
|
|
1103
|
+
@requires_version(2, 0)
|
|
1104
|
+
def loaded_instruments(self) -> Dict[str, InstrumentContext]:
|
|
1105
|
+
"""Get the instruments that have been loaded into the protocol.
|
|
1106
|
+
|
|
1107
|
+
This is a map of mount name to instruments previously loaded with
|
|
1108
|
+
:py:meth:`load_instrument`. It does not reflect what instruments are actually
|
|
1109
|
+
installed on the robot. For example, if the robot has instruments installed on
|
|
1110
|
+
both mounts but your protocol has only loaded one of them with
|
|
1111
|
+
:py:meth:`load_instrument`, the unused one will not be included in
|
|
1112
|
+
``loaded_instruments``.
|
|
1113
|
+
|
|
1114
|
+
:returns: A dict mapping mount name (``"left"`` or ``"right"``) to the
|
|
1115
|
+
instrument in that mount. If a mount has no loaded instrument, that key
|
|
1116
|
+
will be missing from the dict.
|
|
1117
|
+
"""
|
|
1118
|
+
return {
|
|
1119
|
+
mount.name.lower(): instr
|
|
1120
|
+
for mount, instr in self._instruments.items()
|
|
1121
|
+
if instr
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
@publish(command=cmds.pause)
|
|
1125
|
+
@requires_version(2, 0)
|
|
1126
|
+
def pause(self, msg: Optional[str] = None) -> None:
|
|
1127
|
+
"""Pause execution of the protocol until it's resumed.
|
|
1128
|
+
|
|
1129
|
+
A human can resume the protocol in the Opentrons App or on the touchscreen.
|
|
1130
|
+
|
|
1131
|
+
.. note::
|
|
1132
|
+
In Python Protocol API version 2.13 and earlier, the pause will only
|
|
1133
|
+
take effect on the next function call that involves moving the robot.
|
|
1134
|
+
|
|
1135
|
+
:param str msg: An optional message to show in the run log entry for the pause step.
|
|
1136
|
+
"""
|
|
1137
|
+
self._core.pause(msg=msg)
|
|
1138
|
+
|
|
1139
|
+
@publish(command=cmds.resume)
|
|
1140
|
+
@requires_version(2, 0)
|
|
1141
|
+
def resume(self) -> None:
|
|
1142
|
+
"""Resume the protocol after :py:meth:`pause`.
|
|
1143
|
+
|
|
1144
|
+
.. deprecated:: 2.12
|
|
1145
|
+
The Python Protocol API supports no safe way for a protocol to resume itself.
|
|
1146
|
+
If you're looking for a way for your protocol to resume automatically
|
|
1147
|
+
after a period of time, use :py:meth:`delay`.
|
|
1148
|
+
"""
|
|
1149
|
+
if self._api_version >= ENGINE_CORE_API_VERSION:
|
|
1150
|
+
raise UnsupportedAPIError(
|
|
1151
|
+
api_element="A Python Protocol safely resuming itself after a pause",
|
|
1152
|
+
since_version=f"{ENGINE_CORE_API_VERSION}",
|
|
1153
|
+
current_version=f"{self._api_version}",
|
|
1154
|
+
extra_message="To wait automatically for a period of time, use ProtocolContext.delay().",
|
|
1155
|
+
)
|
|
1156
|
+
|
|
1157
|
+
# TODO(mc, 2023-02-13): this assert should be enough for mypy
|
|
1158
|
+
# investigate if upgrading mypy allows the `cast` to be removed
|
|
1159
|
+
assert isinstance(self._core, LegacyProtocolCore)
|
|
1160
|
+
cast(LegacyProtocolCore, self._core).resume()
|
|
1161
|
+
|
|
1162
|
+
@publish(command=cmds.comment)
|
|
1163
|
+
@requires_version(2, 0)
|
|
1164
|
+
def comment(self, msg: str) -> None:
|
|
1165
|
+
"""
|
|
1166
|
+
Add a user-readable message to the run log.
|
|
1167
|
+
|
|
1168
|
+
The message is visible anywhere you can view the run log, including the Opentrons App and the touchscreen on Flex.
|
|
1169
|
+
|
|
1170
|
+
.. note::
|
|
1171
|
+
|
|
1172
|
+
The value of the message is computed during protocol analysis,
|
|
1173
|
+
so ``comment()`` can't communicate real-time information during the
|
|
1174
|
+
actual protocol run.
|
|
1175
|
+
"""
|
|
1176
|
+
self._core.comment(msg=msg)
|
|
1177
|
+
|
|
1178
|
+
@publish(command=cmds.delay)
|
|
1179
|
+
@requires_version(2, 0)
|
|
1180
|
+
def delay(
|
|
1181
|
+
self,
|
|
1182
|
+
seconds: float = 0,
|
|
1183
|
+
minutes: float = 0,
|
|
1184
|
+
msg: Optional[str] = None,
|
|
1185
|
+
) -> None:
|
|
1186
|
+
"""Delay protocol execution for a specific amount of time.
|
|
1187
|
+
|
|
1188
|
+
:param float seconds: The time to delay in seconds.
|
|
1189
|
+
:param float minutes: The time to delay in minutes.
|
|
1190
|
+
|
|
1191
|
+
If both ``seconds`` and ``minutes`` are specified, they will be added together.
|
|
1192
|
+
"""
|
|
1193
|
+
delay_time = seconds + minutes * 60
|
|
1194
|
+
self._core.delay(seconds=delay_time, msg=msg)
|
|
1195
|
+
|
|
1196
|
+
@requires_version(2, 0)
|
|
1197
|
+
def home(self) -> None:
|
|
1198
|
+
"""Home the movement system of the robot."""
|
|
1199
|
+
self._core.home()
|
|
1200
|
+
|
|
1201
|
+
@property
|
|
1202
|
+
def location_cache(self) -> Optional[Union[Location, TrashBin, WasteChute]]:
|
|
1203
|
+
"""The cache used by the robot to determine where it last was.
|
|
1204
|
+
|
|
1205
|
+
.. versionchanged:: 2.24
|
|
1206
|
+
Can return a ``TrashBin`` or ``WasteChute`` object.
|
|
1207
|
+
"""
|
|
1208
|
+
last_loc = self._core.get_last_location()
|
|
1209
|
+
if isinstance(last_loc, Location) or self._api_version >= APIVersion(2, 24):
|
|
1210
|
+
return last_loc
|
|
1211
|
+
return None
|
|
1212
|
+
|
|
1213
|
+
@location_cache.setter
|
|
1214
|
+
def location_cache(self, loc: Optional[Location]) -> None:
|
|
1215
|
+
self._core.set_last_location(loc)
|
|
1216
|
+
|
|
1217
|
+
@property
|
|
1218
|
+
@requires_version(2, 0)
|
|
1219
|
+
def deck(self) -> Deck:
|
|
1220
|
+
"""An interface to provide information about what's currently loaded on the deck.
|
|
1221
|
+
This object is useful for determining if a slot on the deck is free.
|
|
1222
|
+
|
|
1223
|
+
This object behaves like a dictionary whose keys are the :ref:`deck slot <deck-slots>` names.
|
|
1224
|
+
For instance, ``deck[1]``, ``deck["1"]``, and ``deck["D1"]``
|
|
1225
|
+
will all return the object loaded in the front-left slot.
|
|
1226
|
+
|
|
1227
|
+
The value for each key depends on what is loaded in the slot:
|
|
1228
|
+
- A :py:obj:`~opentrons.protocol_api.Labware` if the slot contains a labware.
|
|
1229
|
+
- A module context if the slot contains a hardware module.
|
|
1230
|
+
- ``None`` if the slot doesn't contain anything.
|
|
1231
|
+
|
|
1232
|
+
A module that occupies multiple slots is set as the value for all of the
|
|
1233
|
+
relevant slots. Currently, the only multiple-slot module is the Thermocycler.
|
|
1234
|
+
When loaded, the :py:class:`ThermocyclerContext` object is the value for
|
|
1235
|
+
``deck`` keys ``"A1"`` and ``"B1"`` on Flex, and ``7``, ``8``, ``10``, and
|
|
1236
|
+
``11`` on OT-2. In API version 2.13 and earlier, only slot 7 keyed to the
|
|
1237
|
+
Thermocycler object, and slots 8, 10, and 11 keyed to ``None``.
|
|
1238
|
+
|
|
1239
|
+
Rather than filtering the objects in the deck map yourself,
|
|
1240
|
+
you can also use :py:attr:`loaded_labwares` to get a dict of labwares
|
|
1241
|
+
and :py:attr:`loaded_modules` to get a dict of modules.
|
|
1242
|
+
|
|
1243
|
+
For :ref:`advanced-control` *only*, you can delete an element of the ``deck`` dict.
|
|
1244
|
+
This only works for deck slots that contain labware objects. For example, if slot
|
|
1245
|
+
1 contains a labware, ``del protocol.deck["1"]`` will free the slot so you can
|
|
1246
|
+
load another labware there.
|
|
1247
|
+
|
|
1248
|
+
.. warning::
|
|
1249
|
+
Deleting labware from a deck slot does not pause the protocol. Subsequent
|
|
1250
|
+
commands continue immediately. If you need to physically move the labware to
|
|
1251
|
+
reflect the new deck state, add a :py:meth:`.pause` or use
|
|
1252
|
+
:py:meth:`.move_labware` instead.
|
|
1253
|
+
|
|
1254
|
+
.. versionchanged:: 2.14
|
|
1255
|
+
Includes the Thermocycler in all of the slots it occupies.
|
|
1256
|
+
|
|
1257
|
+
.. versionchanged:: 2.15
|
|
1258
|
+
``del`` sets the corresponding labware's location to ``OFF_DECK``.
|
|
1259
|
+
"""
|
|
1260
|
+
return self._deck
|
|
1261
|
+
|
|
1262
|
+
@property
|
|
1263
|
+
@requires_version(2, 0)
|
|
1264
|
+
def fixed_trash(self) -> Union[Labware, TrashBin]:
|
|
1265
|
+
"""The trash fixed to slot 12 of an OT-2's deck.
|
|
1266
|
+
|
|
1267
|
+
In API version 2.15 and earlier, the fixed trash is a :py:class:`.Labware` object with one well. Access it like labware in your protocol. For example, ``protocol.fixed_trash["A1"]``.
|
|
1268
|
+
|
|
1269
|
+
In API version 2.15 only, Flex protocols have a fixed trash in slot A3.
|
|
1270
|
+
|
|
1271
|
+
In API version 2.16 and later, the fixed trash only exists in OT-2 protocols. It is a :py:class:`.TrashBin` object, which doesn't have any wells. Trying to access ``fixed_trash`` in a Flex protocol will raise an error. See :ref:`configure-trash-bin` for details on using the movable trash in Flex protocols.
|
|
1272
|
+
|
|
1273
|
+
.. versionchanged:: 2.16
|
|
1274
|
+
Returns a ``TrashBin`` object.
|
|
1275
|
+
"""
|
|
1276
|
+
if self._api_version >= APIVersion(2, 16):
|
|
1277
|
+
if self._core.robot_type == "OT-3 Standard":
|
|
1278
|
+
raise UnsupportedAPIError(
|
|
1279
|
+
api_element="Fixed Trash",
|
|
1280
|
+
since_version="2.16",
|
|
1281
|
+
current_version=f"{self._api_version}",
|
|
1282
|
+
extra_message="Fixed trash is no longer supported on Flex protocols.",
|
|
1283
|
+
)
|
|
1284
|
+
disposal_locations = self._core.get_disposal_locations()
|
|
1285
|
+
if len(disposal_locations) == 0:
|
|
1286
|
+
raise NoTrashDefinedError(
|
|
1287
|
+
"No trash container has been defined in this protocol."
|
|
1288
|
+
)
|
|
1289
|
+
if isinstance(disposal_locations[0], TrashBin):
|
|
1290
|
+
return disposal_locations[0]
|
|
1291
|
+
|
|
1292
|
+
fixed_trash = self._core_map.get(self._core.fixed_trash)
|
|
1293
|
+
if fixed_trash is None:
|
|
1294
|
+
raise NoTrashDefinedError(
|
|
1295
|
+
"No trash container has been defined in this protocol."
|
|
1296
|
+
)
|
|
1297
|
+
|
|
1298
|
+
return fixed_trash
|
|
1299
|
+
|
|
1300
|
+
def _load_fixed_trash(self) -> None:
|
|
1301
|
+
fixed_trash_core = self._core.fixed_trash
|
|
1302
|
+
if fixed_trash_core is not None:
|
|
1303
|
+
fixed_trash = Labware(
|
|
1304
|
+
core=fixed_trash_core,
|
|
1305
|
+
api_version=self._api_version,
|
|
1306
|
+
protocol_core=self._core,
|
|
1307
|
+
core_map=self._core_map,
|
|
1308
|
+
)
|
|
1309
|
+
self._core_map.add(fixed_trash_core, fixed_trash)
|
|
1310
|
+
|
|
1311
|
+
@requires_version(2, 5)
|
|
1312
|
+
def set_rail_lights(self, on: bool) -> None:
|
|
1313
|
+
"""
|
|
1314
|
+
Controls the robot's ambient lighting (rail lights).
|
|
1315
|
+
|
|
1316
|
+
:param bool on: If ``True``, turn on the lights; otherwise, turn them off.
|
|
1317
|
+
"""
|
|
1318
|
+
self._core.set_rail_lights(on=on)
|
|
1319
|
+
|
|
1320
|
+
@requires_version(2, 14)
|
|
1321
|
+
def define_liquid(
|
|
1322
|
+
self,
|
|
1323
|
+
name: str,
|
|
1324
|
+
description: Union[str, None, _Unset] = _Unset(),
|
|
1325
|
+
display_color: Union[str, None, _Unset] = _Unset(),
|
|
1326
|
+
) -> Liquid:
|
|
1327
|
+
# This first line of the docstring overrides the method signature in our public
|
|
1328
|
+
# docs, which would otherwise have the `_Unset()`s expanded to a bunch of junk.
|
|
1329
|
+
"""
|
|
1330
|
+
define_liquid(self, name: str, description: Optional[str] = None, display_color: Optional[str] = None)
|
|
1331
|
+
|
|
1332
|
+
Define a liquid within a protocol.
|
|
1333
|
+
|
|
1334
|
+
:param str name: A human-readable name for the liquid.
|
|
1335
|
+
:param Optional[str] description: An optional description of the liquid.
|
|
1336
|
+
:param Optional[str] display_color: An optional hex color code, with hash included,
|
|
1337
|
+
to represent the specified liquid. For example, ``"#48B1FA"``.
|
|
1338
|
+
Standard three-value, four-value, six-value, and eight-value syntax are all
|
|
1339
|
+
acceptable.
|
|
1340
|
+
|
|
1341
|
+
:return: A :py:class:`~opentrons.protocol_api.Liquid` object representing the specified liquid.
|
|
1342
|
+
|
|
1343
|
+
.. versionchanged:: 2.20
|
|
1344
|
+
You can now omit the ``description`` and ``display_color`` arguments.
|
|
1345
|
+
Formerly, when you didn't want to provide values, you had to supply
|
|
1346
|
+
``description=None`` and ``display_color=None`` explicitly.
|
|
1347
|
+
"""
|
|
1348
|
+
desc_and_display_color_omittable_since = APIVersion(2, 20)
|
|
1349
|
+
if isinstance(description, _Unset):
|
|
1350
|
+
if self._api_version < desc_and_display_color_omittable_since:
|
|
1351
|
+
raise APIVersionError(
|
|
1352
|
+
api_element="Calling `define_liquid()` without a `description`",
|
|
1353
|
+
until_version=f"{desc_and_display_color_omittable_since}",
|
|
1354
|
+
current_version=f"{self._api_version}",
|
|
1355
|
+
extra_message="Use a newer API version or explicitly supply `description=None`.",
|
|
1356
|
+
)
|
|
1357
|
+
else:
|
|
1358
|
+
description = None
|
|
1359
|
+
if isinstance(display_color, _Unset):
|
|
1360
|
+
if self._api_version < desc_and_display_color_omittable_since:
|
|
1361
|
+
raise APIVersionError(
|
|
1362
|
+
api_element="Calling `define_liquid()` without a `display_color`",
|
|
1363
|
+
until_version=f"{desc_and_display_color_omittable_since}",
|
|
1364
|
+
current_version=f"{self._api_version}",
|
|
1365
|
+
extra_message="Use a newer API version or explicitly supply `display_color=None`.",
|
|
1366
|
+
)
|
|
1367
|
+
else:
|
|
1368
|
+
display_color = None
|
|
1369
|
+
|
|
1370
|
+
return self._core.define_liquid(
|
|
1371
|
+
name=name,
|
|
1372
|
+
description=description,
|
|
1373
|
+
display_color=display_color,
|
|
1374
|
+
)
|
|
1375
|
+
|
|
1376
|
+
@requires_version(2, 24)
|
|
1377
|
+
def get_liquid_class(
|
|
1378
|
+
self,
|
|
1379
|
+
name: str,
|
|
1380
|
+
) -> LiquidClass:
|
|
1381
|
+
"""
|
|
1382
|
+
Get an instance of an Opentrons-verified liquid class for use in a Flex protocol.
|
|
1383
|
+
|
|
1384
|
+
:param name: Name of an Opentrons-verified liquid class. Must be one of:
|
|
1385
|
+
|
|
1386
|
+
- ``"water"``: an Opentrons-verified liquid class based on deionized water.
|
|
1387
|
+
- ``"glycerol_50"``: an Opentrons-verified liquid class for viscous liquid. Based on 50% glycerol.
|
|
1388
|
+
- ``"ethanol_80"``: an Opentrons-verified liquid class for volatile liquid. Based on 80% ethanol.
|
|
1389
|
+
|
|
1390
|
+
:raises: ``LiquidClassDefinitionDoesNotExist``: if the specified liquid class does not exist.
|
|
1391
|
+
|
|
1392
|
+
:returns: A new LiquidClass object.
|
|
1393
|
+
"""
|
|
1394
|
+
return self._core.get_liquid_class(name=name, version=DEFAULT_LC_VERSION)
|
|
1395
|
+
|
|
1396
|
+
@requires_version(2, 24)
|
|
1397
|
+
def define_liquid_class(
|
|
1398
|
+
self,
|
|
1399
|
+
name: str,
|
|
1400
|
+
properties: Dict[str, Dict[str, TransferPropertiesDict]],
|
|
1401
|
+
base_liquid_class: Optional[LiquidClass] = None,
|
|
1402
|
+
display_name: Optional[str] = None,
|
|
1403
|
+
) -> LiquidClass:
|
|
1404
|
+
"""Define a custom liquid class, either based on an existing liquid class, or create a completely new one.
|
|
1405
|
+
|
|
1406
|
+
:param name: The name to give to the new liquid class. Cannot use the name of an Opentrons-verified liquid class.
|
|
1407
|
+
:param properties: A dict of transfer properties for pipette and tip combinations to use for liquid class transfers. The nested dictionary must have top-level keys corresponding to pipette load names and second-level keys corresponding to compatible tip rack load names. Further nested key–value pairs should be as specified in ``TransferPropertiesDict``. See the `liquid class type definitions <https://github.com/Opentrons/opentrons/blob/edge/shared-data/python/opentrons_shared_data/liquid_classes/types.py>`_.
|
|
1408
|
+
|
|
1409
|
+
:param base_liquid_class: An existing liquid class object to base the newly defined liquid class on. The specified ``transfer_properties`` will override any existing properties for the specified pipette and tip combinations. All other properties will remain the same as those in the base class.
|
|
1410
|
+
|
|
1411
|
+
:param display_name: An optional name for the liquid class. Defaults to the title-case ``name`` if a display name isn't provided.
|
|
1412
|
+
|
|
1413
|
+
:returns: A new LiquidClass object.
|
|
1414
|
+
"""
|
|
1415
|
+
if definition_exists(name, DEFAULT_LC_VERSION):
|
|
1416
|
+
raise ValueError(
|
|
1417
|
+
f"Liquid class named {name} already exists. Please specify a different name."
|
|
1418
|
+
)
|
|
1419
|
+
new_liquid_class: LiquidClass
|
|
1420
|
+
if base_liquid_class:
|
|
1421
|
+
# If base liquid is provided, copy to new class
|
|
1422
|
+
# and replace the entries mentioned in transfer props arg
|
|
1423
|
+
new_liquid_class = deepcopy(base_liquid_class)
|
|
1424
|
+
else:
|
|
1425
|
+
new_liquid_class = LiquidClass.create_from(
|
|
1426
|
+
name=name,
|
|
1427
|
+
display_name=display_name or name.title(),
|
|
1428
|
+
by_pipette_setting={},
|
|
1429
|
+
)
|
|
1430
|
+
for pipette, by_tiprack_props in properties.items():
|
|
1431
|
+
for tiprack, transfer_props in by_tiprack_props.items():
|
|
1432
|
+
new_liquid_class.update_for(
|
|
1433
|
+
pipette=pipette,
|
|
1434
|
+
tip_rack=tiprack,
|
|
1435
|
+
transfer_properties=build_transfer_properties(
|
|
1436
|
+
transfer_properties=SharedTransferProperties.model_validate(
|
|
1437
|
+
transfer_props
|
|
1438
|
+
)
|
|
1439
|
+
),
|
|
1440
|
+
)
|
|
1441
|
+
return new_liquid_class
|
|
1442
|
+
|
|
1443
|
+
@property
|
|
1444
|
+
@requires_version(2, 5)
|
|
1445
|
+
def rail_lights_on(self) -> bool:
|
|
1446
|
+
"""Returns ``True`` if the robot's ambient lighting is on."""
|
|
1447
|
+
return self._core.get_rail_lights_on()
|
|
1448
|
+
|
|
1449
|
+
@property
|
|
1450
|
+
@requires_version(2, 5)
|
|
1451
|
+
def door_closed(self) -> bool:
|
|
1452
|
+
"""Returns ``True`` if the front door of the robot is closed."""
|
|
1453
|
+
return self._core.door_closed()
|
|
1454
|
+
|
|
1455
|
+
@requires_version(2, 23)
|
|
1456
|
+
def load_lid_stack(
|
|
1457
|
+
self,
|
|
1458
|
+
load_name: str,
|
|
1459
|
+
location: Union[DeckLocation, Labware],
|
|
1460
|
+
quantity: int,
|
|
1461
|
+
adapter: Optional[str] = None,
|
|
1462
|
+
namespace: Optional[str] = None,
|
|
1463
|
+
version: Optional[int] = None,
|
|
1464
|
+
) -> Labware:
|
|
1465
|
+
"""
|
|
1466
|
+
Load a stack of Opentrons Tough Auto-Sealing Lids onto a valid deck location or adapter.
|
|
1467
|
+
|
|
1468
|
+
:param str load_name: A string to use for looking up a lid definition.
|
|
1469
|
+
You can find the ``load_name`` for any compatible lid on the Opentrons
|
|
1470
|
+
`Labware Library <https://labware.opentrons.com>`_.
|
|
1471
|
+
:param location: Either a :ref:`deck slot <deck-slots>`,
|
|
1472
|
+
like ``1``, ``"1"``, or ``"D1"``, or a valid Opentrons Adapter.
|
|
1473
|
+
:param int quantity: The quantity of lids to be loaded in the stack.
|
|
1474
|
+
:param adapter: An adapter to load the lid stack on top of. Accepts the same
|
|
1475
|
+
values as the ``load_name`` parameter of :py:meth:`.load_adapter`. The
|
|
1476
|
+
adapter will use the same namespace as the lid labware, and the API will
|
|
1477
|
+
choose the adapter's version automatically.
|
|
1478
|
+
:param str namespace: The namespace that the lid labware definition belongs to.
|
|
1479
|
+
If unspecified, the API will automatically search two namespaces:
|
|
1480
|
+
|
|
1481
|
+
- ``"opentrons"``, to load standard Opentrons labware definitions.
|
|
1482
|
+
- ``"custom_beta"``, to load custom labware definitions created with the
|
|
1483
|
+
`Custom Labware Creator <https://labware.opentrons.com/create>`__.
|
|
1484
|
+
|
|
1485
|
+
You might need to specify an explicit ``namespace`` if you have a custom
|
|
1486
|
+
definition whose ``load_name`` is the same as an Opentrons-verified
|
|
1487
|
+
definition, and you want to explicitly choose one or the other.
|
|
1488
|
+
|
|
1489
|
+
:param version: The version of the labware definition. You should normally
|
|
1490
|
+
leave this unspecified to let ``load_lid_stack()`` choose a version
|
|
1491
|
+
automatically.
|
|
1492
|
+
|
|
1493
|
+
:return: The initialized and loaded labware object representing the lid stack.
|
|
1494
|
+
|
|
1495
|
+
.. versionadded:: 2.23
|
|
1496
|
+
|
|
1497
|
+
"""
|
|
1498
|
+
if self._api_version < validation.LID_STACK_VERSION_GATE:
|
|
1499
|
+
raise APIVersionError(
|
|
1500
|
+
api_element="Loading a Lid Stack",
|
|
1501
|
+
until_version=f"{validation.LID_STACK_VERSION_GATE}",
|
|
1502
|
+
current_version=f"{self._api_version}",
|
|
1503
|
+
)
|
|
1504
|
+
|
|
1505
|
+
load_location: Union[DeckSlotName, StagingSlotName, LabwareCore]
|
|
1506
|
+
if isinstance(location, Labware):
|
|
1507
|
+
load_location = location._core
|
|
1508
|
+
else:
|
|
1509
|
+
load_location = validation.ensure_and_convert_deck_slot(
|
|
1510
|
+
location, self._api_version, self._core.robot_type
|
|
1511
|
+
)
|
|
1512
|
+
|
|
1513
|
+
if adapter is not None:
|
|
1514
|
+
if isinstance(load_location, DeckSlotName) or isinstance(
|
|
1515
|
+
load_location, StagingSlotName
|
|
1516
|
+
):
|
|
1517
|
+
loaded_adapter = self.load_adapter(
|
|
1518
|
+
load_name=adapter,
|
|
1519
|
+
location=load_location.value,
|
|
1520
|
+
namespace=namespace,
|
|
1521
|
+
)
|
|
1522
|
+
load_location = loaded_adapter._core
|
|
1523
|
+
else:
|
|
1524
|
+
raise ValueError(
|
|
1525
|
+
"Location cannot be a Labware or Adapter when the 'adapter' field is not None."
|
|
1526
|
+
)
|
|
1527
|
+
|
|
1528
|
+
load_name = validation.ensure_lowercase_name(load_name)
|
|
1529
|
+
|
|
1530
|
+
result = self._core.load_lid_stack(
|
|
1531
|
+
load_name=load_name,
|
|
1532
|
+
location=load_location,
|
|
1533
|
+
quantity=quantity,
|
|
1534
|
+
namespace=namespace,
|
|
1535
|
+
version=version,
|
|
1536
|
+
)
|
|
1537
|
+
|
|
1538
|
+
labware = Labware(
|
|
1539
|
+
core=result,
|
|
1540
|
+
api_version=self._api_version,
|
|
1541
|
+
protocol_core=self._core,
|
|
1542
|
+
core_map=self._core_map,
|
|
1543
|
+
)
|
|
1544
|
+
return labware
|
|
1545
|
+
|
|
1546
|
+
@requires_version(2, 23)
|
|
1547
|
+
def move_lid(
|
|
1548
|
+
self,
|
|
1549
|
+
source_location: Union[DeckLocation, Labware],
|
|
1550
|
+
new_location: Union[DeckLocation, Labware, OffDeckType, WasteChute, TrashBin],
|
|
1551
|
+
use_gripper: bool = False,
|
|
1552
|
+
pick_up_offset: Optional[Mapping[str, float]] = None,
|
|
1553
|
+
drop_offset: Optional[Mapping[str, float]] = None,
|
|
1554
|
+
) -> Labware | None:
|
|
1555
|
+
"""Move a compatible lid from a valid source to a new location. Can return a lid stack if one is created.
|
|
1556
|
+
|
|
1557
|
+
:param source_location: The lid's starting location. This is either:
|
|
1558
|
+
|
|
1559
|
+
* A deck slot like ``1``, ``"1"``, or ``"D1"``. See :ref:`deck-slots`.
|
|
1560
|
+
* A labware or adapter that's already been loaded on the deck
|
|
1561
|
+
with :py:meth:`load_labware` or :py:meth:`load_adapter`.
|
|
1562
|
+
* A lid stack that's already been loaded on the deck with
|
|
1563
|
+
with :py:meth:`load_lid_stack`.
|
|
1564
|
+
|
|
1565
|
+
:param new_location: Where to move the lid to. This is either:
|
|
1566
|
+
|
|
1567
|
+
* A deck slot like ``1``, ``"1"``, or ``"D1"``. See :ref:`deck-slots`.
|
|
1568
|
+
* A hardware module that's already been loaded on the deck
|
|
1569
|
+
with :py:meth:`load_module`.
|
|
1570
|
+
* A labware or adapter that's already been loaded on the deck
|
|
1571
|
+
with :py:meth:`load_labware` or :py:meth:`load_adapter`.
|
|
1572
|
+
* The special constant :py:obj:`OFF_DECK`.
|
|
1573
|
+
|
|
1574
|
+
:param use_gripper: Whether to use the Flex Gripper to move the lid.
|
|
1575
|
+
|
|
1576
|
+
* If ``True``, use the gripper to perform an automatic
|
|
1577
|
+
movement. This will raise an error in an OT-2 protocol.
|
|
1578
|
+
* If ``False``, pause protocol execution until the user
|
|
1579
|
+
performs the movement. Protocol execution remains paused until
|
|
1580
|
+
the user presses **Confirm and resume**.
|
|
1581
|
+
|
|
1582
|
+
Gripper-only parameters:
|
|
1583
|
+
|
|
1584
|
+
:param pick_up_offset: Optional x, y, z vector offset to use when picking up a lid.
|
|
1585
|
+
:param drop_offset: Optional x, y, z vector offset to use when dropping off a lid.
|
|
1586
|
+
|
|
1587
|
+
Before moving a lid to or from a labware in a hardware module, make sure that the
|
|
1588
|
+
labware's current and new locations are accessible, i.e., open the Thermocycler lid
|
|
1589
|
+
or open the Heater-Shaker's labware latch.
|
|
1590
|
+
|
|
1591
|
+
.. versionadded:: 2.23
|
|
1592
|
+
|
|
1593
|
+
"""
|
|
1594
|
+
source: Union[LabwareCore, DeckSlotName, StagingSlotName]
|
|
1595
|
+
if isinstance(source_location, Labware):
|
|
1596
|
+
source = source_location._core
|
|
1597
|
+
else:
|
|
1598
|
+
source = validation.ensure_and_convert_deck_slot(
|
|
1599
|
+
source_location, self._api_version, self._core.robot_type
|
|
1600
|
+
)
|
|
1601
|
+
|
|
1602
|
+
destination: Union[
|
|
1603
|
+
ModuleCore,
|
|
1604
|
+
LabwareCore,
|
|
1605
|
+
WasteChute,
|
|
1606
|
+
OffDeckType,
|
|
1607
|
+
DeckSlotName,
|
|
1608
|
+
StagingSlotName,
|
|
1609
|
+
TrashBin,
|
|
1610
|
+
]
|
|
1611
|
+
if isinstance(new_location, Labware):
|
|
1612
|
+
destination = new_location._core
|
|
1613
|
+
elif isinstance(new_location, (OffDeckType, WasteChute, TrashBin)):
|
|
1614
|
+
destination = new_location
|
|
1615
|
+
else:
|
|
1616
|
+
destination = validation.ensure_and_convert_deck_slot(
|
|
1617
|
+
new_location, self._api_version, self._core.robot_type
|
|
1618
|
+
)
|
|
1619
|
+
|
|
1620
|
+
_pick_up_offset = (
|
|
1621
|
+
validation.ensure_valid_labware_offset_vector(pick_up_offset)
|
|
1622
|
+
if pick_up_offset
|
|
1623
|
+
else None
|
|
1624
|
+
)
|
|
1625
|
+
_drop_offset = (
|
|
1626
|
+
validation.ensure_valid_labware_offset_vector(drop_offset)
|
|
1627
|
+
if drop_offset
|
|
1628
|
+
else None
|
|
1629
|
+
)
|
|
1630
|
+
with publish_context(
|
|
1631
|
+
broker=self.broker,
|
|
1632
|
+
command=cmds.move_labware(
|
|
1633
|
+
# This needs to be called from protocol context and not the command for import loop reasons
|
|
1634
|
+
text=stringify_lid_movement_command(
|
|
1635
|
+
source_location, new_location, use_gripper
|
|
1636
|
+
)
|
|
1637
|
+
),
|
|
1638
|
+
):
|
|
1639
|
+
result = self._core.move_lid(
|
|
1640
|
+
source_location=source,
|
|
1641
|
+
new_location=destination,
|
|
1642
|
+
use_gripper=use_gripper,
|
|
1643
|
+
pause_for_manual_move=True,
|
|
1644
|
+
pick_up_offset=_pick_up_offset,
|
|
1645
|
+
drop_offset=_drop_offset,
|
|
1646
|
+
)
|
|
1647
|
+
if result is not None:
|
|
1648
|
+
return Labware(
|
|
1649
|
+
core=result,
|
|
1650
|
+
api_version=self._api_version,
|
|
1651
|
+
protocol_core=self._core,
|
|
1652
|
+
core_map=self._core_map,
|
|
1653
|
+
)
|
|
1654
|
+
return None
|
|
1655
|
+
|
|
1656
|
+
|
|
1657
|
+
def _create_module_context(
|
|
1658
|
+
module_core: Union[ModuleCore, NonConnectedModuleCore],
|
|
1659
|
+
protocol_core: ProtocolCore,
|
|
1660
|
+
core_map: LoadedCoreMap,
|
|
1661
|
+
api_version: APIVersion,
|
|
1662
|
+
broker: LegacyBroker,
|
|
1663
|
+
) -> ModuleTypes:
|
|
1664
|
+
module_cls: Optional[Type[ModuleTypes]] = None
|
|
1665
|
+
if isinstance(module_core, AbstractTemperatureModuleCore):
|
|
1666
|
+
module_cls = TemperatureModuleContext
|
|
1667
|
+
elif isinstance(module_core, AbstractMagneticModuleCore):
|
|
1668
|
+
module_cls = MagneticModuleContext
|
|
1669
|
+
elif isinstance(module_core, AbstractThermocyclerCore):
|
|
1670
|
+
module_cls = ThermocyclerContext
|
|
1671
|
+
elif isinstance(module_core, AbstractHeaterShakerCore):
|
|
1672
|
+
module_cls = HeaterShakerContext
|
|
1673
|
+
elif isinstance(module_core, AbstractMagneticBlockCore):
|
|
1674
|
+
module_cls = MagneticBlockContext
|
|
1675
|
+
elif isinstance(module_core, AbstractAbsorbanceReaderCore):
|
|
1676
|
+
module_cls = AbsorbanceReaderContext
|
|
1677
|
+
elif isinstance(module_core, AbstractFlexStackerCore):
|
|
1678
|
+
module_cls = FlexStackerContext
|
|
1679
|
+
else:
|
|
1680
|
+
assert False, "Unsupported module type"
|
|
1681
|
+
|
|
1682
|
+
return module_cls(
|
|
1683
|
+
core=module_core,
|
|
1684
|
+
protocol_core=protocol_core,
|
|
1685
|
+
core_map=core_map,
|
|
1686
|
+
api_version=api_version,
|
|
1687
|
+
broker=broker,
|
|
1688
|
+
)
|