opentrons 8.6.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of opentrons might be problematic. Click here for more details.
- 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 +501 -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 +183 -0
- opentrons/drivers/asyncio/communication/errors.py +88 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +552 -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/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 +215 -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 +1115 -0
- opentrons/motion_planning/__init__.py +32 -0
- opentrons/motion_planning/adjacent_slots_getters.py +168 -0
- opentrons/motion_planning/deck_conflict.py +396 -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 +348 -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 +1025 -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 +990 -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 +3212 -0
- opentrons/protocol_api/labware.py +1579 -0
- opentrons/protocol_api/module_contexts.py +1425 -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 +326 -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 +349 -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 +58 -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 +1158 -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 +2359 -0
- opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
- opentrons/protocol_engine/state/labware.py +1459 -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 +1500 -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 +308 -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 +303 -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 +848 -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.0a1.dist-info/METADATA +37 -0
- opentrons-8.6.0a1.dist-info/RECORD +600 -0
- opentrons-8.6.0a1.dist-info/WHEEL +4 -0
- opentrons-8.6.0a1.dist-info/entry_points.txt +3 -0
- opentrons-8.6.0a1.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Interfaces to provide data and other external system resources.
|
|
2
|
+
|
|
3
|
+
Classes in this module do not maintain state and can be instantiated
|
|
4
|
+
as needed. Some classes may contain solely static methods.
|
|
5
|
+
"""
|
|
6
|
+
from . import pipette_data_provider
|
|
7
|
+
from . import labware_validation
|
|
8
|
+
from .model_utils import ModelUtils
|
|
9
|
+
from .deck_data_provider import DeckDataProvider, DeckFixedLabware
|
|
10
|
+
from .labware_data_provider import LabwareDataProvider
|
|
11
|
+
from .module_data_provider import ModuleDataProvider
|
|
12
|
+
from .file_provider import FileProvider
|
|
13
|
+
from .ot3_validation import ensure_ot3_hardware
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"ModelUtils",
|
|
18
|
+
"LabwareDataProvider",
|
|
19
|
+
"DeckDataProvider",
|
|
20
|
+
"DeckFixedLabware",
|
|
21
|
+
"ModuleDataProvider",
|
|
22
|
+
"FileProvider",
|
|
23
|
+
"ensure_ot3_hardware",
|
|
24
|
+
"pipette_data_provider",
|
|
25
|
+
"labware_validation",
|
|
26
|
+
]
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""Deck configuration resource provider."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Set, Tuple
|
|
4
|
+
|
|
5
|
+
from opentrons_shared_data.deck.types import (
|
|
6
|
+
DeckDefinitionV5,
|
|
7
|
+
CutoutFixture,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from opentrons.types import DeckSlotName
|
|
11
|
+
|
|
12
|
+
from ..types import (
|
|
13
|
+
AddressableArea,
|
|
14
|
+
AreaType,
|
|
15
|
+
PotentialCutoutFixture,
|
|
16
|
+
DeckPoint,
|
|
17
|
+
Dimensions,
|
|
18
|
+
AddressableOffsetVector,
|
|
19
|
+
)
|
|
20
|
+
from ..errors import (
|
|
21
|
+
CutoutDoesNotExistError,
|
|
22
|
+
FixtureDoesNotExistError,
|
|
23
|
+
AddressableAreaDoesNotExistError,
|
|
24
|
+
SlotDoesNotExistError,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_cutout_position(cutout_id: str, deck_definition: DeckDefinitionV5) -> DeckPoint:
|
|
29
|
+
"""Get the base position of a cutout on the deck."""
|
|
30
|
+
for cutout in deck_definition["locations"]["cutouts"]:
|
|
31
|
+
if cutout_id == cutout["id"]:
|
|
32
|
+
position = cutout["position"]
|
|
33
|
+
return DeckPoint(x=position[0], y=position[1], z=position[2])
|
|
34
|
+
else:
|
|
35
|
+
raise CutoutDoesNotExistError(f"Could not find cutout with name {cutout_id}")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_cutout_fixture(
|
|
39
|
+
cutout_fixture_id: str, deck_definition: DeckDefinitionV5
|
|
40
|
+
) -> CutoutFixture:
|
|
41
|
+
"""Gets cutout fixture from deck that matches the cutout fixture ID provided."""
|
|
42
|
+
for cutout_fixture in deck_definition["cutoutFixtures"]:
|
|
43
|
+
if cutout_fixture["id"] == cutout_fixture_id:
|
|
44
|
+
return cutout_fixture
|
|
45
|
+
raise FixtureDoesNotExistError(
|
|
46
|
+
f"Could not find cutout fixture with name {cutout_fixture_id}"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_provided_addressable_area_names(
|
|
51
|
+
cutout_fixture_id: str, cutout_id: str, deck_definition: DeckDefinitionV5
|
|
52
|
+
) -> List[str]:
|
|
53
|
+
"""Gets a list of the addressable areas provided by the cutout fixture on the cutout."""
|
|
54
|
+
cutout_fixture = get_cutout_fixture(cutout_fixture_id, deck_definition)
|
|
55
|
+
try:
|
|
56
|
+
return cutout_fixture["providesAddressableAreas"][cutout_id]
|
|
57
|
+
except KeyError:
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_addressable_area_display_name(
|
|
62
|
+
addressable_area_name: str, deck_definition: DeckDefinitionV5
|
|
63
|
+
) -> str:
|
|
64
|
+
"""Get the display name for an addressable area name."""
|
|
65
|
+
for addressable_area in deck_definition["locations"]["addressableAreas"]:
|
|
66
|
+
if addressable_area["id"] == addressable_area_name:
|
|
67
|
+
return addressable_area["displayName"]
|
|
68
|
+
raise AddressableAreaDoesNotExistError(
|
|
69
|
+
f"Could not find addressable area with name {addressable_area_name}"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_potential_cutout_fixtures(
|
|
74
|
+
addressable_area_name: str, deck_definition: DeckDefinitionV5
|
|
75
|
+
) -> Tuple[str, Set[PotentialCutoutFixture]]:
|
|
76
|
+
"""Given an addressable area name, gets the cutout ID associated with it and a set of potential fixtures."""
|
|
77
|
+
potential_fixtures = []
|
|
78
|
+
for cutout_fixture in deck_definition["cutoutFixtures"]:
|
|
79
|
+
for cutout_id, provided_areas in cutout_fixture[
|
|
80
|
+
"providesAddressableAreas"
|
|
81
|
+
].items():
|
|
82
|
+
if addressable_area_name in provided_areas:
|
|
83
|
+
potential_fixtures.append(
|
|
84
|
+
PotentialCutoutFixture(
|
|
85
|
+
cutout_id=cutout_id,
|
|
86
|
+
cutout_fixture_id=cutout_fixture["id"],
|
|
87
|
+
provided_addressable_areas=frozenset(provided_areas),
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
# This following logic is making the assumption that every addressable area can only go on one cutout, though
|
|
91
|
+
# it may have multiple cutout fixtures that supply it on that cutout. If this assumption changes, some of the
|
|
92
|
+
# following logic will have to be readjusted
|
|
93
|
+
if not potential_fixtures:
|
|
94
|
+
raise AddressableAreaDoesNotExistError(
|
|
95
|
+
f"{addressable_area_name} is not provided by any cutout fixtures"
|
|
96
|
+
f" in deck definition {deck_definition['otId']}"
|
|
97
|
+
)
|
|
98
|
+
cutout_id = potential_fixtures[0].cutout_id
|
|
99
|
+
assert all(cutout_id == fixture.cutout_id for fixture in potential_fixtures)
|
|
100
|
+
return cutout_id, set(potential_fixtures)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_addressable_area_from_name(
|
|
104
|
+
addressable_area_name: str,
|
|
105
|
+
cutout_position: DeckPoint,
|
|
106
|
+
deck_definition: DeckDefinitionV5,
|
|
107
|
+
) -> AddressableArea:
|
|
108
|
+
"""Given a name and a cutout position, get an addressable area on the deck."""
|
|
109
|
+
for addressable_area in deck_definition["locations"]["addressableAreas"]:
|
|
110
|
+
if addressable_area["id"] == addressable_area_name:
|
|
111
|
+
cutout_id, _ = get_potential_cutout_fixtures(
|
|
112
|
+
addressable_area_name, deck_definition
|
|
113
|
+
)
|
|
114
|
+
base_slot = get_deck_slot_for_cutout_id(cutout_id)
|
|
115
|
+
area_offset = addressable_area["offsetFromCutoutFixture"]
|
|
116
|
+
position = AddressableOffsetVector(
|
|
117
|
+
x=area_offset[0] + cutout_position.x,
|
|
118
|
+
y=area_offset[1] + cutout_position.y,
|
|
119
|
+
z=area_offset[2] + cutout_position.z,
|
|
120
|
+
)
|
|
121
|
+
bounding_box = Dimensions(
|
|
122
|
+
x=addressable_area["boundingBox"]["xDimension"],
|
|
123
|
+
y=addressable_area["boundingBox"]["yDimension"],
|
|
124
|
+
z=addressable_area["boundingBox"]["zDimension"],
|
|
125
|
+
)
|
|
126
|
+
features = addressable_area["features"]
|
|
127
|
+
mating_surface_unit_vector = addressable_area.get("matingSurfaceUnitVector")
|
|
128
|
+
|
|
129
|
+
return AddressableArea(
|
|
130
|
+
area_name=addressable_area["id"],
|
|
131
|
+
area_type=AreaType(addressable_area["areaType"]),
|
|
132
|
+
mating_surface_unit_vector=mating_surface_unit_vector,
|
|
133
|
+
base_slot=base_slot,
|
|
134
|
+
display_name=addressable_area["displayName"],
|
|
135
|
+
bounding_box=bounding_box,
|
|
136
|
+
position=position,
|
|
137
|
+
compatible_module_types=addressable_area.get(
|
|
138
|
+
"compatibleModuleTypes", []
|
|
139
|
+
),
|
|
140
|
+
features=features,
|
|
141
|
+
)
|
|
142
|
+
raise AddressableAreaDoesNotExistError(
|
|
143
|
+
f"Could not find addressable area with name {addressable_area_name}"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def get_deck_slot_for_cutout_id(cutout_id: str) -> DeckSlotName:
|
|
148
|
+
"""Get the corresponding deck slot for an addressable area."""
|
|
149
|
+
try:
|
|
150
|
+
return CUTOUT_TO_DECK_SLOT_MAP[cutout_id]
|
|
151
|
+
except KeyError as e:
|
|
152
|
+
raise CutoutDoesNotExistError(
|
|
153
|
+
f"Could not find data for cutout {cutout_id}"
|
|
154
|
+
) from e
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def get_cutout_id_by_deck_slot_name(slot_name: DeckSlotName) -> str:
|
|
158
|
+
"""Get the Cutout ID of a given Deck Slot by Deck Slot Name."""
|
|
159
|
+
try:
|
|
160
|
+
return DECK_SLOT_TO_CUTOUT_MAP[slot_name]
|
|
161
|
+
except KeyError as e:
|
|
162
|
+
raise SlotDoesNotExistError(
|
|
163
|
+
f"Could not find data for slot {slot_name.value}"
|
|
164
|
+
) from e
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def get_labware_hosting_addressable_area_name_for_cutout_and_cutout_fixture(
|
|
168
|
+
cutout_id: str, cutout_fixture_id: str, deck_definition: DeckDefinitionV5
|
|
169
|
+
) -> str:
|
|
170
|
+
"""Get the first addressable area that can contain labware for a cutout and fixture.
|
|
171
|
+
|
|
172
|
+
This probably isn't relevant outside of labware offset locations, where (for now) nothing
|
|
173
|
+
provides more than one labware-containing addressable area.
|
|
174
|
+
"""
|
|
175
|
+
for cutoutFixture in deck_definition["cutoutFixtures"]:
|
|
176
|
+
if cutoutFixture["id"] != cutout_fixture_id:
|
|
177
|
+
continue
|
|
178
|
+
provided_aas = cutoutFixture["providesAddressableAreas"].get(cutout_id, None)
|
|
179
|
+
if provided_aas is None:
|
|
180
|
+
raise CutoutDoesNotExistError(
|
|
181
|
+
f"{cutout_fixture_id} does not go in {cutout_id}"
|
|
182
|
+
)
|
|
183
|
+
for aa_id in provided_aas:
|
|
184
|
+
for addressable_area in deck_definition["locations"]["addressableAreas"]:
|
|
185
|
+
if addressable_area["id"] != aa_id:
|
|
186
|
+
continue
|
|
187
|
+
# TODO: In deck def v6 this will be easier, but as of right now there isn't really
|
|
188
|
+
# a way to tell from an addressable area whether it takes labware so let's take the
|
|
189
|
+
# first one
|
|
190
|
+
return aa_id
|
|
191
|
+
raise AddressableAreaDoesNotExistError(
|
|
192
|
+
f"Could not find an addressable area that allows labware from cutout fixture {cutout_fixture_id} in cutout {cutout_id}"
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
raise FixtureDoesNotExistError(f"Could not find entry for {cutout_fixture_id}")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# This is a temporary shim while Protocol Engine's conflict-checking code
|
|
199
|
+
# can only take deck slots as input.
|
|
200
|
+
# Long-term solution: Check for conflicts based on bounding boxes, not slot adjacencies.
|
|
201
|
+
# Shorter-term: Change the conflict-checking code to take cutouts instead of deck slots.
|
|
202
|
+
CUTOUT_TO_DECK_SLOT_MAP: dict[str, DeckSlotName] = {
|
|
203
|
+
# OT-2
|
|
204
|
+
"cutout1": DeckSlotName.SLOT_1,
|
|
205
|
+
"cutout2": DeckSlotName.SLOT_2,
|
|
206
|
+
"cutout3": DeckSlotName.SLOT_3,
|
|
207
|
+
"cutout4": DeckSlotName.SLOT_4,
|
|
208
|
+
"cutout5": DeckSlotName.SLOT_5,
|
|
209
|
+
"cutout6": DeckSlotName.SLOT_6,
|
|
210
|
+
"cutout7": DeckSlotName.SLOT_7,
|
|
211
|
+
"cutout8": DeckSlotName.SLOT_8,
|
|
212
|
+
"cutout9": DeckSlotName.SLOT_9,
|
|
213
|
+
"cutout10": DeckSlotName.SLOT_10,
|
|
214
|
+
"cutout11": DeckSlotName.SLOT_11,
|
|
215
|
+
"cutout12": DeckSlotName.FIXED_TRASH,
|
|
216
|
+
# Flex
|
|
217
|
+
"cutoutA1": DeckSlotName.SLOT_A1,
|
|
218
|
+
"cutoutA2": DeckSlotName.SLOT_A2,
|
|
219
|
+
"cutoutA3": DeckSlotName.SLOT_A3,
|
|
220
|
+
"cutoutB1": DeckSlotName.SLOT_B1,
|
|
221
|
+
"cutoutB2": DeckSlotName.SLOT_B2,
|
|
222
|
+
"cutoutB3": DeckSlotName.SLOT_B3,
|
|
223
|
+
"cutoutC1": DeckSlotName.SLOT_C1,
|
|
224
|
+
"cutoutC2": DeckSlotName.SLOT_C2,
|
|
225
|
+
"cutoutC3": DeckSlotName.SLOT_C3,
|
|
226
|
+
"cutoutD1": DeckSlotName.SLOT_D1,
|
|
227
|
+
"cutoutD2": DeckSlotName.SLOT_D2,
|
|
228
|
+
"cutoutD3": DeckSlotName.SLOT_D3,
|
|
229
|
+
}
|
|
230
|
+
DECK_SLOT_TO_CUTOUT_MAP = {
|
|
231
|
+
deck_slot: cutout for cutout, deck_slot in CUTOUT_TO_DECK_SLOT_MAP.items()
|
|
232
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Deck data resource provider."""
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import List, Optional, cast
|
|
4
|
+
from typing_extensions import final
|
|
5
|
+
|
|
6
|
+
import anyio
|
|
7
|
+
|
|
8
|
+
from opentrons_shared_data.deck import (
|
|
9
|
+
load as load_deck,
|
|
10
|
+
DEFAULT_DECK_DEFINITION_VERSION,
|
|
11
|
+
)
|
|
12
|
+
from opentrons_shared_data.deck.types import DeckDefinitionV5
|
|
13
|
+
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
14
|
+
from opentrons.types import DeckSlotName
|
|
15
|
+
|
|
16
|
+
from ..types import (
|
|
17
|
+
DeckSlotLocation,
|
|
18
|
+
DeckType,
|
|
19
|
+
LabwareLocation,
|
|
20
|
+
DeckConfigurationType,
|
|
21
|
+
)
|
|
22
|
+
from .labware_data_provider import LabwareDataProvider
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@final
|
|
26
|
+
@dataclass(frozen=True)
|
|
27
|
+
class DeckFixedLabware:
|
|
28
|
+
"""A labware fixture that is always present on a deck."""
|
|
29
|
+
|
|
30
|
+
labware_id: str
|
|
31
|
+
location: LabwareLocation
|
|
32
|
+
definition: LabwareDefinition
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class DeckDataProvider:
|
|
36
|
+
"""Provider class to wrap deck definition and data retrieval."""
|
|
37
|
+
|
|
38
|
+
_labware_data: LabwareDataProvider
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self, deck_type: DeckType, labware_data: Optional[LabwareDataProvider] = None
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Initialize a DeckDataProvider."""
|
|
44
|
+
self._deck_type = deck_type
|
|
45
|
+
self._labware_data = labware_data or LabwareDataProvider()
|
|
46
|
+
|
|
47
|
+
async def get_deck_definition(self) -> DeckDefinitionV5:
|
|
48
|
+
"""Get a labware definition given the labware's identification."""
|
|
49
|
+
|
|
50
|
+
def sync() -> DeckDefinitionV5:
|
|
51
|
+
return load_deck(
|
|
52
|
+
name=self._deck_type.value, version=DEFAULT_DECK_DEFINITION_VERSION
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return await anyio.to_thread.run_sync(sync)
|
|
56
|
+
|
|
57
|
+
async def get_deck_fixed_labware(
|
|
58
|
+
self,
|
|
59
|
+
load_fixed_trash: bool,
|
|
60
|
+
deck_definition: DeckDefinitionV5,
|
|
61
|
+
deck_configuration: Optional[DeckConfigurationType] = None,
|
|
62
|
+
) -> List[DeckFixedLabware]:
|
|
63
|
+
"""Get a list of all labware fixtures from a given deck definition."""
|
|
64
|
+
labware: List[DeckFixedLabware] = []
|
|
65
|
+
|
|
66
|
+
for fixture in deck_definition["locations"]["legacyFixtures"]:
|
|
67
|
+
labware_id = fixture["id"]
|
|
68
|
+
load_name = cast(Optional[str], fixture.get("labware"))
|
|
69
|
+
slot = cast(Optional[str], fixture.get("slot"))
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
load_fixed_trash
|
|
73
|
+
and load_name is not None
|
|
74
|
+
and slot is not None
|
|
75
|
+
and slot in DeckSlotName._value2member_map_
|
|
76
|
+
):
|
|
77
|
+
deck_slot_location = DeckSlotLocation(
|
|
78
|
+
slotName=DeckSlotName.from_primitive(slot)
|
|
79
|
+
)
|
|
80
|
+
definition = await self._labware_data.get_labware_definition(
|
|
81
|
+
load_name=load_name,
|
|
82
|
+
namespace="opentrons",
|
|
83
|
+
version=1,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
labware.append(
|
|
87
|
+
DeckFixedLabware(
|
|
88
|
+
labware_id=labware_id,
|
|
89
|
+
definition=definition,
|
|
90
|
+
location=deck_slot_location,
|
|
91
|
+
)
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
return labware
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""File interaction resource provider."""
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import List, Optional, Callable, Awaitable, Dict
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
from ..errors import StorageLimitReachedError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
MAXIMUM_CSV_FILE_LIMIT = 400
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GenericCsvTransform:
|
|
12
|
+
"""Generic CSV File Type data for rows of data to be seperated by a delimeter."""
|
|
13
|
+
|
|
14
|
+
filename: str
|
|
15
|
+
rows: List[List[str]]
|
|
16
|
+
delimiter: str = ","
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def build(
|
|
20
|
+
filename: str, rows: List[List[str]], delimiter: str = ","
|
|
21
|
+
) -> "GenericCsvTransform":
|
|
22
|
+
"""Build a Generic CSV datatype class."""
|
|
23
|
+
if "." in filename and not filename.endswith(".csv"):
|
|
24
|
+
raise ValueError(
|
|
25
|
+
f"Provided filename {filename} invalid. Only CSV file format is accepted."
|
|
26
|
+
)
|
|
27
|
+
elif "." not in filename:
|
|
28
|
+
filename = f"{filename}.csv"
|
|
29
|
+
csv = GenericCsvTransform()
|
|
30
|
+
csv.filename = filename
|
|
31
|
+
csv.rows = rows
|
|
32
|
+
csv.delimiter = delimiter
|
|
33
|
+
return csv
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ReadData(BaseModel):
|
|
37
|
+
"""Read Data type containing the wavelength for a Plate Reader read alongside the Measurement Data of that read."""
|
|
38
|
+
|
|
39
|
+
wavelength: int
|
|
40
|
+
data: Dict[str, float]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class PlateReaderData(BaseModel):
|
|
44
|
+
"""Data from a Opentrons Plate Reader Read. Can be converted to CSV template format."""
|
|
45
|
+
|
|
46
|
+
read_results: List[ReadData]
|
|
47
|
+
reference_wavelength: Optional[int] = None
|
|
48
|
+
start_time: datetime
|
|
49
|
+
finish_time: datetime
|
|
50
|
+
serial_number: str
|
|
51
|
+
|
|
52
|
+
def build_generic_csv( # noqa: C901
|
|
53
|
+
self, filename: str, measurement: ReadData
|
|
54
|
+
) -> GenericCsvTransform:
|
|
55
|
+
"""Builds a CSV compatible object containing Plate Reader Measurements.
|
|
56
|
+
|
|
57
|
+
This will also automatically reformat the provided filename to include the wavelength of those measurements.
|
|
58
|
+
"""
|
|
59
|
+
plate_alpharows = ["A", "B", "C", "D", "E", "F", "G", "H"]
|
|
60
|
+
rows = []
|
|
61
|
+
|
|
62
|
+
rows.append(["", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"])
|
|
63
|
+
for i in range(8):
|
|
64
|
+
row = [plate_alpharows[i]]
|
|
65
|
+
for j in range(12):
|
|
66
|
+
row.append(str(measurement.data[f"{plate_alpharows[i]}{j+1}"]))
|
|
67
|
+
rows.append(row)
|
|
68
|
+
for i in range(3):
|
|
69
|
+
rows.append([])
|
|
70
|
+
rows.append(["", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"])
|
|
71
|
+
for i in range(8):
|
|
72
|
+
row = [plate_alpharows[i]]
|
|
73
|
+
for j in range(12):
|
|
74
|
+
row.append("")
|
|
75
|
+
rows.append(row)
|
|
76
|
+
for i in range(3):
|
|
77
|
+
rows.append([])
|
|
78
|
+
rows.append(
|
|
79
|
+
[
|
|
80
|
+
"",
|
|
81
|
+
"ID",
|
|
82
|
+
"Well",
|
|
83
|
+
"Absorbance (OD)",
|
|
84
|
+
"Mean Absorbance (OD)",
|
|
85
|
+
"Absorbance %CV",
|
|
86
|
+
]
|
|
87
|
+
)
|
|
88
|
+
for i in range(3):
|
|
89
|
+
rows.append([])
|
|
90
|
+
rows.append(
|
|
91
|
+
[
|
|
92
|
+
"",
|
|
93
|
+
"ID",
|
|
94
|
+
"Well",
|
|
95
|
+
"Absorbance (OD)",
|
|
96
|
+
"Mean Absorbance (OD)",
|
|
97
|
+
"Dilution Factor",
|
|
98
|
+
"Absorbance %CV",
|
|
99
|
+
]
|
|
100
|
+
)
|
|
101
|
+
rows.append(["1", "Sample 1", "", "", "", "1", "", "", "", "", "", ""])
|
|
102
|
+
for i in range(3):
|
|
103
|
+
rows.append([])
|
|
104
|
+
|
|
105
|
+
# end of file metadata
|
|
106
|
+
rows.append(["Protocol"])
|
|
107
|
+
rows.append(["Assay"])
|
|
108
|
+
rows.append(["Sample Wavelength (nm)", str(measurement.wavelength)])
|
|
109
|
+
if self.reference_wavelength is not None:
|
|
110
|
+
rows.append(["Reference Wavelength (nm)", str(self.reference_wavelength)])
|
|
111
|
+
rows.append(["Serial No.", self.serial_number])
|
|
112
|
+
rows.append(
|
|
113
|
+
["Measurement started at", self.start_time.strftime("%m %d %H:%M:%S %Y")]
|
|
114
|
+
)
|
|
115
|
+
rows.append(
|
|
116
|
+
["Measurement finished at", self.finish_time.strftime("%m %d %H:%M:%S %Y")]
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Ensure the filename adheres to ruleset contains the wavelength for a given measurement
|
|
120
|
+
if filename.endswith(".csv"):
|
|
121
|
+
filename = filename[:-4]
|
|
122
|
+
filename = filename + str(measurement.wavelength) + "nm.csv"
|
|
123
|
+
|
|
124
|
+
return GenericCsvTransform.build(
|
|
125
|
+
filename=filename,
|
|
126
|
+
rows=rows,
|
|
127
|
+
delimiter=",",
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class FileProvider:
|
|
132
|
+
"""Provider class to wrap file read write interactions to the data files directory in the engine."""
|
|
133
|
+
|
|
134
|
+
def __init__(
|
|
135
|
+
self,
|
|
136
|
+
data_files_write_csv_callback: Optional[
|
|
137
|
+
Callable[[GenericCsvTransform], Awaitable[str]]
|
|
138
|
+
] = None,
|
|
139
|
+
data_files_filecount: Optional[Callable[[], Awaitable[int]]] = None,
|
|
140
|
+
) -> None:
|
|
141
|
+
"""Initialize the interface callbacks of the File Provider for data file handling within the Protocol Engine.
|
|
142
|
+
|
|
143
|
+
Params:
|
|
144
|
+
data_files_write_csv_callback: Callback to write a CSV file to the data files directory and add it to the database.
|
|
145
|
+
data_files_filecount: Callback to check the amount of data files already present in the data files directory.
|
|
146
|
+
"""
|
|
147
|
+
self._data_files_write_csv_callback = data_files_write_csv_callback
|
|
148
|
+
self._data_files_filecount = data_files_filecount
|
|
149
|
+
|
|
150
|
+
async def write_csv(self, write_data: GenericCsvTransform) -> str:
|
|
151
|
+
"""Writes the provided CSV object to a file in the Data Files directory. Returns the File ID of the file created."""
|
|
152
|
+
if self._data_files_filecount is not None:
|
|
153
|
+
file_count = await self._data_files_filecount()
|
|
154
|
+
if file_count >= MAXIMUM_CSV_FILE_LIMIT:
|
|
155
|
+
raise StorageLimitReachedError(
|
|
156
|
+
f"Not enough space to store file {write_data.filename}."
|
|
157
|
+
)
|
|
158
|
+
if self._data_files_write_csv_callback is not None:
|
|
159
|
+
return await self._data_files_write_csv_callback(write_data)
|
|
160
|
+
# If we are in an analysis or simulation state, return an empty file ID
|
|
161
|
+
return ""
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Validation file for addressable area reference checking functions."""
|
|
2
|
+
|
|
3
|
+
from opentrons.types import DeckSlotName
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def is_waste_chute(addressable_area_name: str) -> bool:
|
|
7
|
+
"""Check if an addressable area is a Waste Chute."""
|
|
8
|
+
return addressable_area_name in {
|
|
9
|
+
"1ChannelWasteChute",
|
|
10
|
+
"8ChannelWasteChute",
|
|
11
|
+
"96ChannelWasteChute",
|
|
12
|
+
"gripperWasteChute",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def is_gripper_waste_chute(addressable_area_name: str) -> bool:
|
|
17
|
+
"""Check if an addressable area is a gripper-movement-compatible Waste Chute."""
|
|
18
|
+
return addressable_area_name == "gripperWasteChute"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_drop_tip_waste_chute(addressable_area_name: str) -> bool:
|
|
22
|
+
"""Check if an addressable area is a Waste Chute compatible for dropping tips."""
|
|
23
|
+
return addressable_area_name in {
|
|
24
|
+
"1ChannelWasteChute",
|
|
25
|
+
"8ChannelWasteChute",
|
|
26
|
+
"96ChannelWasteChute",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def is_trash(addressable_area_name: str) -> bool:
|
|
31
|
+
"""Check if an addressable area is a trash bin."""
|
|
32
|
+
return any(
|
|
33
|
+
[
|
|
34
|
+
s in addressable_area_name
|
|
35
|
+
for s in {"movableTrash", "fixedTrash", "shortFixedTrash"}
|
|
36
|
+
]
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def is_staging_slot(addressable_area_name: str) -> bool:
|
|
41
|
+
"""Check if an addressable area is a staging area slot."""
|
|
42
|
+
return addressable_area_name in {"A4", "B4", "C4", "D4"}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def is_deck_slot(addressable_area_name: str) -> bool:
|
|
46
|
+
"""Check if an addressable area is a deck slot (including staging area slots)."""
|
|
47
|
+
if is_staging_slot(addressable_area_name):
|
|
48
|
+
return True
|
|
49
|
+
try:
|
|
50
|
+
DeckSlotName.from_primitive(addressable_area_name)
|
|
51
|
+
except ValueError:
|
|
52
|
+
return False
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def is_abs_reader(addressable_area_name: str) -> bool:
|
|
57
|
+
"""Check if an addressable area is an absorbance plate reader area."""
|
|
58
|
+
return "absorbanceReaderV1" in addressable_area_name
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Labware data resource provider.
|
|
2
|
+
|
|
3
|
+
This module is a wrapper around existing, but older, internal APIs to
|
|
4
|
+
abstract away rough edges until we can improve those underlying interfaces.
|
|
5
|
+
"""
|
|
6
|
+
import logging
|
|
7
|
+
from anyio import to_thread
|
|
8
|
+
|
|
9
|
+
from opentrons_shared_data.labware.labware_definition import (
|
|
10
|
+
LabwareDefinition,
|
|
11
|
+
LabwareDefinition3,
|
|
12
|
+
labware_definition_type_adapter,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from opentrons.protocols.labware import get_labware_definition
|
|
16
|
+
|
|
17
|
+
# TODO (lc 09-26-2022) We should conditionally import ot2 or ot3 calibration
|
|
18
|
+
from opentrons.hardware_control.instruments.ot2 import (
|
|
19
|
+
instrument_calibration as instr_cal,
|
|
20
|
+
)
|
|
21
|
+
from opentrons.calibration_storage.types import TipLengthCalNotFound
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
log = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class LabwareDataProvider:
|
|
28
|
+
"""Labware data provider."""
|
|
29
|
+
|
|
30
|
+
@staticmethod
|
|
31
|
+
async def get_labware_definition(
|
|
32
|
+
load_name: str,
|
|
33
|
+
namespace: str,
|
|
34
|
+
version: int,
|
|
35
|
+
) -> LabwareDefinition:
|
|
36
|
+
"""Get a labware definition given the labware's identification.
|
|
37
|
+
|
|
38
|
+
Note: this method hits the filesystem, which will have performance
|
|
39
|
+
implications if it is called often.
|
|
40
|
+
"""
|
|
41
|
+
return await to_thread.run_sync(
|
|
42
|
+
LabwareDataProvider._get_labware_definition_sync,
|
|
43
|
+
load_name,
|
|
44
|
+
namespace,
|
|
45
|
+
version,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def _get_labware_definition_sync(
|
|
50
|
+
load_name: str, namespace: str, version: int
|
|
51
|
+
) -> LabwareDefinition:
|
|
52
|
+
return labware_definition_type_adapter.validate_python(
|
|
53
|
+
get_labware_definition(load_name, namespace, version)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
async def get_calibrated_tip_length(
|
|
58
|
+
pipette_serial: str,
|
|
59
|
+
labware_definition: LabwareDefinition,
|
|
60
|
+
nominal_fallback: float,
|
|
61
|
+
) -> float:
|
|
62
|
+
"""Get the calibrated tip length of a tip rack / pipette pair.
|
|
63
|
+
|
|
64
|
+
Note: this method hits the filesystem, which will have performance
|
|
65
|
+
implications if it is called often.
|
|
66
|
+
"""
|
|
67
|
+
return await to_thread.run_sync(
|
|
68
|
+
LabwareDataProvider._get_calibrated_tip_length_sync,
|
|
69
|
+
pipette_serial,
|
|
70
|
+
labware_definition,
|
|
71
|
+
nominal_fallback,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def _get_calibrated_tip_length_sync(
|
|
76
|
+
pipette_serial: str,
|
|
77
|
+
labware_definition: LabwareDefinition,
|
|
78
|
+
nominal_fallback: float,
|
|
79
|
+
) -> float:
|
|
80
|
+
if isinstance(labware_definition, LabwareDefinition3):
|
|
81
|
+
# FIXME(mm, 2025-02-19): This needs to be resolved for v8.4.0.
|
|
82
|
+
# Tip length calibration internals don't yet support schema 3 because
|
|
83
|
+
# it's probably an incompatible change at the filesystem level
|
|
84
|
+
# (not downgrade-safe), and because robot-server's calibration sessions
|
|
85
|
+
# are built atop opentrons.protocol_api.core.legacy, which does not (yet?)
|
|
86
|
+
# support labware schema 3.
|
|
87
|
+
# https://opentrons.atlassian.net/browse/EXEC-1230
|
|
88
|
+
log.warning(
|
|
89
|
+
f"Tip rack"
|
|
90
|
+
f" {labware_definition.namespace}/{labware_definition.parameters.loadName}/{labware_definition.version}"
|
|
91
|
+
f" has schema 3, so tip length calibration is currently unsupported."
|
|
92
|
+
f" Using nominal fallback of {nominal_fallback}."
|
|
93
|
+
)
|
|
94
|
+
return nominal_fallback
|
|
95
|
+
else:
|
|
96
|
+
try:
|
|
97
|
+
return instr_cal.load_tip_length_for_pipette(
|
|
98
|
+
pipette_serial, labware_definition
|
|
99
|
+
).tip_length
|
|
100
|
+
except TipLengthCalNotFound as e:
|
|
101
|
+
message = (
|
|
102
|
+
f"No calibrated tip length found for {pipette_serial},"
|
|
103
|
+
f" using nominal fallback value of {nominal_fallback}"
|
|
104
|
+
)
|
|
105
|
+
log.debug(message, exc_info=e)
|
|
106
|
+
return nominal_fallback
|