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,76 @@
|
|
|
1
|
+
"""Protocol engine types to do with partial tip configurations."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal, Union
|
|
4
|
+
|
|
5
|
+
from pydantic import (
|
|
6
|
+
BaseModel,
|
|
7
|
+
Field,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
NOZZLE_NAME_REGEX = r"[A-Z]\d{1,2}"
|
|
11
|
+
PRIMARY_NOZZLE_LITERAL = Literal["A1", "H1", "A12", "H12"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AllNozzleLayoutConfiguration(BaseModel):
|
|
15
|
+
"""All basemodel to represent a reset to the nozzle configuration. Sending no parameters resets to default."""
|
|
16
|
+
|
|
17
|
+
style: Literal["ALL"] = "ALL"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SingleNozzleLayoutConfiguration(BaseModel):
|
|
21
|
+
"""Minimum information required for a new nozzle configuration."""
|
|
22
|
+
|
|
23
|
+
style: Literal["SINGLE"] = "SINGLE"
|
|
24
|
+
primaryNozzle: PRIMARY_NOZZLE_LITERAL = Field(
|
|
25
|
+
...,
|
|
26
|
+
description="The primary nozzle to use in the layout configuration. This nozzle will update the critical point of the current pipette. For now, this is also the back left corner of your rectangle.",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class RowNozzleLayoutConfiguration(BaseModel):
|
|
31
|
+
"""Minimum information required for a new nozzle configuration."""
|
|
32
|
+
|
|
33
|
+
style: Literal["ROW"] = "ROW"
|
|
34
|
+
primaryNozzle: PRIMARY_NOZZLE_LITERAL = Field(
|
|
35
|
+
...,
|
|
36
|
+
description="The primary nozzle to use in the layout configuration. This nozzle will update the critical point of the current pipette. For now, this is also the back left corner of your rectangle.",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ColumnNozzleLayoutConfiguration(BaseModel):
|
|
41
|
+
"""Information required for nozzle configurations of type ROW and COLUMN."""
|
|
42
|
+
|
|
43
|
+
style: Literal["COLUMN"] = "COLUMN"
|
|
44
|
+
primaryNozzle: PRIMARY_NOZZLE_LITERAL = Field(
|
|
45
|
+
...,
|
|
46
|
+
description="The primary nozzle to use in the layout configuration. This nozzle will update the critical point of the current pipette. For now, this is also the back left corner of your rectangle.",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class QuadrantNozzleLayoutConfiguration(BaseModel):
|
|
51
|
+
"""Information required for nozzle configurations of type QUADRANT."""
|
|
52
|
+
|
|
53
|
+
style: Literal["QUADRANT"] = "QUADRANT"
|
|
54
|
+
primaryNozzle: PRIMARY_NOZZLE_LITERAL = Field(
|
|
55
|
+
...,
|
|
56
|
+
description="The primary nozzle to use in the layout configuration. This nozzle will update the critical point of the current pipette. For now, this is also the back left corner of your rectangle.",
|
|
57
|
+
)
|
|
58
|
+
frontRightNozzle: str = Field(
|
|
59
|
+
...,
|
|
60
|
+
pattern=NOZZLE_NAME_REGEX,
|
|
61
|
+
description="The front right nozzle in your configuration.",
|
|
62
|
+
)
|
|
63
|
+
backLeftNozzle: str = Field(
|
|
64
|
+
...,
|
|
65
|
+
pattern=NOZZLE_NAME_REGEX,
|
|
66
|
+
description="The back left nozzle in your configuration.",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
NozzleLayoutConfigurationType = Union[
|
|
71
|
+
AllNozzleLayoutConfiguration,
|
|
72
|
+
SingleNozzleLayoutConfiguration,
|
|
73
|
+
ColumnNozzleLayoutConfiguration,
|
|
74
|
+
RowNozzleLayoutConfiguration,
|
|
75
|
+
QuadrantNozzleLayoutConfiguration,
|
|
76
|
+
]
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""Protocol Engine types that have to do with runtime parameters."""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, Mapping, Union, Literal, Dict, List
|
|
7
|
+
from pydantic import (
|
|
8
|
+
BaseModel,
|
|
9
|
+
Field,
|
|
10
|
+
StrictBool,
|
|
11
|
+
StrictFloat,
|
|
12
|
+
StrictInt,
|
|
13
|
+
StrictStr,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# TODO (spp, 2024-04-02): move all RTP types to runner
|
|
18
|
+
class RTPBase(BaseModel):
|
|
19
|
+
"""Parameters defined in a protocol."""
|
|
20
|
+
|
|
21
|
+
displayName: StrictStr = Field(..., description="Display string for the parameter.")
|
|
22
|
+
variableName: StrictStr = Field(
|
|
23
|
+
..., description="Python variable name of the parameter."
|
|
24
|
+
)
|
|
25
|
+
description: Optional[StrictStr] = Field(
|
|
26
|
+
None, description="Detailed description of the parameter."
|
|
27
|
+
)
|
|
28
|
+
suffix: Optional[StrictStr] = Field(
|
|
29
|
+
None,
|
|
30
|
+
description="Units (like mL, mm/sec, etc) or a custom suffix for the parameter.",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class NumberParameter(RTPBase):
|
|
35
|
+
"""An integer parameter defined in a protocol."""
|
|
36
|
+
|
|
37
|
+
type: Literal["int", "float"] = Field(
|
|
38
|
+
..., description="String specifying whether the number is an int or float type."
|
|
39
|
+
)
|
|
40
|
+
min: Union[StrictInt, StrictFloat] = Field(
|
|
41
|
+
..., description="Minimum value that the number param is allowed to have."
|
|
42
|
+
)
|
|
43
|
+
max: Union[StrictInt, StrictFloat] = Field(
|
|
44
|
+
..., description="Maximum value that the number param is allowed to have."
|
|
45
|
+
)
|
|
46
|
+
value: Union[StrictInt, StrictFloat] = Field(
|
|
47
|
+
...,
|
|
48
|
+
description="The value assigned to the parameter; if not supplied by the client, will be assigned the default value.",
|
|
49
|
+
)
|
|
50
|
+
default: Union[StrictInt, StrictFloat] = Field(
|
|
51
|
+
...,
|
|
52
|
+
description="Default value of the parameter, to be used when there is no client-specified value.",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class BooleanParameter(RTPBase):
|
|
57
|
+
"""A boolean parameter defined in a protocol."""
|
|
58
|
+
|
|
59
|
+
type: Literal["bool"] = Field(
|
|
60
|
+
default="bool", description="String specifying the type of this parameter"
|
|
61
|
+
)
|
|
62
|
+
value: StrictBool = Field(
|
|
63
|
+
...,
|
|
64
|
+
description="The value assigned to the parameter; if not supplied by the client, will be assigned the default value.",
|
|
65
|
+
)
|
|
66
|
+
default: StrictBool = Field(
|
|
67
|
+
...,
|
|
68
|
+
description="Default value of the parameter, to be used when there is no client-specified value.",
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class EnumChoice(BaseModel):
|
|
73
|
+
"""Components of choices used in RTP Enum Parameters."""
|
|
74
|
+
|
|
75
|
+
displayName: StrictStr = Field(
|
|
76
|
+
..., description="Display string for the param's choice."
|
|
77
|
+
)
|
|
78
|
+
value: Union[StrictInt, StrictFloat, StrictStr] = Field(
|
|
79
|
+
..., description="Enum value of the param's choice."
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class EnumParameter(RTPBase):
|
|
84
|
+
"""A string enum defined in a protocol."""
|
|
85
|
+
|
|
86
|
+
type: Literal["int", "float", "str"] = Field(
|
|
87
|
+
...,
|
|
88
|
+
description="String specifying whether the parameter is an int or float or string type.",
|
|
89
|
+
)
|
|
90
|
+
choices: List[EnumChoice] = Field(
|
|
91
|
+
..., description="List of valid choices for this parameter."
|
|
92
|
+
)
|
|
93
|
+
value: Union[StrictInt, StrictFloat, StrictStr] = Field(
|
|
94
|
+
...,
|
|
95
|
+
description="The value assigned to the parameter; if not supplied by the client, will be assigned the default value.",
|
|
96
|
+
)
|
|
97
|
+
default: Union[StrictInt, StrictFloat, StrictStr] = Field(
|
|
98
|
+
...,
|
|
99
|
+
description="Default value of the parameter, to be used when there is no client-specified value.",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class FileInfo(BaseModel):
|
|
104
|
+
"""A file UUID descriptor."""
|
|
105
|
+
|
|
106
|
+
id: str = Field(
|
|
107
|
+
...,
|
|
108
|
+
description="The UUID identifier of the file stored on the robot.",
|
|
109
|
+
)
|
|
110
|
+
name: str = Field(..., description="Name of the file, including the extension.")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class CSVParameter(RTPBase):
|
|
114
|
+
"""A CSV file parameter defined in a protocol."""
|
|
115
|
+
|
|
116
|
+
type: Literal["csv_file"] = Field(
|
|
117
|
+
default="csv_file", description="String specifying the type of this parameter"
|
|
118
|
+
)
|
|
119
|
+
file: Optional[FileInfo] = Field(
|
|
120
|
+
default=None,
|
|
121
|
+
description="ID of the CSV file stored on the robot; to be used for fetching the CSV file."
|
|
122
|
+
" For local analysis this will most likely be empty.",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
RunTimeParameter = Union[NumberParameter, EnumParameter, BooleanParameter, CSVParameter]
|
|
127
|
+
|
|
128
|
+
PrimitiveRunTimeParamValuesType = Mapping[
|
|
129
|
+
StrictStr, Union[StrictInt, StrictFloat, StrictBool, StrictStr]
|
|
130
|
+
] # update value types as more RTP types are added
|
|
131
|
+
|
|
132
|
+
CSVRunTimeParamFilesType = Mapping[StrictStr, StrictStr]
|
|
133
|
+
CSVRuntimeParamPaths = Dict[str, Path]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Protocol Engine types to deal with tips."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass(frozen=True)
|
|
7
|
+
class TipGeometry:
|
|
8
|
+
"""Tip geometry data.
|
|
9
|
+
|
|
10
|
+
Props:
|
|
11
|
+
length: The effective length (total length minus overlap) of a tip in mm.
|
|
12
|
+
diameter: Tip diameter in mm.
|
|
13
|
+
volume: Maximum volume in µL.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
length: float
|
|
17
|
+
diameter: float
|
|
18
|
+
volume: float
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Protocol engine utility types for model components."""
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class Dimensions:
|
|
9
|
+
"""Dimensions of an object in deck-space."""
|
|
10
|
+
|
|
11
|
+
x: float
|
|
12
|
+
y: float
|
|
13
|
+
z: float
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Vec3f(BaseModel):
|
|
17
|
+
"""A 3D vector of floats."""
|
|
18
|
+
|
|
19
|
+
x: float
|
|
20
|
+
y: float
|
|
21
|
+
z: float
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Protocol engine types to do with positions inside wells."""
|
|
2
|
+
from enum import Enum, auto
|
|
3
|
+
from typing import Union, Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class WellOrigin(str, Enum):
|
|
9
|
+
"""Origin of WellLocation offset.
|
|
10
|
+
|
|
11
|
+
Props:
|
|
12
|
+
TOP: the top-center of the well
|
|
13
|
+
BOTTOM: the bottom-center of the well
|
|
14
|
+
CENTER: the middle-center of the well
|
|
15
|
+
MENISCUS: the meniscus-center of the well
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
TOP = "top"
|
|
19
|
+
BOTTOM = "bottom"
|
|
20
|
+
CENTER = "center"
|
|
21
|
+
MENISCUS = "meniscus"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PickUpTipWellOrigin(str, Enum):
|
|
25
|
+
"""The origin of a PickUpTipWellLocation offset.
|
|
26
|
+
|
|
27
|
+
Props:
|
|
28
|
+
TOP: the top-center of the well
|
|
29
|
+
BOTTOM: the bottom-center of the well
|
|
30
|
+
CENTER: the middle-center of the well
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
TOP = "top"
|
|
34
|
+
BOTTOM = "bottom"
|
|
35
|
+
CENTER = "center"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DropTipWellOrigin(str, Enum):
|
|
39
|
+
"""The origin of a DropTipWellLocation offset.
|
|
40
|
+
|
|
41
|
+
Props:
|
|
42
|
+
TOP: the top-center of the well
|
|
43
|
+
BOTTOM: the bottom-center of the well
|
|
44
|
+
CENTER: the middle-center of the well
|
|
45
|
+
DEFAULT: the default drop-tip location of the well,
|
|
46
|
+
based on pipette configuration and length of the tip.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
TOP = "top"
|
|
50
|
+
BOTTOM = "bottom"
|
|
51
|
+
CENTER = "center"
|
|
52
|
+
DEFAULT = "default"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class WellLocationFunction(int, Enum):
|
|
56
|
+
"""The type of well location object to be created."""
|
|
57
|
+
|
|
58
|
+
BASE = auto()
|
|
59
|
+
LIQUID_HANDLING = auto()
|
|
60
|
+
PICK_UP_TIP = auto()
|
|
61
|
+
DROP_TIP = auto()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# This is deliberately a separate type from Vec3f to let components default to 0.
|
|
65
|
+
class WellOffset(BaseModel):
|
|
66
|
+
"""An offset vector in (x, y, z)."""
|
|
67
|
+
|
|
68
|
+
x: float = 0
|
|
69
|
+
y: float = 0
|
|
70
|
+
z: float = 0
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class WellLocation(BaseModel):
|
|
74
|
+
"""A relative location in reference to a well's location."""
|
|
75
|
+
|
|
76
|
+
origin: WellOrigin = WellOrigin.TOP
|
|
77
|
+
offset: WellOffset = Field(default_factory=WellOffset)
|
|
78
|
+
volumeOffset: float = Field(
|
|
79
|
+
default=0.0,
|
|
80
|
+
description="""A volume of liquid, in µL, to offset the z-axis offset.""",
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class LiquidHandlingWellLocation(BaseModel):
|
|
85
|
+
"""A relative location in reference to a well's location.
|
|
86
|
+
|
|
87
|
+
To be used with commands that handle liquids.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
origin: WellOrigin = WellOrigin.TOP
|
|
91
|
+
offset: WellOffset = Field(default_factory=WellOffset)
|
|
92
|
+
volumeOffset: Union[float, Literal["operationVolume"]] = Field(
|
|
93
|
+
default=0.0,
|
|
94
|
+
description="""A volume of liquid, in µL, to offset the z-axis offset. When "operationVolume" is specified, this volume is pulled from the command volume parameter.""",
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class PickUpTipWellLocation(BaseModel):
|
|
99
|
+
"""A relative location in reference to a well's location.
|
|
100
|
+
|
|
101
|
+
To be used for picking up tips.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
origin: PickUpTipWellOrigin = PickUpTipWellOrigin.TOP
|
|
105
|
+
offset: WellOffset = Field(default_factory=WellOffset)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class DropTipWellLocation(BaseModel):
|
|
109
|
+
"""Like WellLocation, but for dropping tips.
|
|
110
|
+
|
|
111
|
+
Unlike a typical WellLocation, the location for a drop tip
|
|
112
|
+
defaults to location based on the tip length rather than the well's top.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
origin: DropTipWellOrigin = DropTipWellOrigin.DEFAULT
|
|
116
|
+
offset: WellOffset = Field(default_factory=WellOffset)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
WellLocationType = Union[
|
|
120
|
+
WellLocation,
|
|
121
|
+
LiquidHandlingWellLocation,
|
|
122
|
+
PickUpTipWellLocation,
|
|
123
|
+
DropTipWellLocation,
|
|
124
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Protocol file reading interfaces."""
|
|
2
|
+
|
|
3
|
+
from .protocol_files_invalid_error import ProtocolFilesInvalidError
|
|
4
|
+
from .protocol_reader import ProtocolReader
|
|
5
|
+
from .input_file import AbstractInputFile
|
|
6
|
+
from .protocol_source import (
|
|
7
|
+
ProtocolSource,
|
|
8
|
+
ProtocolSourceFile,
|
|
9
|
+
ProtocolFileRole,
|
|
10
|
+
ProtocolType,
|
|
11
|
+
JsonProtocolConfig,
|
|
12
|
+
PythonProtocolConfig,
|
|
13
|
+
)
|
|
14
|
+
from .file_reader_writer import FileReaderWriter, BufferedFile
|
|
15
|
+
from .file_hasher import FileHasher
|
|
16
|
+
from .extract_labware_definitions import extract_labware_definitions
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
# main interfaces
|
|
20
|
+
"ProtocolReader",
|
|
21
|
+
"extract_labware_definitions",
|
|
22
|
+
# input values
|
|
23
|
+
"AbstractInputFile",
|
|
24
|
+
# errors
|
|
25
|
+
"ProtocolFilesInvalidError",
|
|
26
|
+
# values and types
|
|
27
|
+
"ProtocolSource",
|
|
28
|
+
"ProtocolSourceFile",
|
|
29
|
+
"ProtocolFileRole",
|
|
30
|
+
"ProtocolType",
|
|
31
|
+
"JsonProtocolConfig",
|
|
32
|
+
"PythonProtocolConfig",
|
|
33
|
+
"BufferedFile",
|
|
34
|
+
# helpers
|
|
35
|
+
"FileReaderWriter",
|
|
36
|
+
"FileHasher",
|
|
37
|
+
]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# noqa: D100
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
import anyio
|
|
8
|
+
|
|
9
|
+
from opentrons_shared_data.labware.labware_definition import (
|
|
10
|
+
LabwareDefinition,
|
|
11
|
+
labware_definition_type_adapter,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from .protocol_source import ProtocolFileRole, ProtocolSource, ProtocolType
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def extract_labware_definitions(
|
|
18
|
+
protocol_source: ProtocolSource,
|
|
19
|
+
) -> List[LabwareDefinition]:
|
|
20
|
+
"""Extract all the labware definitions that are in the given protocol source.
|
|
21
|
+
|
|
22
|
+
This accounts for differences between JSON protocols,
|
|
23
|
+
which embed their labware definitions in the main protocol file,
|
|
24
|
+
and Python protocols, which have them in separate sidecar files.
|
|
25
|
+
|
|
26
|
+
May raise an exception if the files are not well-formed. Do not depend on the exact
|
|
27
|
+
exception type. This should not happen if the `ProtocolSource` was acquired from a
|
|
28
|
+
`ProtocolReader`, which should have validated the files.
|
|
29
|
+
"""
|
|
30
|
+
if protocol_source.config.protocol_type == ProtocolType.JSON:
|
|
31
|
+
return await _extract_from_json_protocol_file(path=protocol_source.main_file)
|
|
32
|
+
# If there are any separate labware files, ignore them. This avoids custom
|
|
33
|
+
# labware definitions shadowing the ones intrinsic to the main file, which would
|
|
34
|
+
# be confusing. Note that, at least as of v6.2.0, the Opentrons App sends us
|
|
35
|
+
# *every* custom labware definition along with *every* protocol.
|
|
36
|
+
|
|
37
|
+
else:
|
|
38
|
+
assert protocol_source.config.protocol_type == ProtocolType.PYTHON
|
|
39
|
+
return [
|
|
40
|
+
await _extract_from_labware_file(file.path)
|
|
41
|
+
for file in protocol_source.files
|
|
42
|
+
if file.role == ProtocolFileRole.LABWARE
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def _extract_from_labware_file(path: Path) -> LabwareDefinition:
|
|
47
|
+
def _do_parse() -> LabwareDefinition:
|
|
48
|
+
return labware_definition_type_adapter.validate_json(path.read_bytes())
|
|
49
|
+
|
|
50
|
+
return await anyio.to_thread.run_sync(_do_parse)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
async def _extract_from_json_protocol_file(path: Path) -> List[LabwareDefinition]:
|
|
54
|
+
def extract_sync(path: Path) -> List[LabwareDefinition]:
|
|
55
|
+
with path.open("rb") as file:
|
|
56
|
+
json_contents = json.load(file)
|
|
57
|
+
# Rely on the file conforming to one of our JSON protocol schemas 3 to 7,
|
|
58
|
+
# which require this labwareDefinitions key.
|
|
59
|
+
unvalidated_definitions = json_contents["labwareDefinitions"].values()
|
|
60
|
+
validated_definitions = [
|
|
61
|
+
labware_definition_type_adapter.validate_python(u)
|
|
62
|
+
for u in unvalidated_definitions
|
|
63
|
+
]
|
|
64
|
+
return validated_definitions
|
|
65
|
+
|
|
66
|
+
return await anyio.to_thread.run_sync(extract_sync, path)
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""File format validation interface."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Iterable
|
|
5
|
+
|
|
6
|
+
import anyio
|
|
7
|
+
from pydantic import ValidationError as PydanticValidationError
|
|
8
|
+
|
|
9
|
+
from opentrons_shared_data.labware.labware_definition import (
|
|
10
|
+
labware_definition_type_adapter,
|
|
11
|
+
)
|
|
12
|
+
from opentrons_shared_data.protocol.models import (
|
|
13
|
+
ProtocolSchemaV6 as JsonProtocolV6,
|
|
14
|
+
ProtocolSchemaV7 as JsonProtocolV7,
|
|
15
|
+
ProtocolSchemaV8 as JsonProtocolV8,
|
|
16
|
+
)
|
|
17
|
+
from opentrons_shared_data.errors.exceptions import PythonException
|
|
18
|
+
|
|
19
|
+
from opentrons.protocols.models.json_protocol import Model as JsonProtocolUpToV5
|
|
20
|
+
|
|
21
|
+
from .file_identifier import (
|
|
22
|
+
IdentifiedFile,
|
|
23
|
+
IdentifiedJsonMain,
|
|
24
|
+
IdentifiedPythonMain,
|
|
25
|
+
IdentifiedLabwareDefinition,
|
|
26
|
+
IdentifiedData,
|
|
27
|
+
)
|
|
28
|
+
from .protocol_files_invalid_error import ProtocolFilesInvalidError
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FileFormatValidationError(ProtocolFilesInvalidError):
|
|
32
|
+
"""Raised when a file does not conform to the format it's supposed to."""
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def _generic_json_failure(
|
|
36
|
+
cls, info: IdentifiedJsonMain, exc: Exception
|
|
37
|
+
) -> FileFormatValidationError:
|
|
38
|
+
return cls(
|
|
39
|
+
message=f"{info.original_file.name} could not be read as a JSON protocol.",
|
|
40
|
+
detail={"kind": "bad-json-protocol"},
|
|
41
|
+
wrapping=[PythonException(exc)],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class FileFormatValidator:
|
|
46
|
+
"""File format validation interface."""
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
async def validate(files: Iterable[IdentifiedFile]) -> None:
|
|
50
|
+
"""Validate that each file actually conforms to the format we think it does."""
|
|
51
|
+
for file in files:
|
|
52
|
+
if isinstance(file, IdentifiedJsonMain):
|
|
53
|
+
await _validate_json_protocol(file)
|
|
54
|
+
elif isinstance(file, IdentifiedPythonMain):
|
|
55
|
+
pass # No more validation to do for Python protocols.
|
|
56
|
+
elif isinstance(file, IdentifiedLabwareDefinition):
|
|
57
|
+
await _validate_labware_definition(file)
|
|
58
|
+
elif isinstance(file, IdentifiedData):
|
|
59
|
+
pass # No more validation to do for bundled data files.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
async def _validate_labware_definition(info: IdentifiedLabwareDefinition) -> None:
|
|
63
|
+
def validate_sync() -> None:
|
|
64
|
+
try:
|
|
65
|
+
labware_definition_type_adapter.validate_python(info.unvalidated_json)
|
|
66
|
+
except PydanticValidationError as e:
|
|
67
|
+
raise FileFormatValidationError(
|
|
68
|
+
message=f"{info.original_file.name} could not be read as a labware definition.",
|
|
69
|
+
detail={"kind": "bad-labware-definition"},
|
|
70
|
+
wrapping=[PythonException(e)],
|
|
71
|
+
) from e
|
|
72
|
+
|
|
73
|
+
await anyio.to_thread.run_sync(validate_sync)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _handle_v8_json_protocol_validation_error(
|
|
77
|
+
info: IdentifiedJsonMain, pve: PydanticValidationError
|
|
78
|
+
) -> None:
|
|
79
|
+
for error in pve.errors():
|
|
80
|
+
if error["loc"] == ("commandSchemaId",) and error["type"] == "type_error.enum":
|
|
81
|
+
# type_error.enum is for "this entry is not in this enum" and happens if you constrain a field by
|
|
82
|
+
# annotating it with Enum, as we now do for command schema IDs
|
|
83
|
+
raise FileFormatValidationError(
|
|
84
|
+
message=(
|
|
85
|
+
f"{info.original_file.name} could not be read as a JSON protocol, in part because its command schema "
|
|
86
|
+
"id is unknown. This protocol may have been exported from a future version of authorship software. "
|
|
87
|
+
"Updating your Opentrons software may help."
|
|
88
|
+
),
|
|
89
|
+
detail={
|
|
90
|
+
"kind": "bad-command-schema-id",
|
|
91
|
+
"command-schema-id": info.unvalidated_json.get(
|
|
92
|
+
"commandSchemaId", "<unknown>"
|
|
93
|
+
),
|
|
94
|
+
},
|
|
95
|
+
wrapping=[PythonException(pve)],
|
|
96
|
+
) from pve
|
|
97
|
+
if (
|
|
98
|
+
error["loc"] == ("labwareDefinitionSchemaId",)
|
|
99
|
+
and error["type"] == "value_error.const"
|
|
100
|
+
):
|
|
101
|
+
# value_error.const is for "this entry is not one of these const values", which is different from type_error.enum
|
|
102
|
+
# for I'm sure a very good reason, and happens if you constrain a field by annotating it with a Literal
|
|
103
|
+
raise FileFormatValidationError(
|
|
104
|
+
message=(
|
|
105
|
+
f"{info.original_file.name} could not be read as a JSON protocol, in part because its labware schema "
|
|
106
|
+
"id is unknown. This protocol may have been exported from a future version of authorship software. "
|
|
107
|
+
"Updating your Opentrons software may help."
|
|
108
|
+
),
|
|
109
|
+
detail={
|
|
110
|
+
"kind": "bad-labware-schema-id",
|
|
111
|
+
"labware-schema-id": info.unvalidated_json.get(
|
|
112
|
+
"labwareDefinitionSchemaId", "<unknown>"
|
|
113
|
+
),
|
|
114
|
+
},
|
|
115
|
+
)
|
|
116
|
+
if error["loc"] == ("liquidSchemaId",) and error["type"] == "value_error.const":
|
|
117
|
+
raise FileFormatValidationError(
|
|
118
|
+
message=(
|
|
119
|
+
f"{info.original_file.name} could not be read as a JSON protocol, in part because its liquid schema "
|
|
120
|
+
"id is unknown. This protocol may have been exported from a future version of authorship software. "
|
|
121
|
+
"Updating your Opentrons software may help."
|
|
122
|
+
),
|
|
123
|
+
detail={
|
|
124
|
+
"kind": "bad-liquid-schema-id",
|
|
125
|
+
"liquid-schema-id": info.unvalidated_json.get(
|
|
126
|
+
"liquidSchemaId", "<unknown>"
|
|
127
|
+
),
|
|
128
|
+
},
|
|
129
|
+
)
|
|
130
|
+
else:
|
|
131
|
+
raise FileFormatValidationError._generic_json_failure(info, pve) from pve
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
async def _validate_json_protocol(info: IdentifiedJsonMain) -> None:
|
|
135
|
+
def validate_sync() -> None:
|
|
136
|
+
if info.schema_version == 8:
|
|
137
|
+
try:
|
|
138
|
+
JsonProtocolV8.model_validate(info.unvalidated_json)
|
|
139
|
+
except PydanticValidationError as pve:
|
|
140
|
+
_handle_v8_json_protocol_validation_error(info, pve)
|
|
141
|
+
else:
|
|
142
|
+
try:
|
|
143
|
+
if info.schema_version == 7:
|
|
144
|
+
JsonProtocolV7.model_validate(info.unvalidated_json)
|
|
145
|
+
elif info.schema_version == 6:
|
|
146
|
+
JsonProtocolV6.model_validate(info.unvalidated_json)
|
|
147
|
+
else:
|
|
148
|
+
JsonProtocolUpToV5.model_validate(info.unvalidated_json)
|
|
149
|
+
except PydanticValidationError as e:
|
|
150
|
+
raise FileFormatValidationError._generic_json_failure(info, e) from e
|
|
151
|
+
|
|
152
|
+
await anyio.to_thread.run_sync(validate_sync)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""File hashing utiliy class."""
|
|
2
|
+
|
|
3
|
+
from typing import Sequence
|
|
4
|
+
import anyio
|
|
5
|
+
import unicodedata
|
|
6
|
+
from hashlib import md5
|
|
7
|
+
from .file_reader_writer import BufferedFile
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# TODO (spp: 2024-06-17): move file hasher to utils
|
|
11
|
+
class FileHasher:
|
|
12
|
+
"""Hashing utility class that hashes a combination of protocol and labware files."""
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
async def hash(files: Sequence[BufferedFile]) -> str:
|
|
16
|
+
"""Sort and hash a sequence of protocol and labware files."""
|
|
17
|
+
return await anyio.to_thread.run_sync(_hash_sync, files)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _hash_sync(files: Sequence[BufferedFile]) -> str:
|
|
21
|
+
sorted_files = sorted(files, key=lambda x: unicodedata.normalize("NFC", x.name))
|
|
22
|
+
name_content_hasher = md5()
|
|
23
|
+
for file in sorted_files:
|
|
24
|
+
name_hash = md5(file.name.encode("utf-8")).digest()
|
|
25
|
+
contents_hash = md5(file.contents).digest()
|
|
26
|
+
name_content_hasher.update(name_hash + contents_hash)
|
|
27
|
+
return name_content_hasher.hexdigest()
|