From 187ba1ada8674a76ea734ee70b2515aa2c1899a6 Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:51:52 -0500 Subject: [PATCH 01/42] fix(protocol-designer): blowout field checkbox properly populating (#17093) closes RQA-3792 This was a weird bug only affecting the UI and not any commands being generated. Basically, the blowout checkbox was incorrectly not being selected because there was logic in place to hardcode it to false due to the disposal volume checkbox being true. IDK why the disposal volume checkbox is true -- seems like something we allowed for all move liquid steps back in the day. So for a UI fix, I added the field to be dependent on the disposal volume fields and removed the useEffect in place. --- .../StepForm/StepTools/MoveLiquidTools/index.tsx | 8 -------- .../handleFormChange/dependentFieldsUpdateMoveLiquid.ts | 1 + .../formLevel/handleFormChange/test/moveLiquid.test.ts | 1 + 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/index.tsx index fcb64ff8834..e3b0c2f7828 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/index.tsx @@ -1,4 +1,3 @@ -import { useEffect } from 'react' import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { @@ -134,13 +133,6 @@ export function MoveLiquidTools(props: StepFormProps): JSX.Element { const mappedErrorsToField = getFormErrorsMappedToField(visibleFormErrors) - // auto-collapse blowout field if disposal volume is checked - useEffect(() => { - if (formData.disposalVolume_checkbox) { - propsForFields.blowout_checkbox.updateValue(false) - } - }, [formData.disposalVolume_checkbox]) - return toolboxStep === 0 ? ( { dispense_mix_checkbox: false, dispense_mix_times: null, dispense_mix_volume: null, + blowout_checkbox: false, }) }) From f8cdc82615b5fb2db437ea26728e995e0ff8c8ec Mon Sep 17 00:00:00 2001 From: Anthony Ngumah <68346382+AnthonyNASC20@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:48:04 -0500 Subject: [PATCH 02/42] Changes process calls to speed up code execution (#17099) # Overview Switches to using a queue instead of running a separate print process which speeds up execution of push-folder command Co-authored-by: Rhyann Clarke <146747548+rclarke0@users.noreply.github.com> --- abr-testing/abr_testing/tools/make_push.py | 46 ++++++++++------------ 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/abr-testing/abr_testing/tools/make_push.py b/abr-testing/abr_testing/tools/make_push.py index 28a69b11103..665831158bc 100644 --- a/abr-testing/abr_testing/tools/make_push.py +++ b/abr-testing/abr_testing/tools/make_push.py @@ -1,7 +1,8 @@ """Push one or more folders to one or more robots.""" import subprocess -import multiprocessing import json +from typing import List +from multiprocessing import Process, Queue global folders # Opentrons folders that can be pushed to robot @@ -13,13 +14,13 @@ ] -def push_subroutine(cmd: str) -> None: +def push_subroutine(cmd: str, queue: Queue) -> None: """Pushes specified folder to specified robot.""" try: subprocess.run(cmd) + queue.put(f"{cmd}: SUCCESS!\n") except Exception: - print("failed to push folder") - raise + queue.put(f"{cmd}: FAILED\n") def main(folder_to_push: str, robot_to_push: str) -> int: @@ -27,6 +28,8 @@ def main(folder_to_push: str, robot_to_push: str) -> int: cmd = "make -C {folder} push-ot3 host={ip}" robot_ip_path = "" push_cmd = "" + processes: List[Process] = [] + queue: Queue = Queue() folder_int = int(folder_to_push) if folders[folder_int].lower() == "abr-testing + hardware-testing": if robot_to_push.lower() == "all": @@ -41,20 +44,16 @@ def main(folder_to_push: str, robot_to_push: str) -> int: for folder_name in folders[:-2]: # Push abr-testing and hardware-testing folders to all robots for robot in robot_ips: - print_proc = multiprocessing.Process( - target=print, args=(f"Pushing {folder_name} to {robot}!\n\n",) - ) - print_proc.start() - print_proc.join() push_cmd = cmd.format(folder=folder_name, ip=robot) - process = multiprocessing.Process( - target=push_subroutine, args=(push_cmd,) + process = Process( + target=push_subroutine, + args=( + push_cmd, + queue, + ), ) process.start() - process.join() - print_proc = multiprocessing.Process(target=print, args=("Done!\n\n",)) - print_proc.start() - print_proc.join() + processes.append(process) else: if folder_int == (len(folders) - 1): @@ -72,18 +71,15 @@ def main(folder_to_push: str, robot_to_push: str) -> int: # Push folder to robots for robot in robot_ips: - print_proc = multiprocessing.Process( - target=print, args=(f"Pushing {folder_name} to {robot}!\n\n",) - ) - print_proc.start() - print_proc.join() push_cmd = cmd.format(folder=folder_name, ip=robot) - process = multiprocessing.Process(target=push_subroutine, args=(push_cmd,)) + process = Process(target=push_subroutine, args=(push_cmd, queue)) process.start() - process.join() - print_proc = multiprocessing.Process(target=print, args=("Done!\n\n",)) - print_proc.start() - print_proc.join() + processes.append(process) + + for process in processes: + process.join() + result = queue.get() + print(f"\n{result}") return 0 From 7bb771a2032dc49c9031c95d1f2081d27e95dd0c Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Thu, 12 Dec 2024 16:55:36 -0500 Subject: [PATCH 03/42] fix(app): fix manual file upload (#17098) The electron update made it no longer possible to access the file path from the renderer process, see #17010 for more details. That PR did not update one important case: uploading zip files. Currently, fun behavior happens when uploading a system zip, such as throwing an error or better yet, pushing an old, cache file instead of the expected system file. This commit fixes that. --- .../AdvancedTab/UpdateRobotSoftware.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx index a893c616508..55c64ee648a 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx @@ -23,6 +23,7 @@ import { ExternalLink } from '/app/atoms/Link/ExternalLink' import { TertiaryButton } from '/app/atoms/buttons' import { getRobotUpdateDisplayInfo } from '/app/redux/robot-update' import { useDispatchStartRobotUpdate } from '/app/redux/robot-update/hooks' +import { remote } from '/app/redux/shell/remote' import type { ChangeEventHandler, MouseEventHandler } from 'react' import type { State } from '/app/redux/types' @@ -55,14 +56,19 @@ export function UpdateRobotSoftware({ const handleChange: ChangeEventHandler = event => { const { files } = event.target - if (files?.length === 1 && !updateDisabled) { - dispatchStartRobotUpdate(robotName, files[0].path) - onUpdateStart() - } - // this is to reset the state of the file picker so users can reselect the same - // system image if the upload fails - if (inputRef.current?.value != null) { - inputRef.current.value = '' + + if (files != null) { + void remote.getFilePathFrom(files[0]).then(filePath => { + if (files.length === 1 && !updateDisabled) { + dispatchStartRobotUpdate(robotName, filePath) + onUpdateStart() + } + // this is to reset the state of the file picker so users can reselect the same + // system image if the upload fails + if (inputRef.current?.value != null) { + inputRef.current.value = '' + } + }) } } From a0bd4ee26d470737b59b0ff222e5eb12437aca75 Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Fri, 13 Dec 2024 10:19:52 -0500 Subject: [PATCH 04/42] refactor(app): remove unneeded source maps dependency (#17100) After playing with source map dependencies, it turns out that we don't need the extra library, and the tsconfig source maps are irrelevant due to the way vite bundles source maps. All we need is to keep the existing sourceMaps: true property in our vite.config build options! This cuts the bundle size dramatically: it's now only ~3MB increase. This also fixes an interaction with the source maps library and the network settings tab, causing the app to crash (on the desktop app). --- app/package.json | 2 -- app/src/App/index.tsx | 1 - app/tsconfig.json | 1 - yarn.lock | 16 ---------------- 4 files changed, 20 deletions(-) diff --git a/app/package.json b/app/package.json index 5528120de1f..33ae6252d1a 100644 --- a/app/package.json +++ b/app/package.json @@ -64,7 +64,6 @@ "rxjs": "^6.5.1", "semver": "5.7.2", "simple-keyboard-layouts": "3.4.41", - "source-map-support": "0.5.10", "styled-components": "5.3.6", "typeface-open-sans": "0.0.75", "uuid": "3.2.1" @@ -76,7 +75,6 @@ "@types/jszip": "3.1.7", "@types/mixpanel-browser": "^2.35.6", "@types/node-fetch": "2.6.11", - "@types/source-map-support": "0.5.10", "@types/styled-components": "^5.1.26", "axios": "^0.21.1", "electron-updater": "6.3.9", diff --git a/app/src/App/index.tsx b/app/src/App/index.tsx index 2e05c91359e..f0ba1de0304 100644 --- a/app/src/App/index.tsx +++ b/app/src/App/index.tsx @@ -1,6 +1,5 @@ import type * as React from 'react' import { useSelector } from 'react-redux' -import 'source-map-support/register' import { Flex, POSITION_FIXED, DIRECTION_ROW } from '@opentrons/components' diff --git a/app/tsconfig.json b/app/tsconfig.json index db9d81301e0..1a24f98b959 100644 --- a/app/tsconfig.json +++ b/app/tsconfig.json @@ -36,7 +36,6 @@ "paths": { "/app/*": ["./src/*"] }, - "sourceMap": true, }, "include": ["typings", "src"], "exclude": ["**/*.stories.tsx"] diff --git a/yarn.lock b/yarn.lock index 98619e9a945..d788db962fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3684,7 +3684,6 @@ rxjs "^6.5.1" semver "5.7.2" simple-keyboard-layouts "3.4.41" - source-map-support "0.5.10" styled-components "5.3.6" typeface-open-sans "0.0.75" uuid "3.2.1" @@ -6123,13 +6122,6 @@ resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.8.tgz#518609aefb797da19bf222feb199e8f653ff7627" integrity sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg== -"@types/source-map-support@0.5.10": - version "0.5.10" - resolved "https://registry.yarnpkg.com/@types/source-map-support/-/source-map-support-0.5.10.tgz#824dcef989496bae98e9d04c8dc1ac1d70e1bd39" - integrity sha512-tgVP2H469x9zq34Z0m/fgPewGhg/MLClalNOiPIzQlXrSS2YrKu/xCdSCKnEDwkFha51VKEKB6A9wW26/ZNwzA== - dependencies: - source-map "^0.6.0" - "@types/styled-components@^5.1.26": version "5.1.34" resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.34.tgz#4107df8ef8a7eaba4fa6b05f78f93fba4daf0300" @@ -20726,14 +20718,6 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@0.5.10: - version "0.5.10" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" - integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" From a7a84df0096a7aefc46d93288690601a57e70e01 Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Fri, 13 Dec 2024 11:26:24 -0500 Subject: [PATCH 05/42] fix(ci): fix failing builds due to oom issues (#17103) The macos build in particular is failing due to the node heap running out of available memory. Upping the memory fixes this. --- app/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Makefile b/app/Makefile index b11fed0b2b3..8f77700e3b7 100644 --- a/app/Makefile +++ b/app/Makefile @@ -47,7 +47,7 @@ clean: dist: export NODE_ENV := production dist: echo "Building app JS bundle (browser layer)" - vite build + NODE_OPTIONS="--max-old-space-size=8192" vite build # development ##################################################################### From 352e4ac80f67674b812bf6c2c176cab7c73b85bc Mon Sep 17 00:00:00 2001 From: Ryan Howard Date: Fri, 13 Dec 2024 11:50:59 -0500 Subject: [PATCH 06/42] fix(api): Speed up LLD by reducing the post-success raise. (#17102) # Overview Right now if we successfully detect liquid we raise (slowly) the entire max pass distance. this takes a while, especially on the 96 channel since it's calculated off the max plunger speed. This reduces the post-success raise to the "safe plunger prep" distance which we know is a safe distance from the liquid to prevent unwanted capillary action or adhesion to the outside of the tip. ## Test Plan and Hands on Testing ## Changelog ## Review requests ## Risk assessment --- api/src/opentrons/hardware_control/backends/flex_protocol.py | 1 + api/src/opentrons/hardware_control/backends/ot3controller.py | 2 ++ api/src/opentrons/hardware_control/backends/ot3simulator.py | 1 + api/src/opentrons/hardware_control/ot3api.py | 3 +++ .../hardware_control/backends/test_ot3_controller.py | 1 + api/tests/opentrons/hardware_control/test_ot3_api.py | 3 +++ hardware/opentrons_hardware/hardware_control/tool_sensors.py | 4 +++- .../opentrons_hardware/hardware_control/test_tool_sensors.py | 1 + 8 files changed, 15 insertions(+), 1 deletion(-) diff --git a/api/src/opentrons/hardware_control/backends/flex_protocol.py b/api/src/opentrons/hardware_control/backends/flex_protocol.py index 64f82a751ef..ef38af631e7 100644 --- a/api/src/opentrons/hardware_control/backends/flex_protocol.py +++ b/api/src/opentrons/hardware_control/backends/flex_protocol.py @@ -165,6 +165,7 @@ async def liquid_probe( threshold_pascals: float, plunger_impulse_time: float, num_baseline_reads: int, + z_offset_for_plunger_prep: float, probe: InstrumentProbeType = InstrumentProbeType.PRIMARY, force_both_sensors: bool = False, response_queue: Optional[PipetteSensorResponseQueue] = None, diff --git a/api/src/opentrons/hardware_control/backends/ot3controller.py b/api/src/opentrons/hardware_control/backends/ot3controller.py index f710eb405ac..cdbd8818111 100644 --- a/api/src/opentrons/hardware_control/backends/ot3controller.py +++ b/api/src/opentrons/hardware_control/backends/ot3controller.py @@ -1493,6 +1493,7 @@ async def liquid_probe( threshold_pascals: float, plunger_impulse_time: float, num_baseline_reads: int, + z_offset_for_plunger_prep: float, probe: InstrumentProbeType = InstrumentProbeType.PRIMARY, force_both_sensors: bool = False, response_queue: Optional[PipetteSensorResponseQueue] = None, @@ -1535,6 +1536,7 @@ def response_capture(data: Dict[SensorId, List[SensorDataType]]) -> None: threshold_pascals=threshold_pascals, plunger_impulse_time=plunger_impulse_time, num_baseline_reads=num_baseline_reads, + z_offset_for_plunger_prep=z_offset_for_plunger_prep, sensor_id=sensor_id_for_instrument(probe), force_both_sensors=force_both_sensors, emplace_data=response_capture, diff --git a/api/src/opentrons/hardware_control/backends/ot3simulator.py b/api/src/opentrons/hardware_control/backends/ot3simulator.py index e85b51ad53f..10f4ebcfe2a 100644 --- a/api/src/opentrons/hardware_control/backends/ot3simulator.py +++ b/api/src/opentrons/hardware_control/backends/ot3simulator.py @@ -353,6 +353,7 @@ async def liquid_probe( threshold_pascals: float, plunger_impulse_time: float, num_baseline_reads: int, + z_offset_for_plunger_prep: float, probe: InstrumentProbeType = InstrumentProbeType.PRIMARY, force_both_sensors: bool = False, response_queue: Optional[PipetteSensorResponseQueue] = None, diff --git a/api/src/opentrons/hardware_control/ot3api.py b/api/src/opentrons/hardware_control/ot3api.py index 7bb5e05f47b..6295757e7ab 100644 --- a/api/src/opentrons/hardware_control/ot3api.py +++ b/api/src/opentrons/hardware_control/ot3api.py @@ -2677,6 +2677,7 @@ async def _liquid_probe_pass( probe_settings: LiquidProbeSettings, probe: InstrumentProbeType, p_travel: float, + z_offset_for_plunger_prep: float, force_both_sensors: bool = False, response_queue: Optional[PipetteSensorResponseQueue] = None, ) -> float: @@ -2689,6 +2690,7 @@ async def _liquid_probe_pass( probe_settings.sensor_threshold_pascals, probe_settings.plunger_impulse_time, probe_settings.samples_for_baselining, + z_offset_for_plunger_prep, probe=probe, force_both_sensors=force_both_sensors, response_queue=response_queue, @@ -2838,6 +2840,7 @@ async def prep_plunger_for_probe_move( probe_settings, checked_probe, plunger_travel_mm + sensor_baseline_plunger_move_mm, + z_offset_for_plunger_prep, force_both_sensors, response_queue, ) diff --git a/api/tests/opentrons/hardware_control/backends/test_ot3_controller.py b/api/tests/opentrons/hardware_control/backends/test_ot3_controller.py index 9c03bed68b2..9bd87fe62ec 100644 --- a/api/tests/opentrons/hardware_control/backends/test_ot3_controller.py +++ b/api/tests/opentrons/hardware_control/backends/test_ot3_controller.py @@ -745,6 +745,7 @@ async def test_liquid_probe( threshold_pascals=fake_liquid_settings.sensor_threshold_pascals, plunger_impulse_time=fake_liquid_settings.plunger_impulse_time, num_baseline_reads=fake_liquid_settings.samples_for_baselining, + z_offset_for_plunger_prep=2.0, ) except PipetteLiquidNotFoundError: # the move raises a liquid not found now since we don't call the move group and it doesn't diff --git a/api/tests/opentrons/hardware_control/test_ot3_api.py b/api/tests/opentrons/hardware_control/test_ot3_api.py index 2fd3fb4377c..a0775d48e19 100644 --- a/api/tests/opentrons/hardware_control/test_ot3_api.py +++ b/api/tests/opentrons/hardware_control/test_ot3_api.py @@ -858,6 +858,7 @@ async def test_liquid_probe( fake_settings_aspirate.sensor_threshold_pascals, fake_settings_aspirate.plunger_impulse_time, fake_settings_aspirate.samples_for_baselining, + probe_safe_reset_mm, probe=InstrumentProbeType.PRIMARY, force_both_sensors=False, response_queue=None, @@ -1114,6 +1115,7 @@ async def test_multi_liquid_probe( fake_settings_aspirate.sensor_threshold_pascals, fake_settings_aspirate.plunger_impulse_time, fake_settings_aspirate.samples_for_baselining, + 2.0, probe=InstrumentProbeType.PRIMARY, force_both_sensors=False, response_queue=None, @@ -1149,6 +1151,7 @@ async def _fake_pos_update_and_raise( threshold_pascals: float, plunger_impulse_time: float, num_baseline_reads: int, + z_offset_for_plunger_prep: float, probe: InstrumentProbeType = InstrumentProbeType.PRIMARY, force_both_sensors: bool = False, response_queue: Optional[ diff --git a/hardware/opentrons_hardware/hardware_control/tool_sensors.py b/hardware/opentrons_hardware/hardware_control/tool_sensors.py index e9475de8b95..9df634f11b1 100644 --- a/hardware/opentrons_hardware/hardware_control/tool_sensors.py +++ b/hardware/opentrons_hardware/hardware_control/tool_sensors.py @@ -269,6 +269,7 @@ async def liquid_probe( threshold_pascals: float, plunger_impulse_time: float, num_baseline_reads: int, + z_offset_for_plunger_prep: float, sensor_id: SensorId = SensorId.S0, force_both_sensors: bool = False, emplace_data: Optional[ @@ -331,8 +332,9 @@ async def liquid_probe( ) sensor_runner = MoveGroupRunner(move_groups=[[lower_plunger], [sensor_group]]) + # Only raise the z a little so we don't do a huge slow travel raise_z = create_step( - distance={head_node: float64(max_z_distance)}, + distance={head_node: float64(z_offset_for_plunger_prep)}, velocity={head_node: float64(-1 * mount_speed)}, acceleration={}, duration=float64(max_z_distance / mount_speed), diff --git a/hardware/tests/opentrons_hardware/hardware_control/test_tool_sensors.py b/hardware/tests/opentrons_hardware/hardware_control/test_tool_sensors.py index 0c53b81057a..ebcfcc5f05a 100644 --- a/hardware/tests/opentrons_hardware/hardware_control/test_tool_sensors.py +++ b/hardware/tests/opentrons_hardware/hardware_control/test_tool_sensors.py @@ -237,6 +237,7 @@ def move_responder( threshold_pascals=threshold_pascals, plunger_impulse_time=0.2, num_baseline_reads=20, + z_offset_for_plunger_prep=2.0, sensor_id=SensorId.S0, ) assert position[motor_node].positions_only()[0] == 14 From 8c43dcc9b32a7ff5bb62af3105438b9ad38c5817 Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Fri, 13 Dec 2024 14:57:47 -0500 Subject: [PATCH 07/42] fix(app): fix dev ODD system image build causing infinite spinner (#17104) Dev ODD system image builds have been failing. When digging into the Electron renderer process logs, this appears to be because of the way we inject the mixpanel config in our dev builds: it's not what mixpanel expects. During mixpanel initialization, if an unexpected configuration/id is supplied, certain methods on mixpanel are undefined. We've had similar issues like this in the past, and a more general-case solution to all of these issues is just to wrap the whole mixpanel initialization process in a try-catch block. --- app/src/redux/analytics/mixpanel.ts | 70 ++++++++++++++++++----------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/app/src/redux/analytics/mixpanel.ts b/app/src/redux/analytics/mixpanel.ts index aa5ad5a7893..5304bbbe563 100644 --- a/app/src/redux/analytics/mixpanel.ts +++ b/app/src/redux/analytics/mixpanel.ts @@ -1,9 +1,9 @@ -// mixpanel actions import mixpanel from 'mixpanel-browser' -import { createLogger } from '../../logger' +import { createLogger } from '/app/logger' import { CURRENT_VERSION } from '../shell' +import type { Config as MixpanelConfig } from 'mixpanel-browser' import type { AnalyticsEvent, AnalyticsConfig } from './types' const log = createLogger(new URL('', import.meta.url).pathname) @@ -11,7 +11,7 @@ const log = createLogger(new URL('', import.meta.url).pathname) // pulled in from environment at build time const MIXPANEL_ID = process.env.OT_APP_MIXPANEL_ID -const MIXPANEL_OPTS = { +const MIXPANEL_OPTS: Partial = { // opt out by default opt_out_tracking_by_default: true, // user details are persisted in our own config store @@ -27,9 +27,13 @@ export function initializeMixpanel( isOnDevice: boolean | null ): void { if (MIXPANEL_ID != null) { - initMixpanelInstanceOnce(config) - setMixpanelTracking(config, isOnDevice) - trackEvent({ name: 'appOpen', properties: {} }, config) + try { + initMixpanelInstanceOnce(config) + setMixpanelTracking(config, isOnDevice) + trackEvent({ name: 'appOpen', properties: {} }, config) + } catch (error) { + console.error('Failed to initialize Mixpanel:', error) + } } else { log.warn('MIXPANEL_ID not found; this is a bug if build is production') } @@ -43,11 +47,15 @@ export function trackEvent( log.debug('Trackable event', { event, optedIn }) if (MIXPANEL_ID != null && optedIn) { - if (event.superProperties != null) { - mixpanel.register(event.superProperties) - } - if ('name' in event && event.name != null) { - mixpanel.track(event.name, event.properties) + try { + if (event.superProperties != null) { + mixpanel.register(event.superProperties) + } + if ('name' in event && event.name != null) { + mixpanel.track(event.name, event.properties) + } + } catch (error) { + console.error('Failed to track event:', error) } } } @@ -58,19 +66,23 @@ export function setMixpanelTracking( ): void { if (MIXPANEL_ID != null) { initMixpanelInstanceOnce(config) - if (config.optedIn) { - log.debug('User has opted into analytics; tracking with Mixpanel') - mixpanel.identify(config.appId) - mixpanel.opt_in_tracking() - mixpanel.register({ - appVersion: CURRENT_VERSION, - appId: config.appId, - appMode: Boolean(isOnDevice) ? 'ODD' : 'Desktop', - }) - } else { - log.debug('User has opted out of analytics; stopping tracking') - mixpanel.opt_out_tracking?.() - mixpanel.reset?.() + try { + if (config.optedIn) { + log.debug('User has opted into analytics; tracking with Mixpanel') + mixpanel.identify(config.appId) + mixpanel.opt_in_tracking() + mixpanel.register({ + appVersion: CURRENT_VERSION, + appId: config.appId, + appMode: Boolean(isOnDevice) ? 'ODD' : 'Desktop', + }) + } else { + log.debug('User has opted out of analytics; stopping tracking') + mixpanel.opt_out_tracking() + mixpanel.reset() + } + } catch (error) { + console.error('Failed to set Mixpanel tracking:', error) } } } @@ -82,9 +94,13 @@ function initializeMixpanelInstanceOnce( return function (config: AnalyticsConfig): undefined { if (!hasBeenInitialized && MIXPANEL_ID != null) { - hasBeenInitialized = true - log.debug('Initializing Mixpanel', { config }) - mixpanel.init(MIXPANEL_ID, MIXPANEL_OPTS) + try { + hasBeenInitialized = true + log.debug('Initializing Mixpanel', { config }) + mixpanel.init(MIXPANEL_ID, MIXPANEL_OPTS) + } catch (error) { + console.error('Failed to initialize Mixpanel instance:', error) + } } } } From d6e5a5ee3ea6fa33a9f7e5069029466acb604299 Mon Sep 17 00:00:00 2001 From: koji Date: Fri, 13 Dec 2024 15:10:53 -0500 Subject: [PATCH 08/42] chore(protocol-designer): remove unused vite from package.json (#17108) * chore(protocol-designer): remove unused vite from package.json --- protocol-designer/package.json | 2 - yarn.lock | 174 +-------------------------------- 2 files changed, 4 insertions(+), 172 deletions(-) diff --git a/protocol-designer/package.json b/protocol-designer/package.json index 547b15de023..95f5acf4813 100755 --- a/protocol-designer/package.json +++ b/protocol-designer/package.json @@ -21,7 +21,6 @@ "dependencies": { "@fontsource/public-sans": "5.0.3", "@hot-loader/react-dom": "17.0.1", - "@vitejs/plugin-react": "^4.2.1", "@vituum/vite-plugin-postcss": "1.1.0", "@hookform/resolvers": "3.1.1", "@opentrons/components": "link:../components", @@ -62,7 +61,6 @@ "styled-components": "5.3.6", "ua-parser-js": "^0.7.23", "uuid": "3.3.2", - "vite": "5.0.5", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", "postcss-apply": "0.12.0", diff --git a/yarn.lock b/yarn.lock index d788db962fd..ee61c887c8e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -804,7 +804,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02" integrity sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g== -"@babel/core@>=7.2.2", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.18.9", "@babel/core@^7.20.12", "@babel/core@^7.23.0", "@babel/core@^7.23.2", "@babel/core@^7.23.3", "@babel/core@^7.23.5": +"@babel/core@>=7.2.2", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.18.9", "@babel/core@^7.20.12", "@babel/core@^7.23.0", "@babel/core@^7.23.2", "@babel/core@^7.23.3": version "7.24.4" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.4.tgz#1f758428e88e0d8c563874741bc4ffc4f71a4717" integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== @@ -2556,11 +2556,6 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== -"@esbuild/aix-ppc64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" - integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== - "@esbuild/aix-ppc64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537" @@ -2581,11 +2576,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== -"@esbuild/android-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" - integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== - "@esbuild/android-arm64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9" @@ -2606,11 +2596,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== -"@esbuild/android-arm@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" - integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== - "@esbuild/android-arm@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995" @@ -2631,11 +2616,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== -"@esbuild/android-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" - integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== - "@esbuild/android-x64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98" @@ -2656,11 +2636,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== -"@esbuild/darwin-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" - integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== - "@esbuild/darwin-arm64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb" @@ -2681,11 +2656,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== -"@esbuild/darwin-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" - integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== - "@esbuild/darwin-x64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0" @@ -2706,11 +2676,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== -"@esbuild/freebsd-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" - integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== - "@esbuild/freebsd-arm64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911" @@ -2731,11 +2696,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== -"@esbuild/freebsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" - integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== - "@esbuild/freebsd-x64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c" @@ -2756,11 +2716,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== -"@esbuild/linux-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" - integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== - "@esbuild/linux-arm64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5" @@ -2781,11 +2736,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== -"@esbuild/linux-arm@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" - integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== - "@esbuild/linux-arm@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c" @@ -2806,11 +2756,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== -"@esbuild/linux-ia32@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" - integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== - "@esbuild/linux-ia32@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa" @@ -2831,11 +2776,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== -"@esbuild/linux-loong64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" - integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== - "@esbuild/linux-loong64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5" @@ -2856,11 +2796,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== -"@esbuild/linux-mips64el@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" - integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== - "@esbuild/linux-mips64el@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa" @@ -2881,11 +2816,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== -"@esbuild/linux-ppc64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" - integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== - "@esbuild/linux-ppc64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20" @@ -2906,11 +2836,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== -"@esbuild/linux-riscv64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" - integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== - "@esbuild/linux-riscv64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300" @@ -2931,11 +2856,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== -"@esbuild/linux-s390x@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" - integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== - "@esbuild/linux-s390x@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685" @@ -2956,11 +2876,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== -"@esbuild/linux-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" - integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== - "@esbuild/linux-x64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff" @@ -2981,11 +2896,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== -"@esbuild/netbsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" - integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== - "@esbuild/netbsd-x64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6" @@ -3011,11 +2921,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== -"@esbuild/openbsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" - integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== - "@esbuild/openbsd-x64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf" @@ -3036,11 +2941,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== -"@esbuild/sunos-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" - integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== - "@esbuild/sunos-x64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f" @@ -3061,11 +2961,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== -"@esbuild/win32-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" - integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== - "@esbuild/win32-arm64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90" @@ -3086,11 +2981,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== -"@esbuild/win32-ia32@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" - integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== - "@esbuild/win32-ia32@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23" @@ -3111,11 +3001,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== -"@esbuild/win32-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" - integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== - "@esbuild/win32-x64@0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc" @@ -5581,7 +5466,7 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw== -"@types/babel__core@^7.0.0", "@types/babel__core@^7.18.0", "@types/babel__core@^7.20.4", "@types/babel__core@^7.20.5": +"@types/babel__core@^7.0.0", "@types/babel__core@^7.18.0", "@types/babel__core@^7.20.4": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== @@ -6400,17 +6285,6 @@ magic-string "^0.27.0" react-refresh "^0.14.0" -"@vitejs/plugin-react@^4.2.1": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz#744d8e4fcb120fc3dbaa471dadd3483f5a304bb9" - integrity sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ== - dependencies: - "@babel/core" "^7.23.5" - "@babel/plugin-transform-react-jsx-self" "^7.23.3" - "@babel/plugin-transform-react-jsx-source" "^7.23.3" - "@types/babel__core" "^7.20.5" - react-refresh "^0.14.0" - "@vitest/coverage-v8@1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-1.3.0.tgz#31f98b1bad1d5e9db733a4c1ae8d46dec549cd3c" @@ -11041,35 +10915,6 @@ esbuild@^0.18.0: "@esbuild/win32-ia32" "0.18.20" "@esbuild/win32-x64" "0.18.20" -esbuild@^0.19.3: - version "0.19.12" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" - integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== - optionalDependencies: - "@esbuild/aix-ppc64" "0.19.12" - "@esbuild/android-arm" "0.19.12" - "@esbuild/android-arm64" "0.19.12" - "@esbuild/android-x64" "0.19.12" - "@esbuild/darwin-arm64" "0.19.12" - "@esbuild/darwin-x64" "0.19.12" - "@esbuild/freebsd-arm64" "0.19.12" - "@esbuild/freebsd-x64" "0.19.12" - "@esbuild/linux-arm" "0.19.12" - "@esbuild/linux-arm64" "0.19.12" - "@esbuild/linux-ia32" "0.19.12" - "@esbuild/linux-loong64" "0.19.12" - "@esbuild/linux-mips64el" "0.19.12" - "@esbuild/linux-ppc64" "0.19.12" - "@esbuild/linux-riscv64" "0.19.12" - "@esbuild/linux-s390x" "0.19.12" - "@esbuild/linux-x64" "0.19.12" - "@esbuild/netbsd-x64" "0.19.12" - "@esbuild/openbsd-x64" "0.19.12" - "@esbuild/sunos-x64" "0.19.12" - "@esbuild/win32-arm64" "0.19.12" - "@esbuild/win32-ia32" "0.19.12" - "@esbuild/win32-x64" "0.19.12" - esbuild@^0.20.1: version "0.20.2" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.20.2.tgz#9d6b2386561766ee6b5a55196c6d766d28c87ea1" @@ -18490,7 +18335,7 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.2, postcss@^7.0.21 picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.1.7, postcss@^8.4, postcss@^8.4.32, postcss@^8.4.38: +postcss@^8.1.7, postcss@^8.4, postcss@^8.4.38: version "8.4.38" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== @@ -20038,7 +19883,7 @@ rollup@^2.44.0: optionalDependencies: fsevents "~2.3.2" -rollup@^4.13.0, rollup@^4.2.0: +rollup@^4.13.0: version "4.16.2" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.16.2.tgz#43bcbd225d0a6bc68df97a6e41c45003188a3845" integrity sha512-sxDP0+pya/Yi5ZtptF4p3avI+uWCIf/OdrfdH2Gbv1kWddLKk0U7WE3PmQokhi5JrektxsK3sK8s4hzAmjqahw== @@ -22886,17 +22731,6 @@ vite-node@1.2.2: picocolors "^1.0.0" vite "^5.0.0" -vite@5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.5.tgz#3eebe3698e3b32cea36350f58879258fec858a3c" - integrity sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg== - dependencies: - esbuild "^0.19.3" - postcss "^8.4.32" - rollup "^4.2.0" - optionalDependencies: - fsevents "~2.3.3" - vite@5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.2.tgz#2f0a8531c71060467ed3e0a205a203f269b6d9c8" From a4f233853db66a0ac6763113748bc07474946d67 Mon Sep 17 00:00:00 2001 From: Andy Sigler Date: Mon, 16 Dec 2024 09:55:05 -0500 Subject: [PATCH 09/42] chore(shared-data): adds liquid-class Ethanol-80 and Glycerol-50 (#17068) --- .../definitions/1/ethanol_80.json | 2602 +++++++++++++++++ .../definitions/1/glycerol_50.json | 2462 ++++++++++++++++ 2 files changed, 5064 insertions(+) create mode 100644 shared-data/liquid-class/definitions/1/ethanol_80.json create mode 100644 shared-data/liquid-class/definitions/1/glycerol_50.json diff --git a/shared-data/liquid-class/definitions/1/ethanol_80.json b/shared-data/liquid-class/definitions/1/ethanol_80.json new file mode 100644 index 00000000000..392d1454f8f --- /dev/null +++ b/shared-data/liquid-class/definitions/1/ethanol_80.json @@ -0,0 +1,2602 @@ +{ + "liquidClassName": "ethanol_80", + "displayName": "Ethanol-80", + "schemaVersion": 1, + "namespace": "opentrons", + "byPipette": [ + { + "pipetteModel": "flex_1channel_50", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": true, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 30.0] + ], + "correctionByVolume": [ + [1.0, -1.6], + [10.0, -1.1], + [50.0, -3.0] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 30.0]], + "correctionByVolume": [ + [1.0, -1.6], + [10.0, -1.1], + [50.0, -3.0] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [[0.0, 1.0]], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 30.0]], + "correctionByVolume": [ + [1.0, -1.6], + [10.0, -1.1], + [50.0, -3.0] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + } + ] + }, + { + "pipetteModel": "flex_8channel_50", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": true, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 30.0] + ], + "correctionByVolume": [ + [1.0, -1.6], + [10.0, -1.1], + [50.0, -3.0] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 30.0]], + "correctionByVolume": [ + [1.0, -1.6], + [10.0, -1.1], + [50.0, -3.0] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [[0.0, 1.0]], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 30.0]], + "correctionByVolume": [ + [1.0, -1.6], + [10.0, -1.1], + [50.0, -3.0] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + } + ] + }, + { + "pipetteModel": "flex_1channel_1000", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": true, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 30.0] + ], + "correctionByVolume": [ + [5.0, -2.1], + [10.0, -1.7], + [50.0, -3.3] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -2.1], + [10.0, -1.7], + [50.0, -3.3] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [5.0, 10.0], + [10.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -2.1], + [10.0, -1.7], + [50.0, -3.3] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_200ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": true, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 10.0], + [190.0, 10.0], + [200.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [5.0, 7.0], + [50.0, 50.0], + [200.0, 200.0] + ], + "correctionByVolume": [ + [5.0, -1.5], + [50.0, -2.2], + [200.0, -7.4] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 10.0], + [190.0, 10.0], + [200.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -1.5], + [50.0, -2.2], + [200.0, -7.4] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [5.0, 8.0], + [50.0, 4.0], + [200.0, 4.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 10.0], + [190.0, 10.0], + [200.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -1.5], + [50.0, -2.2], + [200.0, -7.4] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_1000ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 12.0], + [188.0, 12.0], + [1000.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [10.0, 10.0], + [100.0, 100.0], + [200.0, 200.0] + ], + "correctionByVolume": [ + [10.0, -1.9], + [100.0, -3.6], + [1000.0, -32.2] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 12.0], + [188.0, 12.0], + [1000.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 250.0]], + "correctionByVolume": [ + [10.0, -1.9], + [100.0, -3.6], + [1000.0, -32.2] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [10.0, 6.0], + [100.0, 3.0], + [1000.0, 3.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 12.0], + [188.0, 12.0], + [1000.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 250.0]], + "correctionByVolume": [ + [10.0, -1.9], + [100.0, -3.6], + [1000.0, -32.2] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + } + ] + }, + { + "pipetteModel": "flex_8channel_1000", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": true, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 30.0] + ], + "correctionByVolume": [ + [5.0, -2.1], + [10.0, -1.7], + [50.0, -3.3] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -2.1], + [10.0, -1.7], + [50.0, -3.3] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [5.0, 10.0], + [10.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -2.1], + [10.0, -1.7], + [50.0, -3.3] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_200ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": true, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 10.0], + [190.0, 10.0], + [200.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [5.0, 7.0], + [50.0, 50.0], + [200.0, 200.0] + ], + "correctionByVolume": [ + [5.0, -1.5], + [50.0, -2.2], + [200.0, -7.4] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 10.0], + [190.0, 10.0], + [200.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -1.5], + [50.0, -2.2], + [200.0, -7.4] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [5.0, 8.0], + [50.0, 4.0], + [200.0, 4.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 10.0], + [190.0, 10.0], + [200.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -1.5], + [50.0, -2.2], + [200.0, -7.4] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_1000ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 12.0], + [188.0, 12.0], + [1000.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [10.0, 10.0], + [100.0, 100.0], + [200.0, 200.0] + ], + "correctionByVolume": [ + [10.0, -1.9], + [100.0, -3.6], + [1000.0, -32.2] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 12.0], + [188.0, 12.0], + [1000.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 250.0]], + "correctionByVolume": [ + [10.0, -1.9], + [100.0, -3.6], + [1000.0, -32.2] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [10.0, 6.0], + [100.0, 3.0], + [1000.0, 3.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 100, + "airGapByVolume": [ + [5.0, 12.0], + [188.0, 12.0], + [1000.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 250.0]], + "correctionByVolume": [ + [10.0, -1.9], + [100.0, -3.6], + [1000.0, -32.2] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + } + ] + }, + { + "pipetteModel": "flex_96channel_1000", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "delay": { + "enable": true, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 30.0] + ], + "correctionByVolume": [ + [5.0, -2.1], + [10.0, -1.7], + [50.0, -3.3] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -2.1], + [10.0, -1.7], + [50.0, -3.3] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [5.0, 10.0], + [10.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "airGapByVolume": [ + [1.0, 5.0], + [45.0, 5.0], + [50.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -2.1], + [10.0, -1.7], + [50.0, -3.3] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_200ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "delay": { + "enable": true, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "airGapByVolume": [ + [5.0, 10.0], + [190.0, 10.0], + [200.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [5.0, 7.0], + [50.0, 50.0], + [200.0, 200.0] + ], + "correctionByVolume": [ + [5.0, -1.5], + [50.0, -2.2], + [200.0, -7.4] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "airGapByVolume": [ + [5.0, 10.0], + [190.0, 10.0], + [200.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -1.5], + [50.0, -2.2], + [200.0, -7.4] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [5.0, 8.0], + [50.0, 4.0], + [200.0, 4.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "airGapByVolume": [ + [5.0, 10.0], + [190.0, 10.0], + [200.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 125.0]], + "correctionByVolume": [ + [5.0, -1.5], + [50.0, -2.2], + [200.0, -7.4] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_1000ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "airGapByVolume": [ + [5.0, 12.0], + [188.0, 12.0], + [1000.0, 0.0] + ], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [10.0, 10.0], + [100.0, 100.0], + [200.0, 200.0] + ], + "correctionByVolume": [ + [10.0, -1.9], + [100.0, -3.6], + [1000.0, -32.2] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "airGapByVolume": [ + [5.0, 12.0], + [188.0, 12.0], + [1000.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 200.0]], + "correctionByVolume": [ + [10.0, -1.9], + [100.0, -3.6], + [1000.0, -32.2] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [10.0, 6.0], + [100.0, 3.0], + [1000.0, 3.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 35, + "airGapByVolume": [ + [5.0, 12.0], + [188.0, 12.0], + [1000.0, 0.0] + ], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 200.0]], + "correctionByVolume": [ + [10.0, -1.9], + [100.0, -3.6], + [1000.0, -32.2] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.2 + } + } + } + } + ] + } + ] +} diff --git a/shared-data/liquid-class/definitions/1/glycerol_50.json b/shared-data/liquid-class/definitions/1/glycerol_50.json new file mode 100644 index 00000000000..0cb8dad21b8 --- /dev/null +++ b/shared-data/liquid-class/definitions/1/glycerol_50.json @@ -0,0 +1,2462 @@ +{ + "liquidClassName": "glycerol_50", + "displayName": "Glycerol-50", + "schemaVersion": 1, + "namespace": "opentrons", + "byPipette": [ + { + "pipetteModel": "flex_1channel_50", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 50.0] + ], + "correctionByVolume": [ + [1.0, -0.5], + [10.0, -0.2], + [50.0, -0.2] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 25.0]], + "correctionByVolume": [ + [1.0, -0.5], + [10.0, -0.2], + [50.0, -0.2] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [1.0, 11.7], + [4.999, 11.7], + [5.0, 3.9], + [50.0, 3.9] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 25.0]], + "correctionByVolume": [ + [1.0, -0.5], + [10.0, -0.2], + [50.0, -0.2] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + } + } + ] + }, + { + "pipetteModel": "flex_8channel_50", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 50.0] + ], + "correctionByVolume": [ + [1.0, -0.5], + [10.0, -0.2], + [50.0, -0.2] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 25.0]], + "correctionByVolume": [ + [1.0, -0.5], + [10.0, -0.2], + [50.0, -0.2] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [1.0, 11.7], + [4.999, 11.7], + [5.0, 3.9], + [50.0, 3.9] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 25.0]], + "correctionByVolume": [ + [1.0, -0.5], + [10.0, -0.2], + [50.0, -0.2] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + } + } + ] + }, + { + "pipetteModel": "flex_1channel_1000", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 40.0] + ], + "correctionByVolume": [ + [5.0, -0.3], + [10.0, -0.2], + [50.0, 0.0] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 2.0 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [10.0, -0.2], + [50.0, 0.0] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [5.0, 30.0], + [10.0, 20.0], + [50.0, 20.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [10.0, -0.2], + [50.0, 0.0] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_200ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [5.0, 10.0], + [50.0, 50.0], + [200.0, 200.0] + ], + "correctionByVolume": [ + [5.0, -0.3], + [50.0, -0.3], + [200.0, -0.8] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [50.0, -0.3], + [200.0, -0.8] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [[0.0, 20.0]], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [50.0, -0.3], + [200.0, -0.8] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_1000ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [10.0, 10.0], + [100.0, 100.0], + [1000.0, 800.0] + ], + "correctionByVolume": [ + [10.0, -0.2], + [100.0, -0.1], + [1000.0, -2.5] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.7 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 250.0]], + "correctionByVolume": [ + [10.0, -0.2], + [100.0, -0.1], + [1000.0, -2.5] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [[0.0, 35.0]], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 250.0]], + "correctionByVolume": [ + [10.0, -0.2], + [100.0, -0.1], + [1000.0, -2.5] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + } + } + ] + }, + { + "pipetteModel": "flex_8channel_1000", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 40.0] + ], + "correctionByVolume": [ + [5.0, -0.3], + [10.0, -0.2], + [50.0, 0.0] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 2.0 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [10.0, -0.2], + [50.0, 0.0] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [5.0, 30.0], + [10.0, 20.0], + [50.0, 20.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [10.0, -0.2], + [50.0, 0.0] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_200ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [5.0, 10.0], + [50.0, 50.0], + [200.0, 200.0] + ], + "correctionByVolume": [ + [5.0, -0.3], + [50.0, -0.3], + [200.0, -0.8] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [50.0, -0.3], + [200.0, -0.8] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [[0.0, 20.0]], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [50.0, -0.3], + [200.0, -0.8] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_1000ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [10.0, 10.0], + [100.0, 100.0], + [1000.0, 800.0] + ], + "correctionByVolume": [ + [10.0, -0.2], + [100.0, -0.1], + [1000.0, -2.5] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.7 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 250.0]], + "correctionByVolume": [ + [10.0, -0.2], + [100.0, -0.1], + [1000.0, -2.5] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [[0.0, 35.0]], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 250.0]], + "correctionByVolume": [ + [10.0, -0.2], + [100.0, -0.1], + [1000.0, -2.5] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + } + } + ] + }, + { + "pipetteModel": "flex_96channel_1000", + "byTipType": [ + { + "tiprack": "opentrons_flex_96_tiprack_50ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 40.0] + ], + "correctionByVolume": [ + [5.0, -0.3], + [10.0, -0.2], + [50.0, 0.0] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 2.0 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 40.0] + ], + "correctionByVolume": [ + [5.0, -0.3], + [10.0, -0.2], + [50.0, 0.0] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [ + [5.0, 30.0], + [10.0, 20.0], + [50.0, 20.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [1.0, 7.0], + [10.0, 10.0], + [50.0, 40.0] + ], + "correctionByVolume": [ + [5.0, -0.3], + [10.0, -0.2], + [50.0, 0.0] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [40.0, 5.0], + [45.0, 0.0], + [50.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_200ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [5.0, 10.0], + [50.0, 50.0], + [200.0, 200.0] + ], + "correctionByVolume": [ + [5.0, -0.3], + [50.0, -0.3], + [200.0, -0.8] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 1.0 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [50.0, -0.3], + [200.0, -0.8] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [[0.0, 20.0]], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 50.0]], + "correctionByVolume": [ + [5.0, -0.3], + [50.0, -0.3], + [200.0, -0.8] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [190.0, 5.0], + [195.0, 0.0], + [200.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + } + }, + { + "tiprack": "opentrons_flex_96_tiprack_1000ul", + "aspirate": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-bottom", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [ + [10.0, 10.0], + [100.0, 100.0], + [200.0, 200.0], + [1000.0, 200.0] + ], + "correctionByVolume": [ + [10.0, -0.2], + [100.0, -0.1], + [1000.0, -2.5] + ], + "preWet": false, + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "delay": { + "enable": true, + "params": { + "duration": 0.7 + } + } + }, + "singleDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 250.0]], + "correctionByVolume": [ + [10.0, -0.2], + [100.0, -0.1], + [1000.0, -2.5] + ], + "mix": { + "enable": false, + "params": { + "repetitions": 1, + "volume": 50 + } + }, + "pushOutByVolume": [[0.0, 35.0]], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + }, + "multiDispense": { + "submerge": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "delay": { + "enable": false, + "params": { + "duration": 0.0 + } + } + }, + "retract": { + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "speed": 4, + "airGapByVolume": [[0.0, 0.0]], + "blowout": { + "enable": false + }, + "touchTip": { + "enable": false, + "params": { + "zOffset": -1, + "mmToEdge": 0.5, + "speed": 30 + } + }, + "delay": { + "enable": false, + "params": { + "duration": 0 + } + } + }, + "positionReference": "well-top", + "offset": { + "x": 0, + "y": 0, + "z": 2 + }, + "flowRateByVolume": [[0.0, 200.0]], + "correctionByVolume": [ + [10.0, -0.2], + [100.0, -0.1], + [1000.0, -2.5] + ], + "conditioningByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "disposalByVolume": [ + [1.0, 5.0], + [990.0, 5.0], + [995.0, 0.0], + [1000.0, 0.0] + ], + "delay": { + "enable": true, + "params": { + "duration": 0.5 + } + } + } + } + ] + } + ] +} From d37b151f743c4608a2bc9f866c3cfebfaff612f5 Mon Sep 17 00:00:00 2001 From: koji Date: Mon, 16 Dec 2024 10:21:05 -0500 Subject: [PATCH 10/42] fix(app): remove marginLeft from ExternalLink component (#17112) * fix(app): remove marginLeft from ExternalLink component --- app/src/atoms/Link/ExternalLink.tsx | 21 ++++++++++++++----- .../Link/__tests__/ExternalLink.test.tsx | 1 - 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/src/atoms/Link/ExternalLink.tsx b/app/src/atoms/Link/ExternalLink.tsx index 5d24a06fdb4..2490266927e 100644 --- a/app/src/atoms/Link/ExternalLink.tsx +++ b/app/src/atoms/Link/ExternalLink.tsx @@ -1,22 +1,33 @@ -import type * as React from 'react' +import { css } from 'styled-components' +import { + DISPLAY_INLINE_BLOCK, + Icon, + Link, + SPACING, + TYPOGRAPHY, +} from '@opentrons/components' -import { Link, Icon, TYPOGRAPHY, SPACING } from '@opentrons/components' +import type { ReactNode } from 'react' import type { LinkProps } from '@opentrons/components' - export interface ExternalLinkProps extends LinkProps { href: string id?: string - children: React.ReactNode + children: ReactNode } export const ExternalLink = (props: ExternalLinkProps): JSX.Element => ( {props.children} + ) + +const SPAN_STYLE = css` + display: ${DISPLAY_INLINE_BLOCK}; + width: 0.4375rem; +` diff --git a/app/src/atoms/Link/__tests__/ExternalLink.test.tsx b/app/src/atoms/Link/__tests__/ExternalLink.test.tsx index e245541c514..f58ad595169 100644 --- a/app/src/atoms/Link/__tests__/ExternalLink.test.tsx +++ b/app/src/atoms/Link/__tests__/ExternalLink.test.tsx @@ -38,6 +38,5 @@ describe('ExternalLink', () => { const icon = screen.getByLabelText('open_in_new_icon') expect(icon).toBeInTheDocument() expect(icon).toHaveStyle('width: 0.5rem; height: 0.5rem') - expect(icon).toHaveStyle('margin-left: 0.4375rem') }) }) From c2d4908a93501172ea5e5d903733caa34a1b9a0b Mon Sep 17 00:00:00 2001 From: Josh McVey Date: Mon, 16 Dec 2024 13:12:08 -0500 Subject: [PATCH 11/42] chore(release): internal release notes ot3@2.3.0-alpha.2 (#17114) --- api/release-notes-internal.md | 4 ++++ app-shell/build/release-notes-internal.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/api/release-notes-internal.md b/api/release-notes-internal.md index ac762aebec4..bc5398781e4 100644 --- a/api/release-notes-internal.md +++ b/api/release-notes-internal.md @@ -2,6 +2,10 @@ For more details about this release, please see the full [technical change log][ [technical change log]: https://github.com/Opentrons/opentrons/releases +## Internal Release 2.3.0-alpha.2 + +This internal release, pulled from the `edge` branch, contains features being developed for 8.3.0. It's for internal testing only. + ## Internal Release 2.3.0-alpha.1 This internal release, pulled from the `edge` branch, contains features being developed for 8.3.0. It's for internal testing only. diff --git a/app-shell/build/release-notes-internal.md b/app-shell/build/release-notes-internal.md index 5459cc2593e..565c5e1aa9b 100644 --- a/app-shell/build/release-notes-internal.md +++ b/app-shell/build/release-notes-internal.md @@ -1,6 +1,10 @@ For more details about this release, please see the full [technical changelog][]. [technical change log]: https://github.com/Opentrons/opentrons/releases +## Internal Release 2.3.0-alpha.2 + +This internal release, pulled from the `edge` branch, contains features being developed for 8.3.0. It's for internal testing only. + ## Internal Release 2.3.0-alpha.1 This internal release, pulled from the `edge` branch, contains features being developed for 8.3.0. It's for internal testing only. From 0540c01f9f877453b9551018bf89a55d9f56fc0d Mon Sep 17 00:00:00 2001 From: Josh McVey Date: Mon, 16 Dec 2024 13:39:50 -0500 Subject: [PATCH 12/42] test(api): install opentrons and simulate (#17048) --- .github/workflows/api-test-lint-deploy.yaml | 56 ++++++- .gitignore | 2 + package-testing/Makefile | 43 ++++++ package-testing/README.md | 34 +++++ package-testing/help.ps1 | 69 +++++++++ package-testing/help.sh | 48 ++++++ package-testing/run_tests.py | 154 ++++++++++++++++++++ package-testing/setup.ps1 | 42 ++++++ package-testing/setup.sh | 35 +++++ package-testing/simulate.ps1 | 45 ++++++ package-testing/simulate.sh | 48 ++++++ 11 files changed, 574 insertions(+), 2 deletions(-) create mode 100644 package-testing/Makefile create mode 100644 package-testing/README.md create mode 100644 package-testing/help.ps1 create mode 100755 package-testing/help.sh create mode 100644 package-testing/run_tests.py create mode 100644 package-testing/setup.ps1 create mode 100755 package-testing/setup.sh create mode 100644 package-testing/simulate.ps1 create mode 100755 package-testing/simulate.sh diff --git a/.github/workflows/api-test-lint-deploy.yaml b/.github/workflows/api-test-lint-deploy.yaml index 6297cb7c747..e1790f28f20 100644 --- a/.github/workflows/api-test-lint-deploy.yaml +++ b/.github/workflows/api-test-lint-deploy.yaml @@ -73,8 +73,6 @@ jobs: strategy: matrix: os: ['windows-2022', 'ubuntu-22.04', 'macos-latest'] - # TODO(mc, 2022-02-24): expand this matrix to 3.8 and 3.9, - # preferably in a nightly cronjob on edge or something python: ['3.10'] with-ot-hardware: ['true', 'false'] exclude: @@ -128,6 +126,60 @@ jobs: files: ./api/coverage.xml flags: api + test-package: + name: 'installed package tests on ${{ matrix.os }}' + timeout-minutes: 5 + strategy: + matrix: + os: ['ubuntu-22.04', 'macos-latest', 'windows-2022'] + runs-on: '${{ matrix.os }}' + steps: + - uses: 'actions/checkout@v4' + - name: 'Fix actions/checkout odd handling of tags' + if: startsWith(github.ref, 'refs/tags') + run: | + git fetch -f origin ${{ github.ref }}:${{ github.ref }} + git checkout ${{ github.ref }} + - uses: 'actions/setup-python@v4' + with: + python-version: '3.10' + - name: Set up package-testing + id: setup + if: ${{ matrix.os != 'windows-2022' }} + working-directory: package-testing + shell: bash + run: make setup + - name: Set up package-testing (Windows) + id: setup-windows + if: ${{ matrix.os == 'windows-2022' }} + working-directory: package-testing + shell: pwsh + run: make setup-windows + - name: Run the tests + if: ${{ matrix.os != 'windows-2022' }} + shell: bash + id: test + working-directory: package-testing + run: make test + - name: Run the tests (Windows) + shell: pwsh + id: test-windows + working-directory: package-testing + run: make test-windows + - name: Save the test results + if: ${{ always() && steps.setup.outcome == 'success' || steps.setup-windows.outcome == 'success' }} + id: results + uses: actions/upload-artifact@v4 + with: + name: package-test-results-${{ matrix.os }} + path: package-testing/results + - name: Set job summary + if: ${{ always() }} + run: | + echo "## Opentrons Package Test Results ${{matrix.os}}" >> $GITHUB_STEP_SUMMARY + echo "### Test Outcome: Unixy ${{ steps.test.outcome }} Windows: ${{ steps.test-windows.outcome }}" >> $GITHUB_STEP_SUMMARY + echo "[Download the test results artifact](${{steps.results.outputs.artifact-url}})" >> $GITHUB_STEP_SUMMARY + deploy: name: 'deploy opentrons package' needs: [test] diff --git a/.gitignore b/.gitignore index 319ccc32e67..2d8b2ff20cb 100755 --- a/.gitignore +++ b/.gitignore @@ -163,3 +163,5 @@ opentrons-robot-app.tar.gz mock_dir .npm-cache/ .eslintcache + +package-testing/results diff --git a/package-testing/Makefile b/package-testing/Makefile new file mode 100644 index 00000000000..6b60cf3401d --- /dev/null +++ b/package-testing/Makefile @@ -0,0 +1,43 @@ +VENV_DIR ?= venv +RESULTS_DIR ?= results +TESTS ?= all + +.PHONY: setup +setup: + @echo "Setting up environment for Unix-like system..." + ./setup.sh $(VENV_DIR) + +.PHONY: setup-windows +setup-windows: + @echo "Setting up environment for Windows..." + pwsh -ExecutionPolicy Bypass -File ./setup.ps1 $(VENV_DIR) + +.PHONY: clean +clean: + @echo "Removing the results directory $(RESULTS_DIR)..." + rm -rf $(RESULTS_DIR) || true + +.PHONY: clean-windows +clean-windows: + @echo "Removing the results directory $(RESULTS_DIR)..." + pwsh -Command "if (Test-Path '$(RESULTS_DIR)') { Remove-Item -Recurse -Force '$(RESULTS_DIR)' }" + +.PHONY: teardown +teardown: clean + rm -rf $(VENV_DIR) || true + +.PHONY: teardown-windows +teardown-windows: clean-windows + pwsh -Command "if (Test-Path '$(VENV_DIR)') { Remove-Item -Recurse -Force '$(VENV_DIR)' }" + + + +.PHONY: test +test: clean + @echo "Running $(TESTS) tests for Unix-like system..." + python run_tests.py $(VENV_DIR) $(RESULTS_DIR) $(TESTS) + +.PHONY: test-windows +test-windows: clean-windows + @echo "Running $(TESTS) tests for Windows..." + python run_tests.py $(VENV_DIR) $(RESULTS_DIR) $(TESTS) diff --git a/package-testing/README.md b/package-testing/README.md new file mode 100644 index 00000000000..88ea89e4e19 --- /dev/null +++ b/package-testing/README.md @@ -0,0 +1,34 @@ +# Test Scripts for the opentrons package + +## Structure + +- Makefile has targets for setting up, tearing down, and running tests for windows and unix-ish systems +- setup.\* is the script run create the virtual environment and install the packages +- help.\* is a script to test --help +- simulate.\* is a script to test that the simulation runs and produces the expected status code +- run_tests.py is the main script that drives test execution and contains the test mapping data + +## Use the tests on Linux and Mac + +1. cd package-testing +2. pyenv local 3.10 +3. make setup - note that this deletes and recreates the virtual environment +4. make test + +## Use the tests on Windows + +- powershell is mapped to pwsh and is version 7 +- python is on the path is version 3.10.\* + +1. cd package-testing +2. make setup-windows - note that this deletes and recreates the virtual environment +3. make test-windows + +## Notes + +- find . -name "\*.sh" -exec shellcheck {} + + +## TODO + +- setup shellcheck and python linting +- more tests diff --git a/package-testing/help.ps1 b/package-testing/help.ps1 new file mode 100644 index 00000000000..277daac5ec8 --- /dev/null +++ b/package-testing/help.ps1 @@ -0,0 +1,69 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS +Validate `opentrons_simulate --help`. + +.PARAMETER TestKey +The test key to identify the test. + +.PARAMETER ExpectedOutput +The expected string to validate in the output of `opentrons_simulate --help`. + +.PARAMETER Venv +The virtual environment directory (default: "venv"). + +.PARAMETER ResultDir +The result directory to store logs (default: "results"). +#> + +param ( + [string]$TestKey, + [string]$ExpectedOutput, + [string]$Venv = "venv", + [string]$ResultDir = "results" +) + +# Ensure the result directory exists +if (-not (Test-Path -Path $ResultDir)) { + New-Item -ItemType Directory -Path $ResultDir | Out-Null +} + +$resultFile = Join-Path -Path $ResultDir -ChildPath "$TestKey.txt" + +Write-Output "Activating virtual environment $Venv..." +$venvActivate = Join-Path -Path $Venv -ChildPath "Scripts/Activate.ps1" +if (-not (Test-Path -Path $venvActivate)) { + Write-Error "FAIL: Virtual environment not found at $venv" + exit 1 +} + +# Source the virtual environment +& $venvActivate + +Write-Output "Validating opentrons_simulate --help for test: $TestKey..." + +# Run the command and capture the output and return code +$output = & opentrons_simulate --help 2>&1 +$returnCode = $LASTEXITCODE + +if ($returnCode -ne 0) { + Write-Output "FAIL: Return code is $returnCode, expected 0" | Tee-Object -FilePath $resultFile + Write-Output "Output was:" | Add-Content -Path $resultFile + $output | Add-Content -Path $resultFile + Rename-Item -Path $resultFile -NewName "${resultFile.Substring(0, $resultFile.Length - 4)}_FAIL.txt" + exit 1 +} + +Write-Output "PASS: Return code is $returnCode, expected 0" | Tee-Object -FilePath $resultFile +Write-Output "Output was:" | Add-Content -Path $resultFile +$output | Add-Content -Path $resultFile + +if ($output -match [regex]::Escape($ExpectedOutput)) { + Write-Output "PASS: Output contains expected string" | Tee-Object -FilePath $resultFile -Append + Write-Output "PASS: Test $TestKey completed successfully." | Tee-Object -FilePath $resultFile -Append + exit 0 +} + +Write-Output "FAIL: Output does not contain expected string" | Tee-Object -FilePath $resultFile -Append +exit 1 diff --git a/package-testing/help.sh b/package-testing/help.sh new file mode 100755 index 00000000000..1d0db6f8f99 --- /dev/null +++ b/package-testing/help.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# Function to validate `opentrons_simulate --help` +# Arguments: +# 1. Test Key (required) +# 2. Virtual Environment Directory (optional, default: "venv") +# 3. Result Directory (optional, default: "results") +test_opentrons_simulate_help() { + local test_key="$1" + local expected_output="${2}" + local venv="${3:-"venv"}" + local result_dir="${4:-"results"}" + mkdir -p "$result_dir" + local result_file="$result_dir/$test_key.txt" + + echo "Activating virtual environment $venv..." + # shellcheck disable=SC1091 + source "$venv/bin/activate" + + echo "Validating opentrons_simulate --help for test: $test_key..." + + local output + local return_code + output=$(opentrons_simulate --help 2>&1) + return_code=$? + + if [ $return_code -ne 0 ]; then + echo "FAIL: Return code is $return_code, expected 0" | tee "$result_file" + echo "Output was:" >> "$result_file" + echo "$output" >> "$result_file" + mv "$result_file" "${result_file%.txt}_FAIL.txt" + return 1 + fi + + echo "PASS: Return code is $return_code, expected 0" | tee "$result_file" + echo "Output was:" >> "$result_file" + echo "$output" >> "$result_file" + + if echo "$output" | grep -q "$expected_output"; then + echo "PASS: Output contains expected string" | tee -a "$result_file" + echo "PASS: Test $test_key completed successfully." | tee -a "$result_file" + return 0 + fi + echo "FAIL: Output does not contain expected string" | tee -a "$result_file" + return 1 +} + +test_opentrons_simulate_help "$@" \ No newline at end of file diff --git a/package-testing/run_tests.py b/package-testing/run_tests.py new file mode 100644 index 00000000000..ce67266df78 --- /dev/null +++ b/package-testing/run_tests.py @@ -0,0 +1,154 @@ +from dataclasses import dataclass +import os +import platform +import subprocess +import sys +from typing import List, Union + + +@dataclass +class TestConfig: + test_key: str + test_helper: str + + +@dataclass +class TestHelp(TestConfig): + expected_output: str + + +@dataclass +class TestSimulate(TestConfig): + protocol_path: str + expected_return_code: str + + +tests: List[Union[TestHelp, TestSimulate]] = [ + TestHelp( + test_key="help", + test_helper="help", + expected_output="Simulate a protocol for an Opentrons robot" + ), + TestSimulate( + test_key="Flex_v2_19_expect_success", + test_helper="simulate", + protocol_path="../analyses-snapshot-testing/files/protocols/Flex_S_v2_19_Illumina_DNA_Prep_48x.py", + expected_return_code="0", + ), + TestSimulate( + test_key="OT2_v2_20_expect_success", + test_helper="simulate", + protocol_path="../analyses-snapshot-testing/files/protocols/OT2_S_v2_20_8_None_SINGLE_HappyPath.py", + expected_return_code="0", + ), + TestSimulate( + test_key="Flex_v2_16_expect_error", + test_helper="simulate", + protocol_path="../analyses-snapshot-testing/files/protocols/Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict.py", + expected_return_code="1", + ), + TestSimulate( + test_key="OT2_v6PD_expect_error", + test_helper="simulate", + protocol_path="../analyses-snapshot-testing/files/protocols/OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods.json", + expected_return_code="1", + ), +] + + +def get_os_type() -> str: + """Determine the current operating system type.""" + return "windows_nt" if "windows" in platform.system().lower() else "unix" + + +def build_command(test: TestConfig, script_ext: str, venv_dir: str, results_dir: str) -> List[str]: + """ + Build the command to run a test based on the test type. + + Args: + test: The test object (either TestHelp or TestSimulate). + script_ext: The script file extension (e.g., "ps1", "sh"). + venv_dir: The virtual environment directory. + results_dir: The directory for storing test results. + + Returns: + A list of strings representing the command to execute. + + Raises: + ValueError: If the test type is unknown. + """ + prefix = ["pwsh", "-File"] if get_os_type() == "windows_nt" else [] + + # Build command based on test type + if isinstance(test, TestHelp): + return prefix + [ + f"./{test.test_helper}.{script_ext}", + test.test_key, + test.expected_output, + venv_dir, + results_dir, + ] + elif isinstance(test, TestSimulate): + return prefix + [ + f"./{test.test_helper}.{script_ext}", + test.test_key, + test.protocol_path, + test.expected_return_code, + venv_dir, + results_dir, + ] + else: + raise ValueError(f"Unknown test type: {type(test)}") + + +def run_test(test: TestConfig, script_ext: str, venv_dir: str, results_dir: str): + """ + Run a single test. + + Args: + test: The test object to run. + script_ext: The script extension (e.g., "ps1", "sh"). + venv_dir: The virtual environment directory. + results_dir: The directory to store test results. + """ + # Ensure results directory exists + os.makedirs(results_dir, exist_ok=True) + + # Build and execute command + command = build_command(test, script_ext, venv_dir, results_dir) + print(f"Running {test.test_key} using {test.test_helper}.{script_ext}...") + try: + subprocess.run(command, check=True, shell=False) + print(f"Test {test.test_key} passed.") + except subprocess.CalledProcessError as e: + print(f"Test {test.test_key} failed: {e}") + sys.exit(1) + + +def main(): + if len(sys.argv) < 4: + print("Usage: python run_tests.py ") + sys.exit(1) + + venv_dir, results_dir, tests_arg = sys.argv[1:4] + os_type = get_os_type() + script_ext = "ps1" if os_type == "windows_nt" else "sh" + + # Filter tests based on user input + if tests_arg.lower() == "all": + selected_tests = tests + else: + requested_keys = tests_arg.split(",") + selected_tests = [test for test in tests if test.test_key in requested_keys] + + if not selected_tests: + print(f"No matching tests found for the provided test keys: {tests_arg}") + sys.exit(1) + + # Run selected tests + for test in selected_tests: + run_test(test, script_ext, venv_dir, results_dir) + + +if __name__ == "__main__": + main() diff --git a/package-testing/setup.ps1 b/package-testing/setup.ps1 new file mode 100644 index 00000000000..afb2258d2b8 --- /dev/null +++ b/package-testing/setup.ps1 @@ -0,0 +1,42 @@ +# Exit immediately on any errors +$ErrorActionPreference = "Stop" + +$VENV_DIR = $null -ne $env:VENV_DIR ? $env:VENV_DIR : "venv" + + +if (Test-Path -Path $VENV_DIR) { + Write-Output "Removing existing virtual environment..." + Remove-Item -Recurse -Force -Path $VENV_DIR +} + +Write-Output "Creating virtual environment in $VENV_DIR..." +python -m venv $VENV_DIR + +Write-Output "Activating virtual environment..." +if ($IsWindows) { + . "$VENV_DIR\Scripts\Activate.ps1" +} else { + . "$VENV_DIR/bin/activate" +} + +Write-Output "Installing packages..." +pip install -U ../shared-data/python ../api + +Write-Output "Validating that opentrons-hardware is not installed..." +$pipList = pip list 2>&1 +if ($pipList -match "opentrons-hardware") { + Write-Output "FAIL: opentrons-hardware is installed" + exit 1 +} else { + Write-Output "PASS: opentrons-hardware is not installed" +} + +Write-Output "Packages installed successfully." +pip list + +Write-Output "To activate the virtual environment, run:" +if ($IsWindows) { + Write-Output ".\$VENV_DIR\Scripts\Activate.ps1" +} else { + Write-Output "source $VENV_DIR/bin/activate" +} diff --git a/package-testing/setup.sh b/package-testing/setup.sh new file mode 100755 index 00000000000..9eefa990cde --- /dev/null +++ b/package-testing/setup.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Exit immediately if a command exits with a non-zero status +set -e + +VENV_DIR=${VENV_DIR:-"venv"} + +if [ -d "$VENV_DIR" ]; then + echo "Removing existing virtual environment..." + rm -rf "$VENV_DIR" +fi + +echo "Creating virtual environment in $VENV_DIR..." +python -m venv "$VENV_DIR" + +echo "Activating virtual environment..." +# shellcheck disable=SC1091 +source "$VENV_DIR/bin/activate" + +echo "Installing packages..." +pip install -U ../shared-data/python ../api # add ../hardware here to validate the below check + +echo "Validate opentrons-hardware is not installed..." +if pip list 2>/dev/null | grep -q "opentrons-hardware"; then + echo "FAIL: opentrons-hardware is installed" + exit 1 +else + echo "PASS: opentrons-hardware is not installed" +fi + +echo "Packages installed successfully." +pip list + +echo "To activate the virtual environment, run:" +echo "source $VENV_DIR/bin/activate" diff --git a/package-testing/simulate.ps1 b/package-testing/simulate.ps1 new file mode 100644 index 00000000000..ecbb3289b02 --- /dev/null +++ b/package-testing/simulate.ps1 @@ -0,0 +1,45 @@ +param ( + [Parameter(Mandatory = $true)][string]$TestKey, + [Parameter(Mandatory = $true)][string]$ProtocolFilePath, + [Parameter(Mandatory = $true)][int]$ExpectedReturnCode, + [string]$Venv = "venv", + [string]$ResultDir = "results" +) + +# Ensure result directory exists +if (-Not (Test-Path -Path $ResultDir)) { + Write-Output "Creating result directory at $ResultDir..." + New-Item -ItemType Directory -Path $ResultDir | Out-Null +} + +# Construct result file path +$ResultFile = Join-Path -Path $ResultDir -ChildPath "$TestKey.txt" + +Write-Output "Activating virtual environment $Venv..." +if (Test-Path -Path "$Venv/Scripts/Activate.ps1") { + . "$Venv/Scripts/Activate.ps1" +} else { + Write-Error "Virtual environment not found at $Venv." + exit 1 +} + +Write-Output "Running opentrons_simulate for protocol:" +Write-Output $ProtocolFilePath + +# Run opentrons_simulate and capture output +$Output = & opentrons_simulate $ProtocolFilePath 2>&1 +$ReturnCode = $LASTEXITCODE + +# Validate return code +if ($ReturnCode -ne $ExpectedReturnCode) { + Write-Output "FAIL: Return code is $ReturnCode, expected $ExpectedReturnCode" | Tee-Object -FilePath $ResultFile + Add-Content -Path $ResultFile -Value "Output was:" + Add-Content -Path $ResultFile -Value $Output + Rename-Item -Path $ResultFile -NewName "$($ResultFile -replace '\.txt$', '_FAIL.txt')" + exit 1 +} else { + Write-Output "PASS: Return code is $ReturnCode, expected $ExpectedReturnCode" | Tee-Object -FilePath $ResultFile + Add-Content -Path $ResultFile -Value "Output was:" + Add-Content -Path $ResultFile -Value $Output + exit 0 +} diff --git a/package-testing/simulate.sh b/package-testing/simulate.sh new file mode 100755 index 00000000000..6eb7039e06c --- /dev/null +++ b/package-testing/simulate.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# Function to test `opentrons_simulate` with a given protocol file +# Arguments: +# 1. Test Key (required) +# 2. Protocol File Path (required) +# 3. Expected return code (required) +# 4. Virtual Environment Directory (optional) +# 5. Result Directory (optional) +simulate_protocol() { + local test_key="$1" + local protocol_file_path="$2" + local expected_return_code="$3" + local venv="${4:-"venv"}" + local result_dir="${5:-"results"}" + mkdir -p "$result_dir" + local result_file="$result_dir/$test_key.txt" + + # echo "test_key: $test_key, protocol_file_path: $protocol_file_path, expected_return_code: $expected_return_code, venv: $venv, result_dir:$result_dir" + # Fail fast if protocol file does not exist + if [ ! -f "$protocol_file_path" ]; then + echo "FAIL: Protocol file not found: $protocol_file_path" + exit 1 + fi + echo "Activating virtual environment $venv ..." + # shellcheck disable=SC1091 + source "$venv/bin/activate" + + printf "Running opentrons_simulate for protocol:\n %s\n" "$protocol_file_path" + + output=$(opentrons_simulate "$protocol_file_path" 2>&1) + return_code=$? + + if [ $return_code -ne "$expected_return_code" ]; then + echo "FAIL: Return code is $return_code, expected $expected_return_code" | tee "$result_file" + echo "Output was:" >> "$result_file" + echo "$output" >> "$result_file" + mv "$result_file" "${result_file%.txt}_FAIL.txt" + exit 1 + else + echo "PASS: Return code is $return_code, expected $expected_return_code" | tee "$result_file" + echo "Output was:" >> "$result_file" + echo "$output" >> "$result_file" + exit 0 + fi +} + +simulate_protocol "$@" From 714a366167e607d2453905ea5e6df0b99edb4def Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:55:29 -0500 Subject: [PATCH 13/42] fix(protocol-designer): analytics opt in modal fixes (#17106) closes AUTH-1142 --- .eslintignore | 1 + components/src/modals/Modal.tsx | 4 +- protocol-designer/cypress/e2e/createNew.cy.ts | 1 + protocol-designer/cypress/e2e/import.cy.ts | 1 + .../cypress/e2e/migrations.cy.ts | 1 + protocol-designer/cypress/e2e/settings.cy.ts | 7 +- protocol-designer/cypress/support/commands.ts | 9 +++ protocol-designer/src/ProtocolRoutes.tsx | 5 +- protocol-designer/src/analytics/actions.ts | 17 +++-- protocol-designer/src/analytics/middleware.ts | 2 +- protocol-designer/src/analytics/mixpanel.ts | 64 ++++++++++--------- protocol-designer/src/analytics/reducers.ts | 10 ++- protocol-designer/src/analytics/selectors.ts | 3 +- .../src/assets/localization/en/shared.json | 2 +- .../components/SettingsPage/SettingsApp.tsx | 13 ++-- .../src/organisms/GateModal/index.tsx | 20 ++---- .../pages/Landing/__tests__/Landing.test.tsx | 5 +- protocol-designer/src/pages/Landing/index.tsx | 2 +- .../Settings/__tests__/Settings.test.tsx | 5 +- .../src/pages/Settings/index.tsx | 22 ++++--- protocol-designer/src/persist.ts | 5 +- 21 files changed, 122 insertions(+), 77 deletions(-) diff --git a/.eslintignore b/.eslintignore index 5d9406d522a..5535673df8f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -12,6 +12,7 @@ **/CHANGELOG.md !api/release-notes.md !app-shell/build/release-notes.md +**/.yarn-cache/** # components library storybook-static diff --git a/components/src/modals/Modal.tsx b/components/src/modals/Modal.tsx index 7be1ca06340..2a622ad083f 100644 --- a/components/src/modals/Modal.tsx +++ b/components/src/modals/Modal.tsx @@ -24,6 +24,7 @@ export interface ModalProps extends StyleProps { zIndexOverlay?: number showOverlay?: boolean position?: Position + hasHeader?: boolean } /** @@ -43,6 +44,7 @@ export const Modal = (props: ModalProps): JSX.Element => { zIndexOverlay, position, showOverlay, + hasHeader = true, ...styleProps } = props @@ -83,7 +85,7 @@ export const Modal = (props: ModalProps): JSX.Element => { showOverlay={showOverlay} zIndexOverlay={zIndexOverlay} width={styleProps.width ?? '31.25rem'} - header={modalHeader} + header={hasHeader ? modalHeader : undefined} onOutsideClick={closeOnOutsideClick ?? false ? onClose : undefined} // center within viewport aside from nav marginLeft={styleProps.marginLeft ?? '5.656rem'} diff --git a/protocol-designer/cypress/e2e/createNew.cy.ts b/protocol-designer/cypress/e2e/createNew.cy.ts index be578415bee..fb1c70470b3 100644 --- a/protocol-designer/cypress/e2e/createNew.cy.ts +++ b/protocol-designer/cypress/e2e/createNew.cy.ts @@ -12,6 +12,7 @@ describe('The Redesigned Create Protocol Landing Page', () => { }) it('content and step 1 flow works', () => { + cy.closeAnalyticsModal() cy.clickCreateNew() cy.verifyCreateNewHeader() verifyCreateProtocolPage() diff --git a/protocol-designer/cypress/e2e/import.cy.ts b/protocol-designer/cypress/e2e/import.cy.ts index 83ddaf0577d..8001f44f7d6 100644 --- a/protocol-designer/cypress/e2e/import.cy.ts +++ b/protocol-designer/cypress/e2e/import.cy.ts @@ -7,6 +7,7 @@ import { describe('The Import Page', () => { beforeEach(() => { cy.visit('/') + cy.closeAnalyticsModal() }) it('successfully loads a protocol exported on a previous version', () => { diff --git a/protocol-designer/cypress/e2e/migrations.cy.ts b/protocol-designer/cypress/e2e/migrations.cy.ts index 61470962bad..eb93db7ed51 100644 --- a/protocol-designer/cypress/e2e/migrations.cy.ts +++ b/protocol-designer/cypress/e2e/migrations.cy.ts @@ -6,6 +6,7 @@ import { TestFilePath } from '../support/testFiles' describe('Protocol fixtures migrate and match snapshots', () => { beforeEach(() => { cy.visit('/') + cy.closeAnalyticsModal() }) const testCases: MigrateTestCase[] = [ diff --git a/protocol-designer/cypress/e2e/settings.cy.ts b/protocol-designer/cypress/e2e/settings.cy.ts index 5ce896aa883..a9802484d89 100644 --- a/protocol-designer/cypress/e2e/settings.cy.ts +++ b/protocol-designer/cypress/e2e/settings.cy.ts @@ -1,6 +1,7 @@ describe('The Settings Page', () => { before(() => { cy.visit('/') + cy.closeAnalyticsModal() }) it('content and toggle state', () => { @@ -19,19 +20,19 @@ describe('The Settings Page', () => { cy.getByTestId('analyticsToggle') .should('exist') .should('be.visible') - .find('path[aria-roledescription="ot-toggle-input-off"]') + .find('path[aria-roledescription="ot-toggle-input-on"]') .should('exist') // Toggle the share sessions with Opentrons setting cy.getByTestId('analyticsToggle').click() cy.getByTestId('analyticsToggle') - .find('path[aria-roledescription="ot-toggle-input-on"]') + .find('path[aria-roledescription="ot-toggle-input-off"]') .should('exist') // Navigate away from the settings page // Then return to see privacy toggle remains toggled on cy.visit('/') cy.openSettingsPage() cy.getByTestId('analyticsToggle').find( - 'path[aria-roledescription="ot-toggle-input-on"]' + 'path[aria-roledescription="ot-toggle-input-off"]' ) // Toggle off editing timeline tips // Navigate away from the settings page diff --git a/protocol-designer/cypress/support/commands.ts b/protocol-designer/cypress/support/commands.ts index 3f9ffd8ddd8..5a40d7762cb 100644 --- a/protocol-designer/cypress/support/commands.ts +++ b/protocol-designer/cypress/support/commands.ts @@ -9,6 +9,7 @@ declare global { verifyFullHeader: () => Cypress.Chainable verifyCreateNewHeader: () => Cypress.Chainable clickCreateNew: () => Cypress.Chainable + closeAnalyticsModal: () => Cypress.Chainable closeAnnouncementModal: () => Cypress.Chainable verifyHomePage: () => Cypress.Chainable importProtocol: (protocolFile: string) => Cypress.Chainable @@ -61,6 +62,7 @@ export const locators = { eula: 'a[href="https://opentrons.com/eula"]', privacyToggle: 'Settings_hotKeys', analyticsToggleTestId: 'analyticsToggle', + confirm: 'Confirm', } // General Custom Commands @@ -111,6 +113,13 @@ Cypress.Commands.add('clickCreateNew', () => { cy.contains(locators.createProtocol).click() }) +Cypress.Commands.add('closeAnalyticsModal', () => { + cy.get('button') + .contains(locators.confirm) + .should('be.visible') + .click({ force: true }) +}) + // Header Import Cypress.Commands.add('importProtocol', (protocolFilePath: string) => { cy.contains(locators.import).click() diff --git a/protocol-designer/src/ProtocolRoutes.tsx b/protocol-designer/src/ProtocolRoutes.tsx index 7350aa0a8da..1f9c4864ed2 100644 --- a/protocol-designer/src/ProtocolRoutes.tsx +++ b/protocol-designer/src/ProtocolRoutes.tsx @@ -59,9 +59,6 @@ export function ProtocolRoutes(): JSX.Element { path: '/', } const allRoutes: RouteProps[] = [...pdRoutes, landingPage] - const showGateModal = - process.env.NODE_ENV === 'production' || process.env.OT_PD_SHOW_GATE - const navigate = useNavigate() const handleReset = (): void => { navigate('/', { replace: true }) @@ -75,7 +72,7 @@ export function ProtocolRoutes(): JSX.Element { - {showGateModal ? : null} + diff --git a/protocol-designer/src/analytics/actions.ts b/protocol-designer/src/analytics/actions.ts index a6fa4fc18cf..d1357dcfc05 100644 --- a/protocol-designer/src/analytics/actions.ts +++ b/protocol-designer/src/analytics/actions.ts @@ -1,9 +1,10 @@ +import { OLDEST_MIGRATEABLE_VERSION } from '../load-file/migration' import { setMixpanelTracking } from './mixpanel' import type { AnalyticsEvent } from './mixpanel' export interface SetOptIn { type: 'SET_OPT_IN' - payload: boolean + payload: { hasOptedIn: boolean; appVersion: string } } const _setOptIn = (payload: SetOptIn['payload']): SetOptIn => { @@ -16,12 +17,20 @@ const _setOptIn = (payload: SetOptIn['payload']): SetOptIn => { return { type: 'SET_OPT_IN', - payload, + payload: { hasOptedIn: payload.hasOptedIn, appVersion: payload.appVersion }, } } -export const optIn = (): SetOptIn => _setOptIn(true) -export const optOut = (): SetOptIn => _setOptIn(false) +export const optIn = (): SetOptIn => + _setOptIn({ + hasOptedIn: true, + appVersion: process.env.OT_PD_VERSION || OLDEST_MIGRATEABLE_VERSION, + }) +export const optOut = (): SetOptIn => + _setOptIn({ + hasOptedIn: false, + appVersion: process.env.OT_PD_VERSION || OLDEST_MIGRATEABLE_VERSION, + }) export interface AnalyticsEventAction { type: 'ANALYTICS_EVENT' payload: AnalyticsEvent diff --git a/protocol-designer/src/analytics/middleware.ts b/protocol-designer/src/analytics/middleware.ts index 6c798e353ff..29cc66f8a11 100644 --- a/protocol-designer/src/analytics/middleware.ts +++ b/protocol-designer/src/analytics/middleware.ts @@ -499,7 +499,7 @@ export const trackEventMiddleware: Middleware = ({ // NOTE: this is the Redux state AFTER the action has been fully dispatched const state = getState() - const optedIn = getHasOptedIn(state as BaseState) ?? false + const optedIn = getHasOptedIn(state as BaseState)?.hasOptedIn ?? false const event = reduxActionToAnalyticsEvent(state as BaseState, action) if (event != null) { diff --git a/protocol-designer/src/analytics/mixpanel.ts b/protocol-designer/src/analytics/mixpanel.ts index 6304753d8c7..c15c95a8f51 100644 --- a/protocol-designer/src/analytics/mixpanel.ts +++ b/protocol-designer/src/analytics/mixpanel.ts @@ -1,10 +1,8 @@ -// TODO(IL, 2020-09-09): reconcile with app/src/analytics/mixpanel.js, which this is derived from import mixpanel from 'mixpanel-browser' import { getIsProduction } from '../networking/opentronsWebApi' import { getHasOptedIn } from './selectors' import type { BaseState } from '../types' -// TODO(IL, 2020-09-09): AnalyticsEvent type copied from app/src/analytics/types.js, consider merging export type AnalyticsEvent = | { name: string @@ -19,18 +17,20 @@ const MIXPANEL_ID = getIsProduction() : process.env.OT_PD_MIXPANEL_DEV_ID const MIXPANEL_OPTS = { - // opt out by default opt_out_tracking_by_default: true, } export function initializeMixpanel(state: BaseState): void { - const optedIn = getHasOptedIn(state) ?? false + const optedIn = getHasOptedIn(state)?.hasOptedIn ?? false if (MIXPANEL_ID != null) { - console.debug('Initializing Mixpanel', { optedIn }) - - mixpanel.init(MIXPANEL_ID, MIXPANEL_OPTS) - setMixpanelTracking(optedIn) - trackEvent({ name: 'appOpen', properties: {} }, optedIn) // TODO IMMEDIATELY: do we want this? + try { + console.debug('Initializing Mixpanel', { optedIn }) + mixpanel.init(MIXPANEL_ID, MIXPANEL_OPTS) + setMixpanelTracking(optedIn) + trackEvent({ name: 'appOpen', properties: {} }, optedIn) + } catch (error) { + console.error('Error initializing Mixpanel:', error) + } } else { console.warn('MIXPANEL_ID not found; this is a bug if build is production') } @@ -40,32 +40,38 @@ export function initializeMixpanel(state: BaseState): void { export function trackEvent(event: AnalyticsEvent, optedIn: boolean): void { console.debug('Trackable event', { event, optedIn }) if (MIXPANEL_ID != null && optedIn) { - if ('superProperties' in event && event.superProperties != null) { - mixpanel.register(event.superProperties) - } - if ('name' in event && event.name != null) { - mixpanel.track(event.name, event.properties) + try { + if ('superProperties' in event && event.superProperties != null) { + mixpanel.register(event.superProperties) + } + if ('name' in event && event.name != null) { + mixpanel.track(event.name, event.properties) + } + } catch (error) { + console.error('Error tracking event:', error) } } } export function setMixpanelTracking(optedIn: boolean): void { if (MIXPANEL_ID != null) { - if (optedIn) { - console.debug('User has opted into analytics; tracking with Mixpanel') - mixpanel.opt_in_tracking() - // Register "super properties" which are included with all events - mixpanel.register({ - appVersion: process.env.OT_PD_VERSION, - // NOTE(IL, 2020): Since PD may be in the same Mixpanel project as other OT web apps, this 'appName' property is intended to distinguish it - appName: 'protocolDesigner', - }) - } else { - console.debug( - 'User has opted out of analytics; stopping Mixpanel tracking' - ) - mixpanel.opt_out_tracking() - mixpanel.reset() + try { + if (optedIn) { + console.debug('User has opted into analytics; tracking with Mixpanel') + mixpanel.opt_in_tracking() + mixpanel.register({ + appVersion: process.env.OT_PD_VERSION, + appName: 'protocolDesigner', + }) + } else { + console.debug( + 'User has opted out of analytics; stopping Mixpanel tracking' + ) + mixpanel.opt_out_tracking() + mixpanel.reset() + } + } catch (error) { + console.error('Error setting Mixpanel tracking:', error) } } } diff --git a/protocol-designer/src/analytics/reducers.ts b/protocol-designer/src/analytics/reducers.ts index 6d4f71ebaa6..9c2427f603a 100644 --- a/protocol-designer/src/analytics/reducers.ts +++ b/protocol-designer/src/analytics/reducers.ts @@ -4,8 +4,14 @@ import type { Reducer } from 'redux' import type { Action } from '../types' import type { SetOptIn } from './actions' import type { RehydratePersistedAction } from '../persist' -type OptInState = boolean | null -const optInInitialState = null +export interface OptInState { + hasOptedIn: boolean | null + appVersion?: string +} +const optInInitialState = { + hasOptedIn: null, +} + // @ts-expect-error(sb, 2021-6-17): cannot use string literals as action type // TODO IMMEDIATELY: refactor this to the old fashioned way if we cannot have type safety: https://github.com/redux-utilities/redux-actions/issues/282#issuecomment-595163081 const hasOptedIn: Reducer = handleActions( diff --git a/protocol-designer/src/analytics/selectors.ts b/protocol-designer/src/analytics/selectors.ts index 77a37bbfcb1..e98c11e3ab7 100644 --- a/protocol-designer/src/analytics/selectors.ts +++ b/protocol-designer/src/analytics/selectors.ts @@ -1,3 +1,4 @@ import type { BaseState } from '../types' -export const getHasOptedIn = (state: BaseState): boolean | null => +import type { OptInState } from './reducers' +export const getHasOptedIn = (state: BaseState): OptInState => state.analytics.hasOptedIn diff --git a/protocol-designer/src/assets/localization/en/shared.json b/protocol-designer/src/assets/localization/en/shared.json index 0d9342713c4..212ae62bf05 100644 --- a/protocol-designer/src/assets/localization/en/shared.json +++ b/protocol-designer/src/assets/localization/en/shared.json @@ -102,7 +102,7 @@ "only_tiprack": "Incompatible file type", "opentrons_flex": "Opentrons Flex", "opentrons": "Opentrons", - "opentrons_collects_data": "In order to improve our products, Opentrons would like to collect data related to your use of Protocol Designer. With your consent, Opentrons will collect and store analytics and session data, including through the use of cookies and similar technologies, solely for the purpose enhancing our products.", + "opentrons_collects_data": "In order to improve our products, Opentrons would like to collect data related to your use of Protocol Designer. Opentrons will collect and store analytics and session data, including through the use of cookies and similar technologies, solely for the purpose enhancing our products.", "ot2": "Opentrons OT-2", "overwrite_labware": "Overwrite labware", "overwrite": "Click Overwrite to replace the existing labware with the new labware.", diff --git a/protocol-designer/src/components/SettingsPage/SettingsApp.tsx b/protocol-designer/src/components/SettingsPage/SettingsApp.tsx index 20a31121010..f3433b9787c 100644 --- a/protocol-designer/src/components/SettingsPage/SettingsApp.tsx +++ b/protocol-designer/src/components/SettingsPage/SettingsApp.tsx @@ -20,13 +20,10 @@ import { FeatureFlagCard } from './FeatureFlagCard/FeatureFlagCard' export function SettingsApp(): JSX.Element { const dispatch = useDispatch() - const hasOptedIn = useSelector(analyticsSelectors.getHasOptedIn) + const { hasOptedIn } = useSelector(analyticsSelectors.getHasOptedIn) const canClearHintDismissals = useSelector( tutorialSelectors.getCanClearHintDismissals ) - const _toggleOptedIn = hasOptedIn - ? analyticsActions.optOut - : analyticsActions.optIn const { t } = useTranslation(['card', 'application', 'button']) return ( @@ -73,7 +70,13 @@ export function SettingsApp(): JSX.Element { dispatch(_toggleOptedIn())} + onClick={() => + dispatch( + hasOptedIn + ? analyticsActions.optOut() + : analyticsActions.optIn() + ) + } /> diff --git a/protocol-designer/src/organisms/GateModal/index.tsx b/protocol-designer/src/organisms/GateModal/index.tsx index cfe35b1b24a..c97db1d5898 100644 --- a/protocol-designer/src/organisms/GateModal/index.tsx +++ b/protocol-designer/src/organisms/GateModal/index.tsx @@ -9,7 +9,6 @@ import { Modal, PrimaryButton, SPACING, - SecondaryButton, StyledText, } from '@opentrons/components' import { @@ -22,12 +21,15 @@ const EULA_URL = 'https://opentrons.com/eula' export function GateModal(): JSX.Element | null { const { t } = useTranslation('shared') - const hasOptedIn = useSelector(analyticsSelectors.getHasOptedIn) + const { appVersion, hasOptedIn } = useSelector( + analyticsSelectors.getHasOptedIn + ) const dispatch = useDispatch() - if (hasOptedIn == null) { + if (appVersion == null || hasOptedIn == null) { return ( - dispatch(analyticsActions.optOut())} - > - - {t('reject')} - - dispatch(analyticsActions.optIn())}> - {t('agree')} + {t('confirm')} @@ -85,9 +80,6 @@ export function GateModal(): JSX.Element | null { }} /> - - {t('analytics_tracking')} - ) diff --git a/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx b/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx index 4ca8430796f..c064a66dfb2 100644 --- a/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx +++ b/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx @@ -35,7 +35,10 @@ const render = () => { describe('Landing', () => { beforeEach(() => { - vi.mocked(getHasOptedIn).mockReturnValue(false) + vi.mocked(getHasOptedIn).mockReturnValue({ + hasOptedIn: false, + appVersion: '8.2.1', + }) vi.mocked(getFileMetadata).mockReturnValue({}) vi.mocked(loadProtocolFile).mockReturnValue(vi.fn()) vi.mocked(useAnnouncements).mockReturnValue({} as any) diff --git a/protocol-designer/src/pages/Landing/index.tsx b/protocol-designer/src/pages/Landing/index.tsx index 3a9ea55bfd3..0e66adaa435 100644 --- a/protocol-designer/src/pages/Landing/index.tsx +++ b/protocol-designer/src/pages/Landing/index.tsx @@ -38,7 +38,7 @@ export function Landing(): JSX.Element { const [showAnnouncementModal, setShowAnnouncementModal] = useState( false ) - const hasOptedIn = useSelector(getHasOptedIn) + const { hasOptedIn } = useSelector(getHasOptedIn) const { bakeToast, eatToast } = useKitchen() const announcements = useAnnouncements() const lastAnnouncement = announcements[announcements.length - 1] diff --git a/protocol-designer/src/pages/Settings/__tests__/Settings.test.tsx b/protocol-designer/src/pages/Settings/__tests__/Settings.test.tsx index 8a1b948e953..671a31ccfc4 100644 --- a/protocol-designer/src/pages/Settings/__tests__/Settings.test.tsx +++ b/protocol-designer/src/pages/Settings/__tests__/Settings.test.tsx @@ -32,7 +32,10 @@ const render = () => { describe('Settings', () => { beforeEach(() => { - vi.mocked(getHasOptedIn).mockReturnValue(false) + vi.mocked(getHasOptedIn).mockReturnValue({ + hasOptedIn: false, + appVersion: '8.2.1', + }) vi.mocked(getFeatureFlagData).mockReturnValue({}) vi.mocked(getCanClearHintDismissals).mockReturnValue(true) }) diff --git a/protocol-designer/src/pages/Settings/index.tsx b/protocol-designer/src/pages/Settings/index.tsx index b678327adb8..7165b5d68a8 100644 --- a/protocol-designer/src/pages/Settings/index.tsx +++ b/protocol-designer/src/pages/Settings/index.tsx @@ -42,18 +42,16 @@ export function Settings(): JSX.Element { const [showAnnouncementModal, setShowAnnouncementModal] = useState( false ) - const hasOptedIn = useSelector(analyticsSelectors.getHasOptedIn) + const analytics = useSelector(analyticsSelectors.getHasOptedIn) const flags = useSelector(getFeatureFlagData) const canClearHintDismissals = useSelector( tutorialSelectors.getCanClearHintDismissals ) - const _toggleOptedIn = hasOptedIn - ? analyticsActions.optOut - : analyticsActions.optIn - const prereleaseModeEnabled = flags.PRERELEASE_MODE === true const pdVersion = process.env.OT_PD_VERSION + const prereleaseModeEnabled = flags.PRERELEASE_MODE === true + const allFlags = Object.keys(flags) as FlagTypes[] const getDescription = (flag: FlagTypes): string => { @@ -276,15 +274,23 @@ export function Settings(): JSX.Element { data-testid="analyticsToggle" size="2rem" css={ - Boolean(hasOptedIn) + Boolean(analytics.hasOptedIn) ? TOGGLE_ENABLED_STYLES : TOGGLE_DISABLED_STYLES } - onClick={() => dispatch(_toggleOptedIn())} + onClick={() => + dispatch( + analytics.hasOptedIn + ? analyticsActions.optOut() + : analyticsActions.optIn() + ) + } > diff --git a/protocol-designer/src/persist.ts b/protocol-designer/src/persist.ts index 693346e77b0..576ad937cc2 100644 --- a/protocol-designer/src/persist.ts +++ b/protocol-designer/src/persist.ts @@ -8,7 +8,10 @@ export interface RehydratePersistedAction { payload: { 'tutorial.dismissedHints'?: Record 'featureFlags.flags'?: Record - 'analytics.hasOptedIn'?: boolean | null + 'analytics.hasOptedIn'?: { + hasOptedIn: boolean | null + appVersion?: string + } } } export const getLocalStorageItem = (path: string): unknown => { From 4446eafa6354b4ffbc3b7925ce54541128a5e8ff Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:49:12 -0500 Subject: [PATCH 14/42] =?UTF-8?q?fix(protocol-designer):=20heater=20shaker?= =?UTF-8?q?=20timer=20field=20is=20a=20boolean=20instea=E2=80=A6=20(#17119?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …d of boolean string closes RQA-3794 --- .../src/molecules/ToggleExpandStepFormField/index.tsx | 6 +----- .../StepForm/StepTools/HeaterShakerTools/index.tsx | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/protocol-designer/src/molecules/ToggleExpandStepFormField/index.tsx b/protocol-designer/src/molecules/ToggleExpandStepFormField/index.tsx index 7412afb3c2a..a99f6547f7a 100644 --- a/protocol-designer/src/molecules/ToggleExpandStepFormField/index.tsx +++ b/protocol-designer/src/molecules/ToggleExpandStepFormField/index.tsx @@ -62,11 +62,7 @@ export function ToggleExpandStepFormField( resetFieldValue() } } else if (toggleValue == null) { - toggleUpdateValue( - name === 'targetTemperature' || name === 'heaterShakerTimer' - ? 'true' - : true - ) + toggleUpdateValue(name === 'targetTemperature' ? 'true' : true) } else { toggleUpdateValue(!toggleValue) if (toggleValue) { diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/HeaterShakerTools/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/HeaterShakerTools/index.tsx index 1577db5da8c..3447de54069 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/HeaterShakerTools/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/HeaterShakerTools/index.tsx @@ -103,7 +103,7 @@ export function HeaterShakerTools(props: StepFormProps): JSX.Element { 'form:step_edit_form.field.heaterShaker.timer.heaterShakerSetTimer' )} fieldTitle={t('form:step_edit_form.field.heaterShaker.duration')} - isSelected={formData.heaterShakerSetTimer === 'true'} + isSelected={formData.heaterShakerSetTimer === true} units={t('application:units.time')} toggleElement="checkbox" formLevelError={getFormLevelError( From f22ed4167c343c2c78c477a5a3b69aac860663ac Mon Sep 17 00:00:00 2001 From: Jeremy Leon Date: Mon, 16 Dec 2024 16:34:33 -0500 Subject: [PATCH 15/42] feat(engine): add mmFromEdge parameter to touchTip (#17107) Adds a new optional parameter `mmFromEdge` to the protocol engine `touchTip` command, primarily for usage for transfering liquids defined by a liquid class. --- .../protocol_engine/commands/touch_tip.py | 19 ++- .../protocol_engine/errors/__init__.py | 2 + .../protocol_engine/errors/exceptions.py | 13 +++ .../protocol_engine/state/_move_types.py | 14 ++- .../opentrons/protocol_engine/state/motion.py | 7 +- .../commands/test_touch_tip.py | 110 +++++++++++++++++- .../protocol_engine/state/test_motion_view.py | 2 + .../protocol_engine/state/test_move_types.py | 28 +++-- shared-data/command/schemas/11.json | 5 + 9 files changed, 180 insertions(+), 20 deletions(-) diff --git a/api/src/opentrons/protocol_engine/commands/touch_tip.py b/api/src/opentrons/protocol_engine/commands/touch_tip.py index 2d7c507d321..2eefd572d9a 100644 --- a/api/src/opentrons/protocol_engine/commands/touch_tip.py +++ b/api/src/opentrons/protocol_engine/commands/touch_tip.py @@ -7,7 +7,11 @@ from opentrons.types import Point -from ..errors import TouchTipDisabledError, LabwareIsTipRackError +from ..errors import ( + TouchTipDisabledError, + TouchTipIncompatibleArgumentsError, + LabwareIsTipRackError, +) from ..types import DeckPoint from .command import ( AbstractCommandImpl, @@ -45,6 +49,12 @@ class TouchTipParams(PipetteIdMixin, WellLocationMixin): ), ) + mmFromEdge: Optional[float] = Field( + None, + description="Offset away from the the well edge, in millimeters." + "Incompatible when a radius is included as a non 1.0 value.", + ) + speed: Optional[float] = Field( None, description=( @@ -89,6 +99,11 @@ async def execute( labware_id = params.labwareId well_name = params.wellName + if params.radius != 1.0 and params.mmFromEdge is not None: + raise TouchTipIncompatibleArgumentsError( + "Cannot use mmFromEdge with a radius that is not 1.0" + ) + if self._state_view.labware.get_has_quirk(labware_id, "touchTipDisabled"): raise TouchTipDisabledError( f"Touch tip not allowed on labware {labware_id}" @@ -112,11 +127,13 @@ async def execute( pipette_id, params.speed ) + mm_from_edge = params.mmFromEdge if params.mmFromEdge is not None else 0 touch_waypoints = self._state_view.motion.get_touch_tip_waypoints( pipette_id=pipette_id, labware_id=labware_id, well_name=well_name, radius=params.radius, + mm_from_edge=mm_from_edge, center_point=Point( center_result.public.position.x, center_result.public.position.y, diff --git a/api/src/opentrons/protocol_engine/errors/__init__.py b/api/src/opentrons/protocol_engine/errors/__init__.py index 8148ce132e6..2b0fb6a6060 100644 --- a/api/src/opentrons/protocol_engine/errors/__init__.py +++ b/api/src/opentrons/protocol_engine/errors/__init__.py @@ -24,6 +24,7 @@ LabwareIsTipRackError, LabwareIsAdapterError, TouchTipDisabledError, + TouchTipIncompatibleArgumentsError, WellDoesNotExistError, PipetteNotLoadedError, ModuleNotLoadedError, @@ -110,6 +111,7 @@ "LabwareIsTipRackError", "LabwareIsAdapterError", "TouchTipDisabledError", + "TouchTipIncompatibleArgumentsError", "WellDoesNotExistError", "PipetteNotLoadedError", "ModuleNotLoadedError", diff --git a/api/src/opentrons/protocol_engine/errors/exceptions.py b/api/src/opentrons/protocol_engine/errors/exceptions.py index 563a1fb816d..c3fddf99a61 100644 --- a/api/src/opentrons/protocol_engine/errors/exceptions.py +++ b/api/src/opentrons/protocol_engine/errors/exceptions.py @@ -361,6 +361,19 @@ def __init__( super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping) +class TouchTipIncompatibleArgumentsError(ProtocolEngineError): + """Raised when touch tip is used with both a custom radius and a mmFromEdge argument.""" + + def __init__( + self, + message: Optional[str] = None, + details: Optional[Dict[str, Any]] = None, + wrapping: Optional[Sequence[EnumeratedError]] = None, + ) -> None: + """Build a TouchTipIncompatibleArgumentsError.""" + super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping) + + class WellDoesNotExistError(ProtocolEngineError): """Raised when referencing a well that does not exist.""" diff --git a/api/src/opentrons/protocol_engine/state/_move_types.py b/api/src/opentrons/protocol_engine/state/_move_types.py index b8dcb28bd8d..94201ffead9 100644 --- a/api/src/opentrons/protocol_engine/state/_move_types.py +++ b/api/src/opentrons/protocol_engine/state/_move_types.py @@ -53,15 +53,19 @@ def get_move_type_to_well( def get_edge_point_list( - center: Point, x_radius: float, y_radius: float, edge_path_type: EdgePathType + center: Point, + x_radius: float, + y_radius: float, + mm_from_edge: float, + edge_path_type: EdgePathType, ) -> List[Point]: """Get list of edge points dependent on edge path type.""" edges = EdgeList( - right=center + Point(x=x_radius, y=0, z=0), - left=center + Point(x=-x_radius, y=0, z=0), + right=center + Point(x=x_radius - mm_from_edge, y=0, z=0), + left=center + Point(x=-x_radius + mm_from_edge, y=0, z=0), center=center, - forward=center + Point(x=0, y=y_radius, z=0), - back=center + Point(x=0, y=-y_radius, z=0), + forward=center + Point(x=0, y=y_radius - mm_from_edge, z=0), + back=center + Point(x=0, y=-y_radius + mm_from_edge, z=0), ) if edge_path_type == EdgePathType.LEFT: diff --git a/api/src/opentrons/protocol_engine/state/motion.py b/api/src/opentrons/protocol_engine/state/motion.py index 0863c42a0c1..855025d01b6 100644 --- a/api/src/opentrons/protocol_engine/state/motion.py +++ b/api/src/opentrons/protocol_engine/state/motion.py @@ -327,6 +327,7 @@ def get_touch_tip_waypoints( labware_id: str, well_name: str, center_point: Point, + mm_from_edge: float = 0, radius: float = 1.0, ) -> List[motion_planning.Waypoint]: """Get a list of touch points for a touch tip operation.""" @@ -346,7 +347,11 @@ def get_touch_tip_waypoints( ) positions = _move_types.get_edge_point_list( - center_point, x_offset, y_offset, edge_path_type + center=center_point, + x_radius=x_offset, + y_radius=y_offset, + mm_from_edge=mm_from_edge, + edge_path_type=edge_path_type, ) critical_point: Optional[CriticalPoint] = None diff --git a/api/tests/opentrons/protocol_engine/commands/test_touch_tip.py b/api/tests/opentrons/protocol_engine/commands/test_touch_tip.py index 0d4071efd6c..5756810c9ee 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_touch_tip.py +++ b/api/tests/opentrons/protocol_engine/commands/test_touch_tip.py @@ -102,8 +102,99 @@ async def test_touch_tip_implementation( pipette_id="abc", labware_id="123", well_name="A3", - center_point=Point(x=1, y=2, z=3), radius=0.456, + mm_from_edge=0, + center_point=Point(x=1, y=2, z=3), + ) + ).then_return( + [ + Waypoint( + position=Point(x=11, y=22, z=33), + critical_point=CriticalPoint.XY_CENTER, + ), + Waypoint( + position=Point(x=44, y=55, z=66), + critical_point=CriticalPoint.XY_CENTER, + ), + ] + ) + + decoy.when( + await mock_gantry_mover.move_to( + pipette_id="abc", + waypoints=[ + Waypoint( + position=Point(x=11, y=22, z=33), + critical_point=CriticalPoint.XY_CENTER, + ), + Waypoint( + position=Point(x=44, y=55, z=66), + critical_point=CriticalPoint.XY_CENTER, + ), + ], + speed=9001, + ) + ).then_return(Point(x=4, y=5, z=6)) + + result = await subject.execute(params) + + assert result == SuccessData( + public=TouchTipResult(position=DeckPoint(x=4, y=5, z=6)), + state_update=update_types.StateUpdate( + pipette_location=update_types.PipetteLocationUpdate( + pipette_id="abc", + new_location=update_types.Well(labware_id="123", well_name="A3"), + new_deck_point=DeckPoint(x=4, y=5, z=6), + ) + ), + ) + + +async def test_touch_tip_implementation_with_mm_to_edge( + decoy: Decoy, + mock_state_view: StateView, + mock_movement_handler: MovementHandler, + mock_gantry_mover: GantryMover, + subject: TouchTipImplementation, +) -> None: + """A TouchTip command should use mmFromEdge if provided.""" + params = TouchTipParams( + pipetteId="abc", + labwareId="123", + wellName="A3", + wellLocation=WellLocation(offset=WellOffset(x=1, y=2, z=3)), + mmFromEdge=0.789, + speed=42.0, + ) + + decoy.when( + await mock_movement_handler.move_to_well( + pipette_id="abc", + labware_id="123", + well_name="A3", + well_location=WellLocation(offset=WellOffset(x=1, y=2, z=3)), + current_well=None, + force_direct=False, + minimum_z_height=None, + speed=None, + operation_volume=None, + ) + ).then_return(Point(x=1, y=2, z=3)) + + decoy.when( + mock_state_view.pipettes.get_movement_speed( + pipette_id="abc", requested_speed=42.0 + ) + ).then_return(9001) + + decoy.when( + mock_state_view.motion.get_touch_tip_waypoints( + pipette_id="abc", + labware_id="123", + well_name="A3", + radius=1.0, + mm_from_edge=0.789, + center_point=Point(x=1, y=2, z=3), ) ).then_return( [ @@ -183,3 +274,20 @@ async def test_touch_tip_no_tip_racks( with pytest.raises(errors.LabwareIsTipRackError): await subject.execute(params) + + +async def test_touch_tip_incompatible_arguments( + decoy: Decoy, mock_state_view: StateView, subject: TouchTipImplementation +) -> None: + """It should disallow touch tip if radius and mmFromEdge is provided.""" + params = TouchTipParams( + pipetteId="abc", + labwareId="123", + wellName="A3", + wellLocation=WellLocation(), + radius=1.23, + mmFromEdge=4.56, + ) + + with pytest.raises(errors.TouchTipIncompatibleArgumentsError): + await subject.execute(params) diff --git a/api/tests/opentrons/protocol_engine/state/test_motion_view.py b/api/tests/opentrons/protocol_engine/state/test_motion_view.py index 9e7307f29a7..3e9d60da79a 100644 --- a/api/tests/opentrons/protocol_engine/state/test_motion_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_motion_view.py @@ -928,6 +928,7 @@ def test_get_touch_tip_waypoints( x_radius=1.2, y_radius=3.4, edge_path_type=_move_types.EdgePathType.RIGHT, + mm_from_edge=0.456, ) ).then_return([Point(x=11, y=22, z=33), Point(x=44, y=55, z=66)]) @@ -937,6 +938,7 @@ def test_get_touch_tip_waypoints( well_name="B2", center_point=center_point, radius=0.123, + mm_from_edge=0.456, ) assert result == [ diff --git a/api/tests/opentrons/protocol_engine/state/test_move_types.py b/api/tests/opentrons/protocol_engine/state/test_move_types.py index 9d46cb8a1ab..27f43ffbc0d 100644 --- a/api/tests/opentrons/protocol_engine/state/test_move_types.py +++ b/api/tests/opentrons/protocol_engine/state/test_move_types.py @@ -53,43 +53,47 @@ def test_get_move_type_to_well( ( subject.EdgePathType.LEFT, [ - Point(5, 20, 30), + Point(8, 20, 30), Point(10, 20, 30), - Point(10, 30, 30), - Point(10, 10, 30), + Point(10, 27, 30), + Point(10, 13, 30), Point(10, 20, 30), ], ), ( subject.EdgePathType.RIGHT, [ - Point(15, 20, 30), + Point(12, 20, 30), Point(10, 20, 30), - Point(10, 30, 30), - Point(10, 10, 30), + Point(10, 27, 30), + Point(10, 13, 30), Point(10, 20, 30), ], ), ( subject.EdgePathType.DEFAULT, [ - Point(15, 20, 30), - Point(5, 20, 30), + Point(12, 20, 30), + Point(8, 20, 30), Point(10, 20, 30), - Point(10, 30, 30), - Point(10, 10, 30), + Point(10, 27, 30), + Point(10, 13, 30), Point(10, 20, 30), ], ), ], ) -def get_edge_point_list( +def test_get_edge_point_list( edge_path_type: subject.EdgePathType, expected_result: List[Point], ) -> None: """It should get a list of well edge points.""" result = subject.get_edge_point_list( - Point(x=10, y=20, z=30), x_radius=5, y_radius=10, edge_path_type=edge_path_type + Point(x=10, y=20, z=30), + x_radius=5, + y_radius=10, + mm_from_edge=3, + edge_path_type=edge_path_type, ) assert result == expected_result diff --git a/shared-data/command/schemas/11.json b/shared-data/command/schemas/11.json index 955dff87690..5bfd3569c0c 100644 --- a/shared-data/command/schemas/11.json +++ b/shared-data/command/schemas/11.json @@ -3924,6 +3924,11 @@ "default": 1.0, "type": "number" }, + "mmFromEdge": { + "title": "Mmfromedge", + "description": "Offset away from the the well edge, in millimeters.Incompatible when a radius is included as a non 1.0 value.", + "type": "number" + }, "speed": { "title": "Speed", "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", From e236cb6e4155404a83830d7c03c1d5826edec18c Mon Sep 17 00:00:00 2001 From: koji Date: Mon, 16 Dec 2024 16:37:06 -0500 Subject: [PATCH 16/42] fix(protocol-designer) remove hardcoded pd version from release notes modal (#17121) * fix(protocol-designer) remove hardcoded pd version from release notes modal --- protocol-designer/src/assets/localization/en/modal.json | 2 +- .../src/organisms/AnnouncementModal/announcements.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/protocol-designer/src/assets/localization/en/modal.json b/protocol-designer/src/assets/localization/en/modal.json index 2c065e2d6b6..8530f61a28a 100644 --- a/protocol-designer/src/assets/localization/en/modal.json +++ b/protocol-designer/src/assets/localization/en/modal.json @@ -52,7 +52,7 @@ "body6": "All protocols require {{app}} version 7.3.0 or later to run." }, "redesign": { - "body1": "Welcome to Protocol Designer 8.2.0!", + "body1": "Welcome to Protocol Designer {{version}}!", "body2": "We’re excited to release the new Opentrons Protocol Designer, now with a fresh redesign! Enjoy the same functionality with the added ability to:", "body3": "Add multiple Heater-Shaker Modules and Magnetic Blocks to the deck (Flex only).", "body4": "All protocols now require Opentrons App version 8.2.0+ to run.", diff --git a/protocol-designer/src/organisms/AnnouncementModal/announcements.tsx b/protocol-designer/src/organisms/AnnouncementModal/announcements.tsx index edbc801351a..76eda9f25ea 100644 --- a/protocol-designer/src/organisms/AnnouncementModal/announcements.tsx +++ b/protocol-designer/src/organisms/AnnouncementModal/announcements.tsx @@ -47,6 +47,7 @@ const OPENTRONS_PD = 'Opentrons Protocol Designer' export const useAnnouncements = (): Announcement[] => { const { t } = useTranslation('modal') + const pdVersion = process.env.OT_PD_VERSION return [ { @@ -307,7 +308,7 @@ export const useAnnouncements = (): Announcement[] => { { announcementKey: 'redesign8.2', image: , - heading: t('announcements.redesign.body1'), + heading: t('announcements.redesign.body1', { version: pdVersion }), message: ( From d69ca2b413034c5f1ac3c7053e86829fc999f449 Mon Sep 17 00:00:00 2001 From: Sarah Breen Date: Mon, 16 Dec 2024 17:58:59 -0500 Subject: [PATCH 17/42] refactor(app): add any found hardcoded copy to i18n for translation (#17095) fix EXEC-879, EXEC-878 --- app/src/App/DesktopApp.tsx | 22 +- app/src/App/Navbar.tsx | 5 +- app/src/assets/localization/en/anonymous.json | 1 + .../assets/localization/en/app_settings.json | 6 + app/src/assets/localization/en/branded.json | 1 + .../localization/en/device_settings.json | 39 ++ .../localization/en/gripper_wizard_flows.json | 2 - .../localization/en/pipette_wizard_flows.json | 1 + .../en/protocol_command_text.json | 5 + .../localization/en/top_navigation.json | 6 + .../getConfigureNozzleLayoutCommandText.ts | 11 +- .../Desktop/Alerts/U2EDriverOutdatedAlert.tsx | 27 +- .../ConfigurePipette/ConfigMessage.tsx | 19 - .../AdvancedTab/UpdateRobotSoftware.tsx | 2 +- .../ConnectNetwork/ConnectModal/FormModal.tsx | 29 +- .../ConnectModal/KeyFileField.tsx | 13 +- .../ConnectModal/SecurityField.tsx | 9 +- .../ConnectNetwork/ConnectModal/TextField.tsx | 5 +- .../__tests__/form-fields.test.ts | 379 ---------------- .../__tests__/form-fields.test.tsx | 422 ++++++++++++++++++ .../ConnectModal/form-fields.ts | 50 ++- .../ConnectNetwork/ConnectModal/index.tsx | 15 +- .../ConnectNetwork/ResultModal.tsx | 31 +- .../ConnectNetwork/SelectSsid/index.tsx | 21 +- .../RobotSettings/ConnectNetwork/i18n.ts | 103 ----- .../UpdateBuildroot/UpdateRobotModal.tsx | 2 +- .../GripperWizardFlows/BeforeBeginning.tsx | 6 +- .../organisms/GripperWizardFlows/constants.ts | 4 + .../QuickTransferFlow/NameQuickTransfer.tsx | 1 - .../PipetteWizardFlows/BeforeBeginning.tsx | 14 +- .../organisms/PipetteWizardFlows/constants.ts | 5 +- app/src/pages/Desktop/Labware/index.tsx | 1 + .../robot-update/__tests__/selectors.test.ts | 18 +- app/src/redux/robot-update/selectors.ts | 22 +- app/src/redux/system-info/constants.ts | 9 - shared-data/js/fixtures.ts | 2 +- 36 files changed, 649 insertions(+), 659 deletions(-) delete mode 100644 app/src/organisms/Desktop/Devices/ConfigurePipette/ConfigMessage.tsx delete mode 100644 app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts create mode 100644 app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.tsx delete mode 100644 app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/i18n.ts diff --git a/app/src/App/DesktopApp.tsx b/app/src/App/DesktopApp.tsx index 029ec99ee26..196a6cf547c 100644 --- a/app/src/App/DesktopApp.tsx +++ b/app/src/App/DesktopApp.tsx @@ -1,4 +1,5 @@ import { useState, Fragment } from 'react' +import { useTranslation } from 'react-i18next' import { Navigate, Route, Routes, useMatch } from 'react-router-dom' import { ErrorBoundary } from 'react-error-boundary' import { @@ -43,6 +44,7 @@ import { useFeatureFlag } from '../redux/config' import type { RouteProps } from './types' export const DesktopApp = (): JSX.Element => { + const { t } = useTranslation('top_navigation') useSoftwareUpdatePoll() const [ isEmergencyStopModalDismissed, @@ -68,55 +70,55 @@ export const DesktopApp = (): JSX.Element => { const desktopRoutes: RouteProps[] = [ { Component: ProtocolsLanding, - name: 'protocols', + name: t('protocols'), navLinkTo: '/protocols', path: '/protocols', }, { Component: ProtocolDetails, - name: 'Protocol Details', + name: t('protocol_details'), path: '/protocols/:protocolKey', }, { Component: ProtocolTimeline, - name: 'Protocol Timeline', + name: t('protocol_timeline'), path: '/protocols/:protocolKey/timeline', }, { Component: Labware, - name: 'labware', + name: t('labware'), navLinkTo: '/labware', path: '/labware', }, { Component: DevicesLanding, - name: 'devices', + name: t('devices'), navLinkTo: '/devices', path: '/devices', }, { Component: DeviceDetails, - name: 'Device', + name: t('device'), path: '/devices/:robotName', }, { Component: RobotSettings, - name: 'Robot Settings', + name: t('robot_settings'), path: '/devices/:robotName/robot-settings/:robotSettingsTab?', }, { Component: CalibrationDashboard, - name: 'Calibration Dashboard', + name: t('calibration_dashboard'), path: '/devices/:robotName/robot-settings/calibration/dashboard', }, { Component: ProtocolRunDetails, - name: 'Run Details', + name: t('run_details'), path: '/devices/:robotName/protocol-runs/:runId/:protocolRunDetailsTab?', }, { Component: AppSettings, - name: 'App Settings', + name: t('app_settings'), path: '/app-settings/:appSettingsTab?', }, ] diff --git a/app/src/App/Navbar.tsx b/app/src/App/Navbar.tsx index 1471ca4c593..1d7711563ae 100644 --- a/app/src/App/Navbar.tsx +++ b/app/src/App/Navbar.tsx @@ -1,5 +1,4 @@ import { useCallback } from 'react' -import { useTranslation } from 'react-i18next' import { NavLink, useNavigate } from 'react-router-dom' import styled from 'styled-components' import debounce from 'lodash/debounce' @@ -111,8 +110,6 @@ const LogoImg = styled('img')` ` export function Navbar({ routes }: { routes: RouteProps[] }): JSX.Element { - const { t } = useTranslation('top_navigation') - const navigate = useNavigate() const navRoutes = routes.filter( ({ navLinkTo }: RouteProps) => navLinkTo != null @@ -151,7 +148,7 @@ export function Navbar({ routes }: { routes: RouteProps[] }): JSX.Element { as="h3" margin={`${SPACING.spacing8} 0 ${SPACING.spacing8} ${SPACING.spacing12}`} > - {t(name)} + {name} ))} diff --git a/app/src/assets/localization/en/anonymous.json b/app/src/assets/localization/en/anonymous.json index 280e602088d..bcfb90dc7eb 100644 --- a/app/src/assets/localization/en/anonymous.json +++ b/app/src/assets/localization/en/anonymous.json @@ -71,6 +71,7 @@ "storage_limit_reached_description": "Your robot has reached the limit of quick transfers that it can store. You must delete an existing quick transfer before creating a new one.", "system_language_preferences_update_description": "Your system’s language was recently updated. Would you like to use the updated language as the default for the app?", "these_are_advanced_settings": "These are advanced settings. Please do not attempt to adjust without assistance from support. Changing these settings may affect the lifespan of your pipette.These settings do not override any pipette settings defined in protocols.", + "u2e_driver_description": "The OT-2 uses this adapter for its USB connection to the desktop app.", "unexpected_error": "An unexpected error has occurred. If the issue persists, contact customer support for assistance.", "update_requires_restarting_app": "Updating requires restarting the app.", "update_robot_software_description": "Bypass the auto-update process and update the robot software manually.", diff --git a/app/src/assets/localization/en/app_settings.json b/app/src/assets/localization/en/app_settings.json index b4d5f654291..c6c4b595597 100644 --- a/app/src/assets/localization/en/app_settings.json +++ b/app/src/assets/localization/en/app_settings.json @@ -37,7 +37,9 @@ "connect_ip_link": "Learn more about connecting a robot manually", "discovery_timeout": "Discovery timed out.", "dont_change": "Don’t change", + "dont_remind_me": "Don't remind me again", "download_update": "Downloading update...", + "driver_out_of_date": "Realtek USB-to-Ethernet Driver Update Available", "enable_dev_tools": "Developer Tools", "enable_dev_tools_description": "Enabling this setting opens Developer Tools on app launch, enables additional logging and gives access to feature flags.", "error_boundary_desktop_app_description": "You need to reload the app. Contact support with the following error message:", @@ -46,6 +48,7 @@ "error_recovery_mode_description": "Pause on protocol errors instead of canceling the run.", "feature_flags": "Feature Flags", "general": "General", + "get_update": "get update", "heater_shaker_attach_description": "Display a reminder to attach the Heater-Shaker properly before running a test shake or using it in a protocol.", "heater_shaker_attach_visible": "Confirm Heater-Shaker Module Attachment", "how_to_restore": "How to Restore a Previous Software Version", @@ -66,6 +69,7 @@ "ot2_advanced_settings": "OT-2 Advanced Settings", "override_path": "override path", "override_path_to_python": "Override Path to Python", + "please_update_driver": "Please update your computer's driver to ensure a reliable connection to your OT-2.", "prevent_robot_caching": "Prevent Robot Caching", "prevent_robot_caching_description": "The app will immediately clear unavailable robots and will not remember unavailable robots while this is enabled. On networks with many robots, preventing caching may improve network performance at the expense of slower and less reliable robot discovery on app launch.", "privacy": "Privacy", @@ -94,6 +98,7 @@ "trash_bin": "Always use trash bin to calibrate", "try_restarting_the_update": "Try restarting the update.", "turn_off_updates": "Turn off software update notifications in App Settings.", + "u2e_driver_outdated_message": "There is an updated Realtek USB-to-Ethernet adapter driver available for your computer.", "up_to_date": "Up to date", "update_alerts": "Software Update Alerts", "update_app_now": "Update app now", @@ -113,5 +118,6 @@ "usb_to_ethernet_unknown_product": "Unknown Adapter", "use_system_language": "Use system language", "view_software_update": "View software update", + "view_adapter_info": "view adapter info", "view_update": "View Update" } diff --git a/app/src/assets/localization/en/branded.json b/app/src/assets/localization/en/branded.json index 0760c3061b4..42c22baa8ad 100644 --- a/app/src/assets/localization/en/branded.json +++ b/app/src/assets/localization/en/branded.json @@ -71,6 +71,7 @@ "storage_limit_reached_description": "Your Opentrons Flex has reached the limit of quick transfers that it can store. You must delete an existing quick transfer before creating a new one.", "system_language_preferences_update_description": "Your system’s language was recently updated. Would you like to use the updated language as the default for the Opentrons App?", "these_are_advanced_settings": "These are advanced settings. Please do not attempt to adjust without assistance from Opentrons Support. Changing these settings may affect the lifespan of your pipette.These settings do not override any pipette settings defined in protocols.", + "u2e_driver_description": "The OT-2 uses this adapter for its USB connection to the Opentrons App.", "unexpected_error": "An unexpected error has occurred. If the issue persists, contact Opentrons Support for assistance.", "update_requires_restarting_app": "Updating requires restarting the Opentrons App.", "update_robot_software_description": "Bypass the Opentrons App auto-update process and update the robot software manually.", diff --git a/app/src/assets/localization/en/device_settings.json b/app/src/assets/localization/en/device_settings.json index 79416a09f73..06a67d39d35 100644 --- a/app/src/assets/localization/en/device_settings.json +++ b/app/src/assets/localization/en/device_settings.json @@ -3,6 +3,7 @@ "about_calibration_description": "For the robot to move accurately and precisely, you need to calibrate it. Positional calibration happens in three parts: deck calibration, pipette offset calibration and tip length calibration.", "about_calibration_description_ot3": "For the robot to move accurately and precisely, you need to calibrate it. Pipette and gripper calibration is an automated process that uses a calibration probe or pin.After calibration is complete, you can save the calibration data to your computer as a JSON file.", "about_calibration_title": "About Calibration", + "add_new": "Add new...", "advanced": "Advanced", "alpha_description": "Warning: alpha releases are feature-complete but may contain significant bugs.", "alternative_security_types": "Alternative security types", @@ -10,10 +11,12 @@ "apply_historic_offsets": "Apply Labware Offsets", "are_you_sure_you_want_to_disconnect": "Are you sure you want to disconnect from {{ssid}}?", "attach_a_pipette_before_calibrating": "Attach a pipette in order to perform calibration", + "authentication": "Authentication", "boot_scripts": "Boot scripts", "both": "Both", "browse_file_system": "Browse file system", "bug_fixes": "Bug Fixes", + "but_we_expected": "but we expected", "calibrate_deck": "Calibrate deck", "calibrate_deck_description": "For pre-2019 robots that do not have crosses etched on the deck.", "calibrate_deck_to_dots": "Calibrate deck to dots", @@ -28,8 +31,10 @@ "change_network": "Change network", "characters_max": "17 characters max", "check_for_updates": "Check for updates", + "check_to_verify_update": "Check your robot's settings page to verify whether or not the update was successful", "checking_for_updates": "Checking for updates", "choose": "Choose...", + "choose_a_network": "Choose a network...", "choose_file": "Choose file", "choose_network_type": "Choose network type", "choose_reset_settings": "Choose reset settings", @@ -56,7 +61,9 @@ "confirm_device_reset_heading": "Are you sure you want to reset your device?", "connect": "Connect", "connect_the_estop_to_continue": "Connect the E-stop to continue", + "connect_to_ssid": "Connect to {{ssid}}", "connect_to_wifi_network": "Connect to Wi-Fi network", + "connect_to_wifi_network_failure": "Your robot was unable to connect to Wi-Fi network {{ssid}}", "connect_via": "Connect via {{type}}", "connect_via_usb_description_1": "1. Connect the USB A-to-B cable to the robot’s USB-B port.", "connect_via_usb_description_2": "2. Connect the cable to an open USB port on your computer.", @@ -65,6 +72,7 @@ "connected_to_ssid": "Connected to {{ssid}}", "connected_via": "Connected via {{networkInterface}}", "connecting_to": "Connecting to {{ssid}}...", + "connecting_to_wifi_network": "Connecting to Wi-Fi network {{ssid}}", "connection_description_ethernet": "Connect to your lab's wired network.", "connection_description_wifi": "Find a network in your lab or enter your own.", "connection_to_robot_lost": "Connection to robot lost", @@ -96,6 +104,7 @@ "display_sleep_settings": "Display Sleep Settings", "do_not_turn_off": "This could take up to {{minutes}} minutes. Don't turn off the robot.", "done": "Done", + "downgrade": "downgrade", "download": "Download", "download_calibration_data": "Download calibration logs", "download_error": "Download error", @@ -109,6 +118,7 @@ "enable_status_light_description": "Turn on or off the strip of color LEDs on the front of the robot.", "engaged": "Engaged", "enter_factory_password": "Enter factory password", + "enter_name_security_type": "Enter the network name and security type.", "enter_network_name": "Enter network name", "enter_password": "Enter password", "estop": "E-stop", @@ -127,6 +137,8 @@ "factory_resets_cannot_be_undone": "Factory resets cannot be undone.", "failed_to_connect_to_ssid": "Failed to connect to {{ssid}}", "feature_flags": "Feature Flags", + "field_is_required": "{{field}} is required", + "find_and_join_network": "Find and join a Wi-Fi network", "finish_setup": "Finish setup", "firmware_version": "Firmware Version", "fully_calibrate_before_checking_health": "Fully calibrate your robot before checking calibration health", @@ -154,6 +166,7 @@ "last_calibrated_label": "Last Calibrated", "launch_jupyter_notebook": "Launch Jupyter Notebook", "legacy_settings": "Legacy Settings", + "likely_incorrect_password": "Likely incorrect network password.", "mac_address": "MAC Address", "manage_oem_settings": "Manage OEM settings", "minutes": "{{minute}} minutes", @@ -171,7 +184,10 @@ "name_your_robot": "Name your robot", "name_your_robot_description": "Don’t worry, you can always change this in your settings.", "need_another_security_type": "Need another security type?", + "network_is_unsecured": "Wi-Fi network {{ssid}} is unsecured", "network_name": "Network Name", + "network_requires_auth": "Wi-Fi network {{ssid}} requires 802.1X authentication", + "network_requires_wpa_password": "Wi-Fi network {{ssid}} requires a WPA2 password", "network_settings": "Network Settings", "networking": "Networking", "never": "Never", @@ -183,6 +199,7 @@ "no_modules_attached": "No modules attached", "no_network_found": "No network found", "no_pipette_attached": "No pipette attached", + "no_update_files": "Unable to retrieve update for this robot. Ensure your computer is connected to the internet and try again later.", "none_description": "Not recommended", "not_calibrated": "Not calibrated yet", "not_calibrated_short": "Not calibrated", @@ -197,8 +214,10 @@ "on": "On", "one_hour": "1 hour", "other_networks": "Other Networks", + "other_robot_updating": "Unable to update because the app is currently updating a different robot.", "password": "Password", "password_error_message": "Must be at least 8 characters", + "password_not_long_enough": "Password must be at least {{minLength}} characters", "pause_protocol": "Pause protocol when robot door opens", "pause_protocol_description": "When enabled, opening the robot door during a run will pause the robot after it has completed its current motion.", "pipette_calibrations_description": "Pipette calibration uses a metal probe to determine the pipette's exact position relative to precision-cut squares on deck slots.", @@ -208,6 +227,7 @@ "pipette_offset_calibration_recommended": "Pipette Offset calibration recommended", "pipette_offset_calibrations_history": "See all Pipette Offset Calibration history", "pipette_offset_calibrations_title": "Pipette Offset Calibrations", + "please_check_credentials": "Please double-check your network credentials", "privacy": "Privacy", "problem_during_update": "This update is taking longer than usual.", "proceed_without_updating": "Proceed without update", @@ -238,9 +258,12 @@ "returns_your_device_to_new_state": "This returns your device to a new state.", "robot_busy_protocol": "This robot cannot be updated while a protocol is running on it", "robot_calibration_data": "Robot Calibration Data", + "robot_has_bad_capabilities": "Robot has incorrect capabilities shape", "robot_initializing": "Initializing robot...", "robot_name": "Robot Name", "robot_operating_update_available": "Robot Operating System Update Available", + "robot_reconnected_with version": "Robot reconnected with version", + "robot_requires_premigration": "This robot must be updated by the system before a custom update can occur", "robot_serial_number": "Robot Serial Number", "robot_server_version": "Robot Server Version", "robot_settings": "Robot Settings", @@ -259,7 +282,9 @@ "select_a_network": "Select a network", "select_a_security_type": "Select a security type", "select_all_settings": "Select all settings", + "select_auth_method_short": "Select authentication method", "select_authentication_method": "Select authentication method for your selected network.", + "select_file": "Select file", "sending_software": "Sending software...", "serial": "Serial", "setup_mode": "Setup mode", @@ -275,6 +300,9 @@ "subnet_mask": "Subnet Mask", "successfully_connected": "Successfully connected!", "successfully_connected_to_network": "Successfully connected to {{ssid}}!", + "successfully_connected_to_ssid": "Your robot has successfully connected to Wi-Fi network {{ssid}}", + "successfully_connected_to_wifi": "Successfully connected to Wi-Fi", + "successfully_disconnected_from_wifi": "Successfully disconnected from Wi-Fi", "supported_protocol_api_versions": "Supported Protocol API Versions", "text_size": "Text Size", "text_size_description": "Text on all screens will adjust to the size you choose below.", @@ -286,6 +314,14 @@ "troubleshooting": "Troubleshooting", "try_again": "Try again", "try_restarting_the_update": "Try restarting the update.", + "unable_to_cancel_update": "Unable to cancel in-progress update session", + "unable_to_commit_update": "Unable to commit update", + "unable_to_connect": "Unable to connect to Wi-Fi", + "unable_to_disconnect": "Unable to disconnect from Wi-Fi", + "unable_to_find_system_file": "Unable to find system file for update", + "unable_to_find_robot_with_name": "Unable to find online robot with name", + "unable_to_restart": "Unable to restart robot", + "unable_to_start_update_session": "Unable to start update session", "up_to_date": "up to date", "update_available": "Update Available", "update_channel_description": "Stable receives the latest stable releases. Beta allows you to try out new in-progress features before they launch in Stable channel, but they have not completed testing yet.", @@ -294,7 +330,10 @@ "update_requires_restarting_robot": "Updating the robot software requires restarting the robot", "update_robot_now": "Update robot now", "update_robot_software": "Update robot software manually with a local file (.zip)", + "update_server_unavailable": "Unable to update because your robot's update server is not responding.", + "update_unavailable": "Update unavailable", "updating": "Updating", + "upgrade": "upgrade", "upload_custom_logo": "Upload custom logo", "upload_custom_logo_description": "Upload a logo for the robot to display during boot up.", "upload_custom_logo_dimensions": "The logo must fit within dimensions 1024 x 600 and be a PNG file (.png).", diff --git a/app/src/assets/localization/en/gripper_wizard_flows.json b/app/src/assets/localization/en/gripper_wizard_flows.json index ff98d8e07f0..70df5688820 100644 --- a/app/src/assets/localization/en/gripper_wizard_flows.json +++ b/app/src/assets/localization/en/gripper_wizard_flows.json @@ -5,7 +5,6 @@ "before_you_begin": "Before you begin", "begin_calibration": "Begin calibration", "calibrate_gripper": "Calibrate Gripper", - "calibration_pin": "Calibration Pin", "calibration_pin_touching": "The calibration pin will touch the calibration square in slot {{slot}} to determine its exact position.", "complete_calibration": "Complete calibration", "continue": "Continue", @@ -17,7 +16,6 @@ "gripper_calibration": "Gripper Calibration", "gripper_recalibration": "Gripper Recalibration", "gripper_successfully_attached": "Gripper successfully attached", - "hex_screwdriver": "2.5 mm Hex Screwdriver", "hold_gripper_and_loosen_screws": "Hold the gripper in place and loosen the top gripper screw first. After that move onto the bottom screw. (The screws are captive and will not come apart from the gripper.) Then carefully remove the gripper.", "insert_pin_into_front_jaw": "Insert calibration pin in front jaw", "insert_pin_into_rear_jaw": "Insert calibration pin in rear jaw", diff --git a/app/src/assets/localization/en/pipette_wizard_flows.json b/app/src/assets/localization/en/pipette_wizard_flows.json index 78dc2b852a6..1154d6f9659 100644 --- a/app/src/assets/localization/en/pipette_wizard_flows.json +++ b/app/src/assets/localization/en/pipette_wizard_flows.json @@ -67,6 +67,7 @@ "pipette_heavy": "The 96-Channel Pipette is heavy ({{weight}}). Ask a labmate for help, if needed.", "please_install_correct_pip": "Install {{pipetteName}} instead", "progress_will_be_lost": "{{flow}} progress will be lost", + "provided_with_robot": "Provided with the robot. Using another size can strip the instruments’s screws.", "reattach_carriage": "reattach z-axis carriage", "recalibrate_pipette": "recalibrate {{mount}} pipette", "remove_cal_probe": "remove calibration probe", diff --git a/app/src/assets/localization/en/protocol_command_text.json b/app/src/assets/localization/en/protocol_command_text.json index 2842f9dc30d..8037b8f2778 100644 --- a/app/src/assets/localization/en/protocol_command_text.json +++ b/app/src/assets/localization/en/protocol_command_text.json @@ -6,11 +6,13 @@ "adapter_in_mod_in_slot": "{{adapter}} on {{module}} in Slot {{slot}}", "adapter_in_slot": "{{adapter}} in Slot {{slot}}", "air_gap_in_place": "Air gapping {{volume}} µL", + "all_nozzles": "all nozzles", "aspirate": "Aspirating {{volume}} µL from well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", "aspirate_in_place": "Aspirating {{volume}} µL in place at {{flow_rate}} µL/sec ", "blowout": "Blowing out at well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", "blowout_in_place": "Blowing out in place at {{flow_rate}} µL/sec", "closing_tc_lid": "Closing Thermocycler lid", + "column_layout": "column layout", "comment": "Comment", "configure_for_volume": "Configure {{pipette}} to aspirate {{volume}} µL", "configure_nozzle_layout": "Configure {{pipette}} to use {{layout}}", @@ -59,11 +61,13 @@ "opening_tc_lid": "Opening Thermocycler lid", "pause": "Pause", "pause_on": "Pause on {{robot_name}}", + "partial_layout": "partial layout", "pickup_tip": "Picking up tip(s) from {{well_range}} of {{labware}} in {{labware_location}}", "prepare_to_aspirate": "Preparing {{pipette}} to aspirate", "reloading_labware": "Reloading {{labware}}", "return_tip": "Returning tip to {{well_name}} of {{labware}} in {{labware_location}}", "right": "Right", + "row_layout": "row layout", "save_position": "Saving position", "set_and_await_hs_shake": "Setting Heater-Shaker to shake at {{rpm}} rpm and waiting until reached", "setting_hs_temp": "Setting Target Temperature of Heater-Shaker to {{temp}}", @@ -71,6 +75,7 @@ "setting_thermocycler_block_temp": "Setting Thermocycler block temperature to {{temp}} with hold time of {{hold_time_seconds}} seconds after target reached", "setting_thermocycler_lid_temp": "Setting Thermocycler lid temperature to {{temp}}", "single": "single", + "single_nozzle_layout": "single nozzle layout", "slot": "Slot {{slot_name}}", "target_temperature": "target temperature", "tc_awaiting_for_duration": "Waiting for Thermocycler profile to complete", diff --git a/app/src/assets/localization/en/top_navigation.json b/app/src/assets/localization/en/top_navigation.json index 178b02042b9..16d5e2d011d 100644 --- a/app/src/assets/localization/en/top_navigation.json +++ b/app/src/assets/localization/en/top_navigation.json @@ -1,7 +1,10 @@ { + "app_settings": "App Settings", "attached_pipettes_do_not_match": "Attached pipettes do not match pipettes specified in loaded protocol", "calibrate_deck_to_proceed": "Calibrate your deck to proceed", + "calibration_dashboard": "Calibration Dashboard", "deck_setup": "Deck Setup", + "device": "Device", "devices": "Devices", "instruments": "Instruments", "labware": "Labware", @@ -10,10 +13,13 @@ "pipettes": "pipettes", "please_connect_to_a_robot": "Please connect to a robot to proceed", "please_load_a_protocol": "Please load a protocol to proceed", + "protocol_details": "Protocol Details", "protocol_runs": "Protocol Runs", + "protocol_timeline": "Protocol Timeline", "protocols": "Protocols", "quick_transfer": "Quick Transfer", "robot_settings": "Robot Settings", "run": "run", + "run_details": "Run Details", "settings": "Settings" } diff --git a/app/src/local-resources/commands/hooks/useCommandTextString/utils/commandText/getConfigureNozzleLayoutCommandText.ts b/app/src/local-resources/commands/hooks/useCommandTextString/utils/commandText/getConfigureNozzleLayoutCommandText.ts index 8c9e12f3d5b..f6440d69e1d 100644 --- a/app/src/local-resources/commands/hooks/useCommandTextString/utils/commandText/getConfigureNozzleLayoutCommandText.ts +++ b/app/src/local-resources/commands/hooks/useCommandTextString/utils/commandText/getConfigureNozzleLayoutCommandText.ts @@ -13,13 +13,12 @@ export function getConfigureNozzleLayoutCommandText({ pip => pip.id === pipetteId )?.pipetteName - // TODO(cb, 2024-09-10): confirm these strings for copy consistency and add them to i18n const ConfigAmount = { - SINGLE: 'single nozzle layout', - COLUMN: 'column layout', - ROW: 'row layout', - QUADRANT: 'partial layout', - ALL: 'all nozzles', + SINGLE: t('single_nozzle_layout'), + COLUMN: t('column_layout'), + ROW: t('row_layout'), + QUADRANT: t('partial_layout'), + ALL: t('all_nozzles'), } return t('configure_nozzle_layout', { diff --git a/app/src/organisms/Desktop/Alerts/U2EDriverOutdatedAlert.tsx b/app/src/organisms/Desktop/Alerts/U2EDriverOutdatedAlert.tsx index fbb79a6b935..a327fce6a31 100644 --- a/app/src/organisms/Desktop/Alerts/U2EDriverOutdatedAlert.tsx +++ b/app/src/organisms/Desktop/Alerts/U2EDriverOutdatedAlert.tsx @@ -1,5 +1,6 @@ import { Link as InternalLink } from 'react-router-dom' import styled from 'styled-components' +import { useTranslation } from 'react-i18next' import { AlertModal, @@ -12,20 +13,9 @@ import { ANALYTICS_U2E_DRIVE_ALERT_DISMISSED, ANALYTICS_U2E_DRIVE_LINK_CLICKED, } from '/app/redux/analytics' -import { - U2E_DRIVER_UPDATE_URL, - U2E_DRIVER_OUTDATED_MESSAGE, - U2E_DRIVER_DESCRIPTION, - U2E_DRIVER_OUTDATED_CTA, -} from '/app/redux/system-info' +import { U2E_DRIVER_UPDATE_URL } from '/app/redux/system-info' import type { AlertProps } from './types' -// TODO(mc, 2020-05-07): i18n -const DRIVER_OUT_OF_DATE = 'Realtek USB-to-Ethernet Driver Update Available' -const VIEW_ADAPTER_INFO = 'view adapter info' -const GET_UPDATE = 'get update' -const DONT_REMIND_ME_AGAIN = "Don't remind me again" - const ADAPTER_INFO_URL = '/more/network-and-system' const LinkButton = styled(Link)` @@ -42,19 +32,20 @@ const IgnoreCheckbox = styled(DeprecatedCheckboxField)` export function U2EDriverOutdatedAlert(props: AlertProps): JSX.Element { const trackEvent = useTrackEvent() + const { t } = useTranslation(['app_settings', 'branded']) const [rememberDismiss, toggleRememberDismiss] = useToggle() const { dismissAlert } = props return ( { dismissAlert(rememberDismiss) trackEvent({ @@ -67,7 +58,7 @@ export function U2EDriverOutdatedAlert(props: AlertProps): JSX.Element { Component: LinkButton, href: U2E_DRIVER_UPDATE_URL, external: true, - children: GET_UPDATE, + children: t('get_update'), onClick: () => { dismissAlert(rememberDismiss) trackEvent({ @@ -79,11 +70,11 @@ export function U2EDriverOutdatedAlert(props: AlertProps): JSX.Element { ]} >

- {U2E_DRIVER_OUTDATED_MESSAGE} {U2E_DRIVER_DESCRIPTION} + {t('u2e_driver_outdated_message')} {t('branded:u2e_driver_description')}

-

{U2E_DRIVER_OUTDATED_CTA}

+

{t('please_update_driver')}

diff --git a/app/src/organisms/Desktop/Devices/ConfigurePipette/ConfigMessage.tsx b/app/src/organisms/Desktop/Devices/ConfigurePipette/ConfigMessage.tsx deleted file mode 100644 index d6a32fa6d4b..00000000000 --- a/app/src/organisms/Desktop/Devices/ConfigurePipette/ConfigMessage.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import styles from './styles.module.css' - -// TODO (ka 2019-2-12): Add intercom onClick to assistance text -export function ConfigMessage(): JSX.Element { - return ( -
-

Warning:

-

- These are advanced settings. Please do not attempt to adjust without - assistance from an Opentrons support team member, as doing - so may affect the lifespan of your pipette. -

-

- Note that these settings will not override any pipette settings - pre-defined in protocols. -

-
- ) -} diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx index 55c64ee648a..01917e5b483 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx @@ -112,7 +112,7 @@ export function UpdateRobotSoftware({ {updateFromFileDisabledReason != null && ( - {updateFromFileDisabledReason} + {t(updateFromFileDisabledReason)} )}
diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/FormModal.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/FormModal.tsx index 60ce3d2a88e..73f6004eb73 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/FormModal.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/FormModal.tsx @@ -1,17 +1,17 @@ import { Controller } from 'react-hook-form' import styled, { css } from 'styled-components' - +import { useTranslation } from 'react-i18next' import { FONT_SIZE_BODY_1, BUTTON_TYPE_SUBMIT, Flex, } from '@opentrons/components' +import { SECURITY_WPA_PSK, SECURITY_WPA_EAP } from '/app/redux/networking' import { ScrollableAlertModal } from '/app/molecules/modals' import { TextField } from './TextField' import { KeyFileField } from './KeyFileField' import { SecurityField } from './SecurityField' import { FIELD_TYPE_KEY_FILE, FIELD_TYPE_SECURITY } from '../constants' -import * as Copy from '../i18n' import type { Control } from 'react-hook-form' import type { ConnectFormField, ConnectFormValues, WifiNetwork } from '../types' @@ -53,16 +53,23 @@ export interface FormModalProps { export const FormModal = (props: FormModalProps): JSX.Element => { const { id, network, fields, isValid, onCancel, control } = props + const { t } = useTranslation(['device_settings', 'shared']) const heading = network !== null - ? Copy.CONNECT_TO_SSID(network.ssid) - : Copy.FIND_AND_JOIN_A_NETWORK + ? t('connect_to_ssid', { ssid: network.ssid }) + : t('find_and_join_network') - const body = - network !== null - ? Copy.NETWORK_REQUIRES_SECURITY(network) - : Copy.ENTER_NAME_AND_SECURITY_TYPE + let bodyText = t('enter_name_security_type') + if (network != null) { + if (network.securityType === SECURITY_WPA_PSK) { + bodyText = t('network_requires_wpa_password', { ssid: network.ssid }) + } else if (network.securityType === SECURITY_WPA_EAP) { + bodyText = t('network_requires_auth', { ssid: network.ssid }) + } else { + bodyText = t('network_is_unsecured', { ssid: network.ssid }) + } + } return ( { iconName="wifi" onCloseClick={onCancel} buttons={[ - { children: Copy.CANCEL, onClick: props.onCancel }, + { children: t('shared:cancel'), onClick: props.onCancel }, { - children: Copy.CONNECT, + children: t('connect'), type: BUTTON_TYPE_SUBMIT, form: id, disabled: !isValid, }, ]} > - {body} + {bodyText} {fields.map(fieldProps => { const { name } = fieldProps diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/KeyFileField.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/KeyFileField.tsx index 376048ba420..b7ea68d5e36 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/KeyFileField.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/KeyFileField.tsx @@ -1,9 +1,9 @@ import { useRef } from 'react' +import { useTranslation } from 'react-i18next' import { SelectField } from '@opentrons/components' import { FormRow } from './FormRow' import { UploadKeyInput } from './UploadKeyInput' -import { LABEL_ADD_NEW_KEY } from '../i18n' import { useConnectFormField } from './form-state' import type { WifiKey } from '../types' @@ -27,10 +27,6 @@ export interface KeyFileFieldProps { const ADD_NEW_KEY_VALUE = '__addNewKey__' -const ADD_NEW_KEY_OPTION_GROUP = { - options: [{ value: ADD_NEW_KEY_VALUE, label: LABEL_ADD_NEW_KEY }], -} - const makeKeyOptions = ( keys: WifiKey[] ): { options: Array<{ value: string; label: string }> } => ({ @@ -48,6 +44,11 @@ export const KeyFileField = (props: KeyFileFieldProps): JSX.Element => { field, fieldState, } = props + const { t } = useTranslation('device_settings') + const ADD_NEW_KEY_OPTION_GROUP = { + options: [{ value: ADD_NEW_KEY_VALUE, label: t('add_new') }], + } + const { value, error, setValue, setTouched } = useConnectFormField( field, fieldState @@ -81,7 +82,7 @@ export const KeyFileField = (props: KeyFileFieldProps): JSX.Element => { diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/SecurityField.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/SecurityField.tsx index c9fa4e0c069..cb7c2cbf615 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/SecurityField.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/SecurityField.tsx @@ -1,7 +1,7 @@ +import { useTranslation } from 'react-i18next' import { SelectField } from '@opentrons/components' import { SECURITY_NONE, SECURITY_WPA_PSK } from '../constants' -import { LABEL_SECURITY_NONE, LABEL_SECURITY_PSK } from '../i18n' import { useConnectFormField } from './form-state' import { FormRow } from './FormRow' @@ -25,8 +25,8 @@ export interface SecurityFieldProps { } const ALL_SECURITY_OPTIONS = [ - { options: [{ value: SECURITY_NONE, label: LABEL_SECURITY_NONE }] }, - { options: [{ value: SECURITY_WPA_PSK, label: LABEL_SECURITY_PSK }] }, + { options: [{ value: SECURITY_NONE, label: 'shared:none' }] }, + { options: [{ value: SECURITY_WPA_PSK, label: 'wpa2_personal' }] }, ] const makeEapOptionsGroup = ( @@ -39,6 +39,7 @@ const makeEapOptionsGroup = ( }) export const SecurityField = (props: SecurityFieldProps): JSX.Element => { + const { t } = useTranslation(['device_settings', 'shared']) const { id, name, @@ -62,7 +63,7 @@ export const SecurityField = (props: SecurityFieldProps): JSX.Element => { ] return ( - + { + const { t } = useTranslation('device_settings') const { id, name, label, isPassword, className, field, fieldState } = props const { value, error, onChange, onBlur } = useConnectFormField( field, @@ -42,7 +43,7 @@ export const TextField = (props: TextFieldProps): JSX.Element => { /> {isPassword && ( diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts deleted file mode 100644 index 80336fb0139..00000000000 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts +++ /dev/null @@ -1,379 +0,0 @@ -import * as Fixtures from '/app/redux/networking/__fixtures__' -import { describe, it, expect } from 'vitest' - -import { - CONFIGURE_FIELD_SSID, - CONFIGURE_FIELD_PSK, - CONFIGURE_FIELD_SECURITY_TYPE, - SECURITY_WPA_EAP, - SECURITY_WPA_PSK, - SECURITY_NONE, -} from '/app/redux/networking' - -import { - FIELD_TYPE_TEXT, - FIELD_TYPE_KEY_FILE, - FIELD_TYPE_SECURITY, -} from '../../constants' - -import { - LABEL_SECURITY, - LABEL_SSID, - LABEL_PSK, - SELECT_AUTHENTICATION_METHOD, - SELECT_FILE, -} from '../../i18n' - -import { - getConnectFormFields, - validateConnectFormFields, - connectFormToConfigureRequest, -} from '../form-fields' - -describe('getConnectFormFields', () => { - it('should add a string field for SSID if network is unknown', () => { - const fields = getConnectFormFields(null, 'robot-name', [], [], {}) - - expect(fields).toContainEqual({ - type: FIELD_TYPE_TEXT, - name: CONFIGURE_FIELD_SSID, - label: `* ${LABEL_SSID}`, - isPassword: false, - }) - }) - - it('should add a security dropdown field if network is unknown', () => { - const eapOptions = [Fixtures.mockEapOption] - const fields = getConnectFormFields(null, 'robot-name', eapOptions, [], {}) - - expect(fields).toContainEqual({ - type: FIELD_TYPE_SECURITY, - name: CONFIGURE_FIELD_SECURITY_TYPE, - label: `* ${LABEL_SECURITY}`, - eapOptions, - showAllOptions: true, - placeholder: SELECT_AUTHENTICATION_METHOD, - }) - }) - - it('should add a security dropdown field if known network has EAP security', () => { - const eapOptions = [Fixtures.mockEapOption] - const network = { - ...Fixtures.mockWifiNetwork, - securityType: SECURITY_WPA_EAP, - } - const fields = getConnectFormFields( - network, - 'robot-name', - eapOptions, - [], - {} - ) - - expect(fields).toContainEqual({ - type: FIELD_TYPE_SECURITY, - name: CONFIGURE_FIELD_SECURITY_TYPE, - label: `* ${LABEL_SECURITY}`, - eapOptions, - showAllOptions: false, - placeholder: SELECT_AUTHENTICATION_METHOD, - }) - }) - - it('should add a password field for PSK if known network as PSK security', () => { - const network = { - ...Fixtures.mockWifiNetwork, - securityType: SECURITY_WPA_PSK, - } - const fields = getConnectFormFields(network, 'robot-name', [], [], {}) - - expect(fields).toContainEqual({ - type: FIELD_TYPE_TEXT, - name: CONFIGURE_FIELD_PSK, - label: `* ${LABEL_PSK}`, - isPassword: true, - }) - }) - - it('should add a password field for PSK if unknown network and user selects PSK', () => { - const fields = getConnectFormFields(null, 'robot-name', [], [], { - securityType: SECURITY_WPA_PSK, - }) - - expect(fields).toContainEqual({ - type: FIELD_TYPE_TEXT, - name: CONFIGURE_FIELD_PSK, - label: `* ${LABEL_PSK}`, - isPassword: true, - }) - }) - - it('should add EAP options based on the selected eapType if network is unknown', () => { - const eapOptions = [ - { ...Fixtures.mockEapOption, name: 'someEapType', options: [] }, - { ...Fixtures.mockEapOption, name: 'someOtherEapType' }, - ] - const wifiKeys = [Fixtures.mockWifiKey] - const fields = getConnectFormFields( - null, - 'robot-name', - eapOptions, - wifiKeys, - { - securityType: 'someOtherEapType', - } - ) - - expect(fields).toEqual( - expect.arrayContaining([ - { - type: FIELD_TYPE_TEXT, - name: 'eapConfig.stringField', - label: '* String Field', - isPassword: false, - }, - { - type: FIELD_TYPE_TEXT, - name: 'eapConfig.passwordField', - label: 'Password Field', - isPassword: true, - }, - { - type: FIELD_TYPE_KEY_FILE, - name: 'eapConfig.fileField', - label: '* File Field', - robotName: 'robot-name', - wifiKeys, - placeholder: SELECT_FILE, - }, - ]) - ) - }) - - it('should add EAP options based on the selected eapType if network is EAP', () => { - const network = { - ...Fixtures.mockWifiNetwork, - securityType: SECURITY_WPA_EAP, - } - const eapOptions = [ - { ...Fixtures.mockEapOption, name: 'someEapType' }, - { ...Fixtures.mockEapOption, name: 'someOtherEapType', options: [] }, - ] - const wifiKeys = [Fixtures.mockWifiKey] - const fields = getConnectFormFields( - network, - 'robot-name', - eapOptions, - wifiKeys, - { securityType: 'someEapType' } - ) - - expect(fields).toEqual( - expect.arrayContaining([ - { - type: FIELD_TYPE_TEXT, - name: 'eapConfig.stringField', - label: '* String Field', - isPassword: false, - }, - { - type: FIELD_TYPE_TEXT, - name: 'eapConfig.passwordField', - label: 'Password Field', - isPassword: true, - }, - { - type: FIELD_TYPE_KEY_FILE, - name: 'eapConfig.fileField', - label: '* File Field', - robotName: 'robot-name', - wifiKeys, - placeholder: SELECT_FILE, - }, - ]) - ) - }) -}) - -describe('validateConnectFormFields', () => { - it('should error if network is hidden and ssid is blank', () => { - const errors = validateConnectFormFields( - null, - [], - { - securityType: SECURITY_WPA_PSK, - psk: '12345678', - }, - {} - ) - - expect(errors).toEqual({ - ssid: { message: `${LABEL_SSID} is required`, type: 'ssidError' }, - }) - }) - - it('should error if network is hidden and securityType is blank', () => { - const errors = validateConnectFormFields(null, [], { ssid: 'foobar' }, {}) - - expect(errors).toEqual({ - securityType: { - message: `${LABEL_SECURITY} is required`, - type: 'securityTypeError', - }, - }) - }) - - it('should error if network is PSK and psk is blank', () => { - const network = { - ...Fixtures.mockWifiNetwork, - securityType: SECURITY_WPA_PSK, - } - const errors = validateConnectFormFields(network, [], { psk: '' }, {}) - - expect(errors).toEqual({ - psk: { - message: `${LABEL_PSK} must be at least 8 characters`, - type: 'pskError', - }, - }) - }) - - it('should error if selected security is PSK and psk is blank', () => { - const values = { ssid: 'foobar', securityType: SECURITY_WPA_PSK } - const errors = validateConnectFormFields(null, [], values, {}) - - expect(errors).toEqual({ - psk: { - message: `${LABEL_PSK} must be at least 8 characters`, - type: 'pskError', - }, - }) - }) - - it('should error if network is EAP and securityType is blank', () => { - const network = { - ...Fixtures.mockWifiNetwork, - securityType: SECURITY_WPA_EAP, - } - const errors = validateConnectFormFields(network, [], {}, {}) - - expect(errors).toEqual({ - securityType: { - message: `${LABEL_SECURITY} is required`, - type: 'securityTypeError', - }, - }) - }) - - it('should error if any required EAP fields are missing', () => { - const network = { - ...Fixtures.mockWifiNetwork, - securityType: SECURITY_WPA_EAP, - } - const eapOptions = [ - { ...Fixtures.mockEapOption, name: 'someEapType', options: [] }, - { ...Fixtures.mockEapOption, name: 'someOtherEapType' }, - ] - const values = { - securityType: 'someOtherEapType', - eapConfig: { fileField: '123' }, - } - const errors = validateConnectFormFields(network, eapOptions, values, {}) - - expect(errors).toEqual({ - 'eapConfig.stringField': { - message: `String Field is required`, - type: 'eapError', - }, - }) - }) -}) - -describe('connectFormToConfigureRequest', () => { - it('should return null if unknown network and no ssid', () => { - const values = { securityType: SECURITY_NONE } - const result = connectFormToConfigureRequest(null, values) - - expect(result).toEqual(null) - }) - - it('should set ssid and securityType from values if unknown network', () => { - const values = { ssid: 'foobar', securityType: SECURITY_NONE } - const result = connectFormToConfigureRequest(null, values) - - expect(result).toEqual({ - ssid: 'foobar', - securityType: SECURITY_NONE, - hidden: true, - }) - }) - - it('should set ssid from network if known', () => { - const network = { - ...Fixtures.mockWifiNetwork, - ssid: 'foobar', - securityType: SECURITY_NONE, - } - const values = {} - const result = connectFormToConfigureRequest(network, values) - - expect(result).toEqual({ - ssid: 'foobar', - securityType: SECURITY_NONE, - hidden: false, - }) - }) - - it('should set psk from values', () => { - const network = { - ...Fixtures.mockWifiNetwork, - ssid: 'foobar', - securityType: SECURITY_WPA_PSK, - } - const values = { psk: '12345678' } - const result = connectFormToConfigureRequest(network, values) - - expect(result).toEqual({ - ssid: 'foobar', - securityType: SECURITY_WPA_PSK, - hidden: false, - psk: '12345678', - }) - }) - - it('should set eapConfig from values with known network', () => { - const network = { - ...Fixtures.mockWifiNetwork, - ssid: 'foobar', - securityType: SECURITY_WPA_EAP, - } - const values = { - securityType: 'someEapType', - eapConfig: { option1: 'fizzbuzz' }, - } - const result = connectFormToConfigureRequest(network, values) - - expect(result).toEqual({ - ssid: 'foobar', - securityType: SECURITY_WPA_EAP, - hidden: false, - eapConfig: { eapType: 'someEapType', option1: 'fizzbuzz' }, - }) - }) - - it('should set eapConfig from values with unknown network', () => { - const values = { - ssid: 'foobar', - securityType: 'someEapType', - eapConfig: { option1: 'fizzbuzz' }, - } - const result = connectFormToConfigureRequest(null, values) - - expect(result).toEqual({ - ssid: 'foobar', - securityType: SECURITY_WPA_EAP, - hidden: true, - eapConfig: { eapType: 'someEapType', option1: 'fizzbuzz' }, - }) - }) -}) diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.tsx new file mode 100644 index 00000000000..638d9f1b76c --- /dev/null +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.tsx @@ -0,0 +1,422 @@ +import * as Fixtures from '/app/redux/networking/__fixtures__' +import { describe, it, expect } from 'vitest' +import { screen } from '@testing-library/react' +import { useTranslation } from 'react-i18next' + +import { + SECURITY_WPA_EAP, + SECURITY_WPA_PSK, + SECURITY_NONE, +} from '/app/redux/networking' +import { renderWithProviders } from '/app/__testing-utils__' +import { i18n } from '/app/i18n' + +import { + getConnectFormFields, + validateConnectFormFields, + connectFormToConfigureRequest, +} from '../form-fields' + +import type { FieldError } from 'react-hook-form' +import type { + WifiNetwork, + WifiKey, + EapOption, + ConnectFormValues, +} from '../../types' +import type { ComponentProps } from 'react' + +const TestWrapperConnectFormFields = ({ + network, + robotName, + eapOptions, + wifiKeys, + values, +}: { + network: WifiNetwork | null + robotName: string + eapOptions: EapOption[] + wifiKeys: WifiKey[] + values: ConnectFormValues +}) => { + const { t } = useTranslation('device_settings') + const fields = getConnectFormFields( + network, + robotName, + eapOptions, + wifiKeys, + values, + t + ) + return
{JSON.stringify(fields)}
+} + +const renderConnectFormFields = ( + props: ComponentProps +) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('getConnectFormFields', () => { + it('should add a string field for SSID if network is unknown', () => { + const props = { + network: null, + robotName: 'robot-name', + eapOptions: [], + wifiKeys: [], + values: {}, + } + renderConnectFormFields(props) + screen.getByText(/text/) + screen.getByText(/ssid/) + screen.getByText(/ * Network Name/) + }) + + it('should add a security dropdown field if network is unknown', () => { + const props = { + network: null, + robotName: 'robot-name', + eapOptions: [Fixtures.mockEapOption], + wifiKeys: [], + values: {}, + } + renderConnectFormFields(props) + screen.getByText(/security/) + screen.getByText(/ * Authentication/) + screen.getByText(/Select authentication method/) + }) + + it('should add a security dropdown field if known network has EAP security', () => { + const network = { + ...Fixtures.mockWifiNetwork, + securityType: SECURITY_WPA_EAP, + } + const props = { + network: network, + robotName: 'robot-name', + eapOptions: [Fixtures.mockEapOption], + wifiKeys: [], + values: {}, + } + renderConnectFormFields(props) + + screen.getByText(/security/) + screen.getByText(/ * Authentication/) + screen.getByText(/Select authentication method/) + screen.getByText(/EAP Option/) + screen.getByText(/String Field/) + screen.getByText(/Password Field/) + screen.getByText(/File Field/) + }) + + it('should add a password field for PSK if known network as PSK security', () => { + const network = { + ...Fixtures.mockWifiNetwork, + securityType: SECURITY_WPA_PSK, + } + const props = { + network: network, + robotName: 'robot-name', + eapOptions: [], + wifiKeys: [], + values: {}, + } + renderConnectFormFields(props) + + screen.getByText(/psk/) + screen.getByText(/ * Password/) + }) + + it('should add a password field for PSK if unknown network and user selects PSK', () => { + const props = { + network: null, + robotName: 'robot-name', + eapOptions: [], + wifiKeys: [], + values: { securityType: SECURITY_WPA_PSK }, + } + + renderConnectFormFields(props) + screen.getByText(/psk/) + screen.getByText(/ * Password/) + }) + + it('should add EAP options based on the selected eapType if network is unknown', () => { + const eapOptions = [ + { ...Fixtures.mockEapOption, name: 'someEapType', options: [] }, + { ...Fixtures.mockEapOption, name: 'someOtherEapType' }, + ] + const wifiKeys = [Fixtures.mockWifiKey] + const props = { + network: null, + robotName: 'robot-name', + eapOptions: eapOptions, + wifiKeys: wifiKeys, + values: {}, + } + renderConnectFormFields(props) + + screen.getByText(/someEapType/) + screen.getByText(/someOtherEapType/) + screen.getByText(/stringField/) + screen.getByText(/String Field/) + screen.getByText(/passwordField/) + screen.getByText(/Password Field/) + screen.getByText(/fileField/) + screen.getByText(/File Field/) + }) + + it('should add EAP options based on the selected eapType if network is EAP', () => { + const network = { + ...Fixtures.mockWifiNetwork, + securityType: SECURITY_WPA_EAP, + } + const eapOptions = [ + { ...Fixtures.mockEapOption, name: 'someEapType' }, + { ...Fixtures.mockEapOption, name: 'someOtherEapType', options: [] }, + ] + const wifiKeys = [Fixtures.mockWifiKey] + const props = { + network: network, + robotName: 'robot-name', + eapOptions: eapOptions, + wifiKeys: wifiKeys, + values: { securityType: 'someEapType' }, + } + renderConnectFormFields(props) + screen.getByText(/ * String Field/) + screen.getByText(/Password Field/) + screen.getByText(/ * File Field/) + }) +}) + +const TestWrapperValidateFormFields = ({ + network, + eapOptions, + values, + errors, +}: { + network: WifiNetwork | null + eapOptions: EapOption[] + values: ConnectFormValues + errors: Record +}) => { + const { t } = useTranslation('device_settings') + const validationErrors = validateConnectFormFields( + network, + eapOptions, + values, + errors, + t + ) + return
{JSON.stringify(validationErrors)}
+} + +const renderValidateFormFields = ( + props: ComponentProps +) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('validateConnectFormFields', () => { + it('should error if network is hidden and ssid is blank', () => { + const props = { + network: null, + eapOptions: [], + values: { + securityType: SECURITY_WPA_PSK, + psk: '12345678', + }, + errors: {}, + } + renderValidateFormFields(props) + screen.getByText(/ssid/) + screen.getByText(/ssidError/) + screen.getByText(/Network Name is required/) + }) + + it('should error if network is hidden and securityType is blank', () => { + const props = { + network: null, + eapOptions: [], + values: { + ssid: 'foobar', + }, + errors: {}, + } + renderValidateFormFields(props) + screen.getByText(/securityType/) + screen.getByText(/securityTypeError/) + screen.getByText(/Authentication is required/) + }) + + it('should error if network is PSK and psk is blank', () => { + const network = { + ...Fixtures.mockWifiNetwork, + securityType: SECURITY_WPA_PSK, + } + const props = { + network: network, + eapOptions: [], + values: { + psk: '', + }, + errors: {}, + } + renderValidateFormFields(props) + screen.getByText(/psk/) + screen.getByText(/pskError/) + screen.getByText(/Password must be at least 8 characters/) + }) + + it('should error if selected security is PSK and psk is blank', () => { + const values = { ssid: 'foobar', securityType: SECURITY_WPA_PSK } + const props = { + network: null, + eapOptions: [], + values: values, + errors: {}, + } + renderValidateFormFields(props) + screen.getByText(/psk/) + screen.getByText(/pskError/) + screen.getByText(/Password must be at least 8 characters/) + }) + + it('should error if network is EAP and securityType is blank', () => { + const network = { + ...Fixtures.mockWifiNetwork, + securityType: SECURITY_WPA_EAP, + } + const props = { + network: network, + eapOptions: [], + values: {}, + errors: {}, + } + + renderValidateFormFields(props) + screen.getByText(/securityType/) + screen.getByText(/securityTypeError/) + screen.getByText(/Authentication is required/) + }) + + it('should error if any required EAP fields are missing', () => { + const network = { + ...Fixtures.mockWifiNetwork, + securityType: SECURITY_WPA_EAP, + } + const eapOptions = [ + { ...Fixtures.mockEapOption, name: 'someEapType', options: [] }, + { ...Fixtures.mockEapOption, name: 'someOtherEapType' }, + ] + const values = { + securityType: 'someOtherEapType', + eapConfig: { fileField: '123' }, + } + const props = { + network: network, + eapOptions: eapOptions, + values: values, + errors: {}, + } + + renderValidateFormFields(props) + screen.getByText(/eapConfig.stringField/) + screen.getByText(/eapError/) + screen.getByText(/String Field is required/) + }) +}) + +describe('connectFormToConfigureRequest', () => { + it('should return null if unknown network and no ssid', () => { + const values = { securityType: SECURITY_NONE } + const result = connectFormToConfigureRequest(null, values) + + expect(result).toEqual(null) + }) + + it('should set ssid and securityType from values if unknown network', () => { + const values = { ssid: 'foobar', securityType: SECURITY_NONE } + const result = connectFormToConfigureRequest(null, values) + + expect(result).toEqual({ + ssid: 'foobar', + securityType: SECURITY_NONE, + hidden: true, + }) + }) + + it('should set ssid from network if known', () => { + const network = { + ...Fixtures.mockWifiNetwork, + ssid: 'foobar', + securityType: SECURITY_NONE, + } + const values = {} + const result = connectFormToConfigureRequest(network, values) + + expect(result).toEqual({ + ssid: 'foobar', + securityType: SECURITY_NONE, + hidden: false, + }) + }) + + it('should set psk from values', () => { + const network = { + ...Fixtures.mockWifiNetwork, + ssid: 'foobar', + securityType: SECURITY_WPA_PSK, + } + const values = { psk: '12345678' } + const result = connectFormToConfigureRequest(network, values) + + expect(result).toEqual({ + ssid: 'foobar', + securityType: SECURITY_WPA_PSK, + hidden: false, + psk: '12345678', + }) + }) + + it('should set eapConfig from values with known network', () => { + const network = { + ...Fixtures.mockWifiNetwork, + ssid: 'foobar', + securityType: SECURITY_WPA_EAP, + } + const values = { + securityType: 'someEapType', + eapConfig: { option1: 'fizzbuzz' }, + } + const result = connectFormToConfigureRequest(network, values) + + expect(result).toEqual({ + ssid: 'foobar', + securityType: SECURITY_WPA_EAP, + hidden: false, + eapConfig: { eapType: 'someEapType', option1: 'fizzbuzz' }, + }) + }) + + it('should set eapConfig from values with unknown network', () => { + const values = { + ssid: 'foobar', + securityType: 'someEapType', + eapConfig: { option1: 'fizzbuzz' }, + } + const result = connectFormToConfigureRequest(null, values) + + expect(result).toEqual({ + ssid: 'foobar', + securityType: SECURITY_WPA_EAP, + hidden: true, + eapConfig: { eapType: 'someEapType', option1: 'fizzbuzz' }, + }) + }) +}) diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/form-fields.ts b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/form-fields.ts index 1a91d2ac994..b8caeb3824c 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/form-fields.ts +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/form-fields.ts @@ -1,9 +1,9 @@ import get from 'lodash/get' import * as Constants from '../constants' -import * as Copy from '../i18n' import type { FieldError } from 'react-hook-form' +import type { TFunction } from 'i18next' import type { WifiNetwork, WifiKey, @@ -24,28 +24,29 @@ type Errors = Record export const renderLabel = (label: string, required: boolean): string => `${required ? '* ' : ''}${label}` -const FIELD_SSID: ConnectFormTextField = { +const makeFieldSsid = (t: TFunction): ConnectFormTextField => ({ type: Constants.FIELD_TYPE_TEXT, name: Constants.CONFIGURE_FIELD_SSID, - label: renderLabel(Copy.LABEL_SSID, true), + label: renderLabel(t('network_name'), true), isPassword: false, -} +}) -const FIELD_PSK: ConnectFormTextField = { +const makeFieldPsk = (t: TFunction): ConnectFormTextField => ({ type: Constants.FIELD_TYPE_TEXT, name: Constants.CONFIGURE_FIELD_PSK, - label: renderLabel(Copy.LABEL_PSK, true), + label: renderLabel(t('password'), true), isPassword: true, -} +}) const makeSecurityField = ( eapOptions: EapOption[], - showAllOptions: boolean + showAllOptions: boolean, + t: TFunction ): ConnectFormSecurityField => ({ type: Constants.FIELD_TYPE_SECURITY, name: Constants.CONFIGURE_FIELD_SECURITY_TYPE, - label: renderLabel(Copy.LABEL_SECURITY, true), - placeholder: Copy.SELECT_AUTHENTICATION_METHOD, + label: renderLabel(t('authentication'), true), + placeholder: t('select_auth_method_short'), eapOptions, showAllOptions, }) @@ -77,21 +78,22 @@ export function getConnectFormFields( robotName: string, eapOptions: EapOption[], wifiKeys: WifiKey[], - values: ConnectFormValues + values: ConnectFormValues, + t: TFunction ): ConnectFormField[] { const { securityType: formSecurityType } = values const fields = [] // if the network is unknown, display a field to enter the SSID if (network === null) { - fields.push(FIELD_SSID) + fields.push(makeFieldSsid(t)) } // if the network is unknown or the known network is EAP, display a // security dropdown; security dropdown will handle which options to // display based on known or unknown network if (!network || network.securityType === Constants.SECURITY_WPA_EAP) { - fields.push(makeSecurityField(eapOptions, !network)) + fields.push(makeSecurityField(eapOptions, !network, t)) } // if known network is PSK or network is unknown and user has selected PSK @@ -100,7 +102,7 @@ export function getConnectFormFields( network?.securityType === Constants.SECURITY_WPA_PSK || formSecurityType === Constants.SECURITY_WPA_PSK ) { - fields.push(FIELD_PSK) + fields.push(makeFieldPsk(t)) } // if known network is EAP or user selected EAP, map eap options to fields @@ -121,7 +123,7 @@ export function getConnectFormFields( label, robotName, wifiKeys, - placeholder: Copy.SELECT_FILE, + placeholder: t('select_file'), } } @@ -142,7 +144,8 @@ export function validateConnectFormFields( network: WifiNetwork | null, eapOptions: EapOption[], values: ConnectFormValues, - errors: Errors + errors: Errors, + t: TFunction ): Errors { const { ssid: formSsid, @@ -152,7 +155,7 @@ export function validateConnectFormFields( let errorMessage: string | undefined if (network === null && (formSsid == null || formSsid.length === 0)) { - errorMessage = Copy.FIELD_IS_REQUIRED(Copy.LABEL_SSID) + errorMessage = t('field_is_required', { field: t('network_name') }) return errorMessage != null ? { ...errors, @@ -168,7 +171,7 @@ export function validateConnectFormFields( (network === null || network.securityType === Constants.SECURITY_WPA_EAP) && !formSecurityType ) { - errorMessage = Copy.FIELD_IS_REQUIRED(Copy.LABEL_SECURITY) + errorMessage = t('field_is_required', { field: t('authentication') }) return errorMessage != null ? { ...errors, @@ -185,10 +188,9 @@ export function validateConnectFormFields( formSecurityType === Constants.SECURITY_WPA_PSK) && (!formPsk || formPsk.length < Constants.CONFIGURE_PSK_MIN_LENGTH) ) { - errorMessage = Copy.FIELD_NOT_LONG_ENOUGH( - Copy.LABEL_PSK, - Constants.CONFIGURE_PSK_MIN_LENGTH - ) + errorMessage = t('password_not_long_enough', { + minLength: Constants.CONFIGURE_PSK_MIN_LENGTH, + }) return errorMessage != null ? { ...errors, @@ -215,7 +217,9 @@ export function validateConnectFormFields( ) => { const fieldName = getEapFieldName(name) const errorMessage = - displayName != null ? Copy.FIELD_IS_REQUIRED(displayName) : '' + displayName != null + ? t('field_is_required', { field: displayName }) + : '' if (errorMessage != null) { acc[fieldName] = { diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/index.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/index.tsx index 3e1c731d33e..2b5d228c12b 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/index.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/index.tsx @@ -1,4 +1,5 @@ import { useForm } from 'react-hook-form' +import { useTranslation } from 'react-i18next' import { useResetFormOnSecurityChange } from './form-state' import { @@ -10,6 +11,7 @@ import { import { FormModal } from './FormModal' import type { Control, Resolver } from 'react-hook-form' +import type { TFunction } from 'i18next' import type { ConnectFormValues, WifiConfigureRequest, @@ -35,6 +37,7 @@ interface ConnectModalComponentProps extends ConnectModalProps { } export const ConnectModal = (props: ConnectModalProps): JSX.Element => { + const { t } = useTranslation(['device_settings', 'shared']) const { network, eapOptions, onConnect } = props const onSubmit = (values: ConnectFormValues): void => { @@ -45,7 +48,13 @@ export const ConnectModal = (props: ConnectModalProps): JSX.Element => { const handleValidate: Resolver = values => { let errors = {} - errors = validateConnectFormFields(network, eapOptions, values, errors) + errors = validateConnectFormFields( + network, + eapOptions, + values, + errors, + t as TFunction + ) return { values, errors } } @@ -78,6 +87,7 @@ export const ConnectModal = (props: ConnectModalProps): JSX.Element => { export const ConnectModalComponent = ( props: ConnectModalComponentProps ): JSX.Element => { + const { t } = useTranslation(['device_settings', 'shared']) const { robotName, network, @@ -95,7 +105,8 @@ export const ConnectModalComponent = ( robotName, eapOptions, wifiKeys, - values + values, + t as TFunction ) useResetFormOnSecurityChange() diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ResultModal.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ResultModal.tsx index 6628c35dfc5..3a372c6df66 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ResultModal.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ResultModal.tsx @@ -1,6 +1,6 @@ +import { useTranslation } from 'react-i18next' import { AlertModal, SpinnerModal } from '@opentrons/components' -import * as Copy from './i18n' import { ErrorModal } from '/app/molecules/modals' import { DISCONNECT } from './constants' import { PENDING, FAILURE } from '/app/redux/robot-api' @@ -18,29 +18,32 @@ export interface ResultModalProps { export const ResultModal = (props: ResultModalProps): JSX.Element => { const { type, ssid, requestStatus, error, onClose } = props + const { t } = useTranslation(['device_settings', 'shared']) const isDisconnect = type === DISCONNECT if (requestStatus === PENDING) { const message = isDisconnect - ? Copy.DISCONNECTING_FROM_NETWORK(ssid) - : Copy.CONNECTING_TO_NETWORK(ssid) + ? t('disconnecting_from_wifi_network', { ssid: ssid }) + : t('connecting_to_wifi_network', { ssid: ssid }) return } if (error || requestStatus === FAILURE) { const heading = isDisconnect - ? Copy.UNABLE_TO_DISCONNECT - : Copy.UNABLE_TO_CONNECT + ? t('unable_to_disconnect') + : t('unable_to_connect') const message = isDisconnect - ? Copy.YOUR_ROBOT_WAS_UNABLE_TO_DISCONNECT(ssid) - : Copy.YOUR_ROBOT_WAS_UNABLE_TO_CONNECT(ssid) + ? t('disconnect_from_wifi_network_failure', { ssid: ssid }) + : t('connect_to_wifi_network_failure', { ssid: ssid }) - const retryMessage = !isDisconnect ? ` ${Copy.CHECK_YOUR_CREDENTIALS}.` : '' + const retryMessage = !isDisconnect ? t('please_check_credentials') : '' const placeholderError = { - message: `Likely incorrect network password. ${Copy.CHECK_YOUR_CREDENTIALS}.`, + message: `${t('likely_incorrect_password')} ${t( + 'please_check_credentials' + )}.`, } return ( @@ -54,12 +57,12 @@ export const ResultModal = (props: ResultModalProps): JSX.Element => { } const heading = isDisconnect - ? Copy.SUCCESSFULLY_DISCONNECTED - : Copy.SUCCESSFULLY_CONNECTED + ? t('successfully_disconnected') + : t('successfully_connected_to_wifi') const message = isDisconnect - ? Copy.YOUR_ROBOT_HAS_DISCONNECTED(ssid) - : Copy.YOUR_ROBOT_HAS_CONNECTED(ssid) + ? t('disconnect_from_wifi_network_success') + : t('successfully_connected_to_ssid', { ssid: ssid }) return ( { iconName="wifi" heading={heading} onCloseClick={props.onClose} - buttons={[{ children: Copy.CLOSE, onClick: onClose }]} + buttons={[{ children: t('shared:close'), onClick: onClose }]} > {message} diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/SelectSsid/index.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/SelectSsid/index.tsx index b85cc72d563..a8b04feba4b 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/SelectSsid/index.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/SelectSsid/index.tsx @@ -1,9 +1,10 @@ import type * as React from 'react' +import { useTranslation } from 'react-i18next' import { CONTEXT_MENU } from '@opentrons/components' import { SelectField } from '/app/atoms/SelectField' -import * as Copy from '../i18n' import { NetworkOptionLabel, NetworkActionLabel } from './NetworkOptionLabel' +import type { TFunction } from 'i18next' import type { SelectOptionOrGroup } from '@opentrons/components' import type { WifiNetwork } from '../types' @@ -20,11 +21,16 @@ const FIELD_NAME = '__SelectSsid__' const JOIN_OTHER_VALUE = '__join-other-network__' -const SELECT_JOIN_OTHER_GROUP = { - options: [{ value: JOIN_OTHER_VALUE, label: Copy.LABEL_JOIN_OTHER_NETWORK }], -} +const formatOptions = ( + list: WifiNetwork[], + t: TFunction +): SelectOptionOrGroup[] => { + const SELECT_JOIN_OTHER_GROUP = { + options: [ + { value: JOIN_OTHER_VALUE, label: `${t('join_other_network')}...` }, + ], + } -const formatOptions = (list: WifiNetwork[]): SelectOptionOrGroup[] => { const ssidOptionsList = { options: list?.map(({ ssid }) => ({ value: ssid })), } @@ -34,6 +40,7 @@ const formatOptions = (list: WifiNetwork[]): SelectOptionOrGroup[] => { } export function SelectSsid(props: SelectSsidProps): JSX.Element { + const { t } = useTranslation('device_settings') const { list, value, onConnect, onJoinOther, isRobotBusy } = props const handleValueChange = (_: string, value: string): void => { @@ -69,8 +76,8 @@ export function SelectSsid(props: SelectSsidProps): JSX.Element { disabled={isRobotBusy} name={FIELD_NAME} value={value} - options={formatOptions(list)} - placeholder={Copy.SELECT_NETWORK} + options={formatOptions(list, t as TFunction)} + placeholder={t('choose_a_network')} onValueChange={handleValueChange} formatOptionLabel={formatOptionLabel} width="16rem" diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/i18n.ts b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/i18n.ts deleted file mode 100644 index cfee1e77d89..00000000000 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/i18n.ts +++ /dev/null @@ -1,103 +0,0 @@ -// TODO(mc, 2020-03-11): i18n -import { - SECURITY_WPA_PSK, - SECURITY_WPA_EAP, - SECURITY_NONE, -} from '/app/redux/networking' - -import type { WifiNetwork } from './types' - -const SECURITY_DESC = { - [SECURITY_WPA_PSK]: 'requires a WPA2 password', - [SECURITY_WPA_EAP]: 'requires 802.1X authentication', - [SECURITY_NONE]: 'is unsecured', -} - -export const FIND_AND_JOIN_A_NETWORK = 'Find and join a Wi-Fi network' - -export const ENTER_NAME_AND_SECURITY_TYPE = - 'Enter the network name and security type.' - -const WIFI_NETWORK = 'Wi-Fi network' - -export const CANCEL = 'cancel' - -export const CONNECT = 'connect' - -export const CLOSE = 'close' - -export const DISCONNECT = 'disconnect' - -export const LABEL_SSID = 'Network Name (SSID)' - -export const LABEL_PSK = 'Password' - -export const LABEL_SECURITY = 'Authentication' - -export const LABEL_SECURITY_NONE = 'None' - -export const LABEL_SECURITY_PSK = 'WPA2 Personal' - -export const LABEL_ADD_NEW_KEY = 'Add new...' - -export const LABEL_SHOW_PASSWORD = 'Show password' - -export const LABEL_JOIN_OTHER_NETWORK = 'Join other network...' - -export const SELECT_AUTHENTICATION_METHOD = 'Select authentication method' - -export const SELECT_FILE = 'Select file' - -export const SELECT_NETWORK = 'Choose a network...' - -export const SUCCESSFULLY_DISCONNECTED = 'Successfully disconnected from Wi-Fi' - -export const SUCCESSFULLY_CONNECTED = 'Successfully connected to Wi-Fi' - -export const UNABLE_TO_DISCONNECT = 'Unable to disconnect from Wi-Fi' - -export const UNABLE_TO_CONNECT = 'Unable to connect to Wi-Fi' - -export const CHECK_YOUR_CREDENTIALS = - 'Please double-check your network credentials' - -export const CONNECT_TO_SSID = (ssid: string): string => `Connect to ${ssid}` - -export const DISCONNECT_FROM_SSID = (ssid: string): string => - `Disconnect from ${ssid}` - -export const ARE_YOU_SURE_YOU_WANT_TO_DISCONNECT = (ssid: string): string => - `Are you sure you want to disconnect from ${ssid}?` - -export const NETWORK_REQUIRES_SECURITY = (network: WifiNetwork): string => - `${WIFI_NETWORK} ${network.ssid} ${SECURITY_DESC[network.securityType]}` - -export const FIELD_IS_REQUIRED = (name: string): string => `${name} is required` - -export const FIELD_NOT_LONG_ENOUGH = ( - name: string, - minLength: number -): string => `${name} must be at least ${minLength} characters` - -const renderMaybeSsid = (ssid: string | null): string => - ssid !== null ? ` network ${ssid}` : '' - -export const CONNECTING_TO_NETWORK = (ssid: string | null): string => - `Connecting to Wi-Fi${renderMaybeSsid(ssid)}` - -export const DISCONNECTING_FROM_NETWORK = (ssid: string | null): string => - `Disconnecting from Wi-Fi${renderMaybeSsid(ssid)}` - -export const YOUR_ROBOT_WAS_UNABLE_TO_CONNECT = (ssid: string | null): string => - `Your robot was unable to connect to Wi-Fi${renderMaybeSsid(ssid)}` - -export const YOUR_ROBOT_WAS_UNABLE_TO_DISCONNECT = ( - ssid: string | null -): string => - `Your robot was unable to disconnect from Wi-Fi${renderMaybeSsid(ssid)}` - -export const YOUR_ROBOT_HAS_DISCONNECTED = (ssid: string | null): string => - `Your robot has successfully disconnected from Wi-Fi${renderMaybeSsid(ssid)}` - -export const YOUR_ROBOT_HAS_CONNECTED = (ssid: string | null): string => - `Your robot has successfully connected to Wi-Fi${renderMaybeSsid(ssid)}` diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx index 4b2225fe868..da77dee89c9 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx @@ -88,7 +88,7 @@ export function UpdateRobotModal({ let disabledReason: string = '' if (updateFromFileDisabledReason) - disabledReason = updateFromFileDisabledReason + disabledReason = t(updateFromFileDisabledReason) else if (isRobotBusy) disabledReason = t('robot_busy_protocol') useEffect(() => { diff --git a/app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx b/app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx index 89395aeee10..316a3a5526a 100644 --- a/app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx +++ b/app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx @@ -13,6 +13,8 @@ import { SCREWDRIVER_LOADNAME, GRIPPER_LOADNAME, CAL_PIN_LOADNAME, + CALIBRATION_PIN_DISPLAY_NAME, + HEX_SCREWDRIVER_DISPLAY_NAME, } from './constants' import type { UseMutateFunction } from 'react-query' @@ -105,9 +107,9 @@ export const BeforeBeginning = ( const equipmentInfoByLoadName: { [loadName: string]: { displayName: string; subtitle?: string } } = { - calibration_pin: { displayName: t('calibration_pin') }, + calibration_pin: { displayName: CALIBRATION_PIN_DISPLAY_NAME }, hex_screwdriver: { - displayName: t('hex_screwdriver'), + displayName: HEX_SCREWDRIVER_DISPLAY_NAME, subtitle: t('provided_with_robot_use_right_size'), }, [GRIPPER_LOADNAME]: { displayName: t('branded:gripper') }, diff --git a/app/src/organisms/GripperWizardFlows/constants.ts b/app/src/organisms/GripperWizardFlows/constants.ts index db06adc340f..a5b633bab14 100644 --- a/app/src/organisms/GripperWizardFlows/constants.ts +++ b/app/src/organisms/GripperWizardFlows/constants.ts @@ -13,6 +13,10 @@ export const GRIPPER_FLOW_TYPES = { RECALIBRATE: 'RECALIBRATE', } as const +// note: we will not translate these item titles to be consistent with manuals +export const CALIBRATION_PIN_DISPLAY_NAME = 'Calibration Pin' +export const HEX_SCREWDRIVER_DISPLAY_NAME = '2.5 mm Hex Screwdriver' + // pin movements export const MOVE_PIN_TO_FRONT_JAW = 'movePinToFrontJaw' as const diff --git a/app/src/organisms/ODD/QuickTransferFlow/NameQuickTransfer.tsx b/app/src/organisms/ODD/QuickTransferFlow/NameQuickTransfer.tsx index 8bff060ac38..2ef4592f568 100644 --- a/app/src/organisms/ODD/QuickTransferFlow/NameQuickTransfer.tsx +++ b/app/src/organisms/ODD/QuickTransferFlow/NameQuickTransfer.tsx @@ -33,7 +33,6 @@ export function NameQuickTransfer(props: NameQuickTransferProps): JSX.Element { if (name.length > 60) { error = t('character_limit_error') } - // TODO add error handling for quick transfer name replication return createPortal( diff --git a/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx b/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx index ffcb72dae18..a69e095a674 100644 --- a/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx +++ b/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx @@ -107,6 +107,10 @@ export const BeforeBeginning = ( let equipmentList = [CALIBRATION_PROBE] const proceedButtonText = t('move_gantry_to_front') + const hexScrewdriverWithSubtitle = { + ...HEX_SCREWDRIVER, + subtitle: t('provided_with_robot'), + } let bodyTranslationKey: string = '' switch (flowType) { @@ -124,7 +128,7 @@ export const BeforeBeginning = ( equipmentList = [ { ...PIPETTE, displayName: displayName ?? PIPETTE.displayName }, CALIBRATION_PROBE, - HEX_SCREWDRIVER, + hexScrewdriverWithSubtitle, ] } else { equipmentList = [ @@ -133,7 +137,7 @@ export const BeforeBeginning = ( displayName: displayName ?? NINETY_SIX_CHANNEL_PIPETTE.displayName, }, CALIBRATION_PROBE, - HEX_SCREWDRIVER, + hexScrewdriverWithSubtitle, NINETY_SIX_CHANNEL_MOUNTING_PLATE, ] } @@ -148,19 +152,19 @@ export const BeforeBeginning = ( equipmentList = [ { ...NINETY_SIX_CHANNEL_PIPETTE, displayName }, CALIBRATION_PROBE, - HEX_SCREWDRIVER, + hexScrewdriverWithSubtitle, NINETY_SIX_CHANNEL_MOUNTING_PLATE, ] } else { equipmentList = [ { ...PIPETTE, displayName }, CALIBRATION_PROBE, - HEX_SCREWDRIVER, + hexScrewdriverWithSubtitle, ] } } else { bodyTranslationKey = 'get_started_detach' - equipmentList = [HEX_SCREWDRIVER] + equipmentList = [hexScrewdriverWithSubtitle] } break } diff --git a/app/src/organisms/PipetteWizardFlows/constants.ts b/app/src/organisms/PipetteWizardFlows/constants.ts index e4ddd762d95..1d0b94878c1 100644 --- a/app/src/organisms/PipetteWizardFlows/constants.ts +++ b/app/src/organisms/PipetteWizardFlows/constants.ts @@ -18,6 +18,8 @@ export const FLOWS = { DETACH: 'DETACH', CALIBRATE: 'CALIBRATE', } + +// note: we will not be translating these item titles to be consistent with manuals export const CALIBRATION_PROBE_DISPLAY_NAME = 'Calibration Probe' export const HEX_SCREWDRIVER_DISPLAY_NAME = '2.5 mm Hex Screwdriver' export const PIPETTE_DISPLAY_NAME = '1- or 8-Channel Pipette' @@ -33,9 +35,6 @@ export const CALIBRATION_PROBE = { export const HEX_SCREWDRIVER = { loadName: 'hex_screwdriver', displayName: HEX_SCREWDRIVER_DISPLAY_NAME, - // TODO(jr, 4/3/23): add this subtitle to i18n - subtitle: - 'Provided with the robot. Using another size can strip the instruments’s screws.', } export const PIPETTE = { loadName: 'flex_pipette', diff --git a/app/src/pages/Desktop/Labware/index.tsx b/app/src/pages/Desktop/Labware/index.tsx index 83f9dd94f3f..5d8959a5861 100644 --- a/app/src/pages/Desktop/Labware/index.tsx +++ b/app/src/pages/Desktop/Labware/index.tsx @@ -63,6 +63,7 @@ const labwareDisplayCategoryFilters: LabwareFilter[] = [ 'wellPlate', ] +// note: we've decided not to translate these categories const FILTER_OPTIONS: DropdownOption[] = labwareDisplayCategoryFilters.map( category => ({ name: startCase(category), diff --git a/app/src/redux/robot-update/__tests__/selectors.test.ts b/app/src/redux/robot-update/__tests__/selectors.test.ts index e4f3e8f8283..079244b5f32 100644 --- a/app/src/redux/robot-update/__tests__/selectors.test.ts +++ b/app/src/redux/robot-update/__tests__/selectors.test.ts @@ -474,10 +474,10 @@ describe('robot update selectors', () => { expect(result).toMatchObject({ autoUpdateDisabledReason: expect.stringMatching( - /update server is not responding/ + /update_server_unavailable/ ), updateFromFileDisabledReason: expect.stringMatching( - /update server is not responding/ + /update_server_unavailable/ ), }) }) @@ -495,10 +495,10 @@ describe('robot update selectors', () => { expect(result).toMatchObject({ autoUpdateDisabledReason: expect.stringMatching( - /update server is not responding/ + /update_server_unavailable/ ), updateFromFileDisabledReason: expect.stringMatching( - /update server is not responding/ + /update_server_unavailable/ ), }) }) @@ -526,11 +526,9 @@ describe('robot update selectors', () => { const result = selectors.getRobotUpdateDisplayInfo(state, robotName) expect(result).toMatchObject({ - autoUpdateDisabledReason: expect.stringMatching( - /updating a different robot/ - ), + autoUpdateDisabledReason: expect.stringMatching(/other_robot_updating/), updateFromFileDisabledReason: expect.stringMatching( - /updating a different robot/ + /other_robot_updating/ ), }) }) @@ -547,9 +545,7 @@ describe('robot update selectors', () => { expect(result).toEqual({ autoUpdateAction: expect.stringMatching(/unavailable/i), - autoUpdateDisabledReason: expect.stringMatching( - /unable to retrieve update/i - ), + autoUpdateDisabledReason: expect.stringMatching(/no_update_files/i), updateFromFileDisabledReason: null, }) }) diff --git a/app/src/redux/robot-update/selectors.ts b/app/src/redux/robot-update/selectors.ts index 0570a9dd2c8..a2427dfefb5 100644 --- a/app/src/redux/robot-update/selectors.ts +++ b/app/src/redux/robot-update/selectors.ts @@ -19,15 +19,6 @@ import type { RobotUpdateTarget, } from './types' -// TODO(mc, 2020-08-02): i18n -const UPDATE_SERVER_UNAVAILABLE = - "Unable to update because your robot's update server is not responding." -const OTHER_ROBOT_UPDATING = - 'Unable to update because the app is currently updating a different robot.' -const NO_UPDATE_FILES = - 'Unable to retrieve update for this robot. Ensure your computer is connected to the internet and try again later.' -const UNAVAILABLE = 'Update unavailable' - export const getRobotUpdateTarget: ( state: State, robotName: string @@ -198,6 +189,7 @@ export function getRobotUpdateAvailable( : getRobotUpdateType(currentVersion, updateVersion) } +// this util returns i18n keys in device_settings export const getRobotUpdateDisplayInfo: ( state: State, robotName: string @@ -212,21 +204,21 @@ export const getRobotUpdateDisplayInfo: ( (robot, currentUpdatingRobot, updateVersion) => { const robotVersion = robot ? getRobotApiVersion(robot) : null const autoUpdateType = getRobotUpdateType(robotVersion, updateVersion) - const autoUpdateAction = autoUpdateType ?? UNAVAILABLE + const autoUpdateAction = autoUpdateType ?? 'update_unavailable' let autoUpdateDisabledReason = null let updateFromFileDisabledReason = null if (robot?.serverHealthStatus !== HEALTH_STATUS_OK) { - autoUpdateDisabledReason = UPDATE_SERVER_UNAVAILABLE - updateFromFileDisabledReason = UPDATE_SERVER_UNAVAILABLE + autoUpdateDisabledReason = 'update_server_unavailable' + updateFromFileDisabledReason = 'update_server_unavailable' } else if ( currentUpdatingRobot !== null && currentUpdatingRobot.name !== robot?.name ) { - autoUpdateDisabledReason = OTHER_ROBOT_UPDATING - updateFromFileDisabledReason = OTHER_ROBOT_UPDATING + autoUpdateDisabledReason = 'other_robot_updating' + updateFromFileDisabledReason = 'other_robot_updating' } else if (autoUpdateType === null) { - autoUpdateDisabledReason = NO_UPDATE_FILES + autoUpdateDisabledReason = 'no_update_files' } return { diff --git a/app/src/redux/system-info/constants.ts b/app/src/redux/system-info/constants.ts index 1502d4bba07..a79b6ffb7bb 100644 --- a/app/src/redux/system-info/constants.ts +++ b/app/src/redux/system-info/constants.ts @@ -22,12 +22,3 @@ export const USB_DEVICE_REMOVED: 'systemInfo:USB_DEVICE_REMOVED' = export const NETWORK_INTERFACES_CHANGED: 'systemInfo:NETWORK_INTERFACES_CHANGED' = 'systemInfo:NETWORK_INTERFACES_CHANGED' - -// copy -// TODO(mc, 2020-05-11): i18n -export const U2E_DRIVER_OUTDATED_MESSAGE = - 'There is an updated Realtek USB-to-Ethernet adapter driver available for your computer.' -export const U2E_DRIVER_DESCRIPTION = - 'The OT-2 uses this adapter for its USB connection to the Opentrons App.' -export const U2E_DRIVER_OUTDATED_CTA = - "Please update your computer's driver to ensure a reliable connection to your OT-2." diff --git a/shared-data/js/fixtures.ts b/shared-data/js/fixtures.ts index 4f13a8b0321..905429cd111 100644 --- a/shared-data/js/fixtures.ts +++ b/shared-data/js/fixtures.ts @@ -238,7 +238,7 @@ export function getAddressableAreaNamesFromLoadedModule( return [...acc, ...providedAddressableAreas] }, []) } - +// note: we've decided not to translate these strings export function getFixtureDisplayName( cutoutFixtureId: CutoutFixtureId | null, usbPortNumber?: number From 98afdcfd84af983608e57aff8f005ea2dfc3341e Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Tue, 17 Dec 2024 08:50:24 -0500 Subject: [PATCH 18/42] fix(app): Fix run start/finish protocol analytics (#17118) Closes EXEC-850 and EXEC-805 --- .../useRunHeaderModalContainer.ts | 12 ++++++++++++ .../ProtocolRunHeader/hooks/useRunAnalytics.ts | 7 ++----- .../ProtocolSetup/__tests__/ProtocolSetup.test.tsx | 1 - app/src/pages/ODD/ProtocolSetup/index.tsx | 8 ++++++++ .../__tests__/useTrackProtocolRunEvent.test.tsx | 8 ++------ .../analytics/hooks/useTrackProtocolRunEvent.ts | 3 +++ 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/app/src/organisms/Desktop/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/useRunHeaderModalContainer.ts b/app/src/organisms/Desktop/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/useRunHeaderModalContainer.ts index 48eda0ebfa5..1e0d1e5c073 100644 --- a/app/src/organisms/Desktop/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/useRunHeaderModalContainer.ts +++ b/app/src/organisms/Desktop/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/useRunHeaderModalContainer.ts @@ -16,9 +16,15 @@ import { useProtocolDetailsForRun } from '/app/resources/runs' import { getFallbackRobotSerialNumber } from '../utils' import { ANALYTICS_PROTOCOL_PROCEED_TO_RUN, + ANALYTICS_PROTOCOL_RUN_ACTION, useTrackEvent, } from '/app/redux/analytics' +import { + useRobotAnalyticsData, + useTrackProtocolRunEvent, +} from '/app/redux-resources/analytics' import { useRobot, useRobotType } from '/app/redux-resources/robots' + import type { AttachedModule, RunStatus, Run } from '@opentrons/api-client' import type { UseErrorRecoveryResult } from '/app/organisms/ErrorRecoveryFlows' import type { @@ -71,7 +77,9 @@ export function useRunHeaderModalContainer({ const robot = useRobot(robotName) const robotSerialNumber = getFallbackRobotSerialNumber(robot) const trackEvent = useTrackEvent() + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const robotType = useRobotType(robotName) + const robotAnalyticsData = useRobotAnalyticsData(robotName) function handleProceedToRunClick(): void { navigate(`/devices/${robotName}/protocol-runs/${runId}/run-preview`) @@ -79,6 +87,10 @@ export function useRunHeaderModalContainer({ name: ANALYTICS_PROTOCOL_PROCEED_TO_RUN, properties: { robotSerialNumber }, }) + trackProtocolRunEvent({ + name: ANALYTICS_PROTOCOL_RUN_ACTION.START, + properties: robotAnalyticsData ?? {}, + }) protocolRunControls.play() } diff --git a/app/src/organisms/Desktop/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunAnalytics.ts b/app/src/organisms/Desktop/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunAnalytics.ts index 31399cbc541..95658999f4a 100644 --- a/app/src/organisms/Desktop/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunAnalytics.ts +++ b/app/src/organisms/Desktop/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunAnalytics.ts @@ -28,15 +28,12 @@ export function useRunAnalytics({ useEffect(() => { const areReportConditionsValid = - isRunCurrent && - runId != null && - robotAnalyticsData != null && - isTerminalRunStatus(runStatus) + isRunCurrent && runId != null && isTerminalRunStatus(runStatus) if (areReportConditionsValid) { trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_ACTION.FINISH, - properties: robotAnalyticsData, + properties: robotAnalyticsData ?? undefined, }) } }, [runStatus, isRunCurrent, runId, robotAnalyticsData]) diff --git a/app/src/pages/ODD/ProtocolSetup/__tests__/ProtocolSetup.test.tsx b/app/src/pages/ODD/ProtocolSetup/__tests__/ProtocolSetup.test.tsx index 5f7d1f8cfc8..5863d70ba93 100644 --- a/app/src/pages/ODD/ProtocolSetup/__tests__/ProtocolSetup.test.tsx +++ b/app/src/pages/ODD/ProtocolSetup/__tests__/ProtocolSetup.test.tsx @@ -576,7 +576,6 @@ describe('ProtocolSetup', () => { render(`/runs/${RUN_ID}/setup/`) fireEvent.click(screen.getByRole('button', { name: 'play' })) - expect(mockTrackProtocolRunEvent).toBeCalledTimes(1) expect(mockTrackProtocolRunEvent).toHaveBeenCalledWith({ name: ANALYTICS_PROTOCOL_RUN_ACTION.START, properties: {}, diff --git a/app/src/pages/ODD/ProtocolSetup/index.tsx b/app/src/pages/ODD/ProtocolSetup/index.tsx index 25c978e6717..1df659c633b 100644 --- a/app/src/pages/ODD/ProtocolSetup/index.tsx +++ b/app/src/pages/ODD/ProtocolSetup/index.tsx @@ -741,11 +741,19 @@ export function ProtocolSetup(): JSX.Element { robotType, protocolName ) + + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) + const robotAnalyticsData = useRobotAnalyticsData(robotName) + const handleProceedToRunClick = (): void => { trackEvent({ name: ANALYTICS_PROTOCOL_PROCEED_TO_RUN, properties: { robotSerialNumber }, }) + trackProtocolRunEvent({ + name: ANALYTICS_PROTOCOL_RUN_ACTION.START, + properties: robotAnalyticsData ?? {}, + }) play() } const configBypassHeaterShakerAttachmentConfirmation = useSelector( diff --git a/app/src/redux-resources/analytics/hooks/__tests__/useTrackProtocolRunEvent.test.tsx b/app/src/redux-resources/analytics/hooks/__tests__/useTrackProtocolRunEvent.test.tsx index 3172c8d1fbc..f769dc005c4 100644 --- a/app/src/redux-resources/analytics/hooks/__tests__/useTrackProtocolRunEvent.test.tsx +++ b/app/src/redux-resources/analytics/hooks/__tests__/useTrackProtocolRunEvent.test.tsx @@ -2,7 +2,7 @@ import type * as React from 'react' import { createStore } from 'redux' import { Provider } from 'react-redux' import { QueryClient, QueryClientProvider } from 'react-query' -import { vi, it, expect, describe, beforeEach, afterEach } from 'vitest' +import { vi, it, expect, describe, beforeEach } from 'vitest' import { when } from 'vitest-when' import { waitFor, renderHook } from '@testing-library/react' @@ -63,10 +63,6 @@ describe('useTrackProtocolRunEvent hook', () => { }) }) - afterEach(() => { - vi.resetAllMocks() - }) - it('returns trackProtocolRunEvent function', () => { const { result } = renderHook( () => useTrackProtocolRunEvent(RUN_ID, ROBOT_NAME), @@ -92,7 +88,7 @@ describe('useTrackProtocolRunEvent hook', () => { ) expect(mockTrackEvent).toHaveBeenCalledWith({ name: ANALYTICS_PROTOCOL_RUN_ACTION.START, - properties: PROTOCOL_PROPERTIES, + properties: { ...PROTOCOL_PROPERTIES, transactionId: RUN_ID }, }) }) diff --git a/app/src/redux-resources/analytics/hooks/useTrackProtocolRunEvent.ts b/app/src/redux-resources/analytics/hooks/useTrackProtocolRunEvent.ts index 2f9f085fd64..05c3ce16746 100644 --- a/app/src/redux-resources/analytics/hooks/useTrackProtocolRunEvent.ts +++ b/app/src/redux-resources/analytics/hooks/useTrackProtocolRunEvent.ts @@ -34,6 +34,9 @@ export function useTrackProtocolRunEvent( ...properties, ...protocolRunAnalyticsData, runTime, + // It's sometimes unavoidable (namely on the desktop app) to prevent sending an event multiple times. + // In these circumstances, we need an idempotency key to accurately filter events in Mixpanel. + transactionId: runId, }, }) }) From 5ff3efdabff4d63d1b47f2f76dba69638ac1da15 Mon Sep 17 00:00:00 2001 From: koji Date: Tue, 17 Dec 2024 10:50:04 -0500 Subject: [PATCH 19/42] fix(protocol-designer): add gridgap to between error and warning (#17116) * fix(protocol-designer): add gridgap to between error and warning --- protocol-designer/src/organisms/Alerts/FormAlerts.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/protocol-designer/src/organisms/Alerts/FormAlerts.tsx b/protocol-designer/src/organisms/Alerts/FormAlerts.tsx index b6080a05a73..8348b5bd798 100644 --- a/protocol-designer/src/organisms/Alerts/FormAlerts.tsx +++ b/protocol-designer/src/organisms/Alerts/FormAlerts.tsx @@ -184,6 +184,7 @@ function FormAlertsComponent(props: FormAlertsProps): JSX.Element | null { {showFormErrors ? formErrors.map((error, key) => makeAlert('error', error, key)) From 4bb6a9c6fc1f05f8298063b168d121199a599575 Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Tue, 17 Dec 2024 10:55:12 -0500 Subject: [PATCH 20/42] =?UTF-8?q?fix(protocol-designer):=20make=208=5F2=5F?= =?UTF-8?q?2=20migration=20to=20migrate=20HS=20set=20timer=20=E2=80=A6=20(?= =?UTF-8?q?#17124)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …field The `heaterShakerSetTimer` field's type is `heaterShakerSetTimer: 'true' | 'false' | null` - this was written 3 years ago. However, despite this, the field when checking the checkbox in the form in PD would populate it as `true` or `false` booleans rather than the true/false strings. 2 weeks ago, right before 8.2.0 was released, there was a bug checking the timer checkbox for the temperature module and it was because of this boolean vs boolean strings issue. So I extended it onto the heater-shaker set timer field as well because of its type. Unfortunately, that resulted in this current error: - protocols created in 8.2.0 and 8.2.1 have the `heaterShakerSetTimer` field set to either `'true'` or `'false'` strings - protocols created prior to 8.2.0 have the `heaterShakerSetTimer` field set to `true` or `false` boolean - my initial fix was to update the form field to check for `true` or `false` boolean but that didn't fix any protocols created in 8.2.0 and 8.2.1. - the extended fix unfortunately required a migration so now if `'true'` or `'false'` strings are used in the field, they get migrated to `true` or `false` boolean -- this i believe is the only way to fix all protocol versions --- .../fixtures/protocol/8/doItAllV8.json | 2 +- .../8/newAdvancedSettingsAndMultiTemp.json | 2 +- .../8/ninetySixChannelFullAndColumn.json | 2 +- protocol-designer/src/form-types.ts | 2 +- .../src/load-file/migration/8_2_2.ts | 51 +++++++++++++++++++ .../src/load-file/migration/index.ts | 4 ++ .../test/heaterShakerFormToArgs.test.ts | 4 +- 7 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 protocol-designer/src/load-file/migration/8_2_2.ts diff --git a/protocol-designer/fixtures/protocol/8/doItAllV8.json b/protocol-designer/fixtures/protocol/8/doItAllV8.json index 5618fde0e9b..9206bdcf267 100644 --- a/protocol-designer/fixtures/protocol/8/doItAllV8.json +++ b/protocol-designer/fixtures/protocol/8/doItAllV8.json @@ -13,7 +13,7 @@ }, "designerApplication": { "name": "opentrons/protocol-designer", - "version": "8.2.0", + "version": "8.2.2", "data": { "_internalAppBuildDate": "Mon, 11 Nov 2024 20:18:16 GMT", "defaultValues": { diff --git a/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json b/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json index 6fe09bdbd02..9c6d24abaca 100644 --- a/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json +++ b/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json @@ -13,7 +13,7 @@ }, "designerApplication": { "name": "opentrons/protocol-designer", - "version": "8.2.0", + "version": "8.2.2", "data": { "_internalAppBuildDate": "Mon, 11 Nov 2024 20:10:44 GMT", "defaultValues": { diff --git a/protocol-designer/fixtures/protocol/8/ninetySixChannelFullAndColumn.json b/protocol-designer/fixtures/protocol/8/ninetySixChannelFullAndColumn.json index cc871cd6917..fe6d08df65c 100644 --- a/protocol-designer/fixtures/protocol/8/ninetySixChannelFullAndColumn.json +++ b/protocol-designer/fixtures/protocol/8/ninetySixChannelFullAndColumn.json @@ -13,7 +13,7 @@ }, "designerApplication": { "name": "opentrons/protocol-designer", - "version": "8.2.0", + "version": "8.2.2", "data": { "_internalAppBuildDate": "Wed, 01 May 2024 13:32:34 GMT", "defaultValues": { diff --git a/protocol-designer/src/form-types.ts b/protocol-designer/src/form-types.ts index 1a9962ae582..8e86d72a426 100644 --- a/protocol-designer/src/form-types.ts +++ b/protocol-designer/src/form-types.ts @@ -360,7 +360,7 @@ export interface HydratedTemperatureFormData { targetTemperature: string | null } export interface HydratedHeaterShakerFormData { - heaterShakerSetTimer: 'true' | 'false' | null + heaterShakerSetTimer: boolean | null heaterShakerTimer: string | null id: string latchOpen: boolean diff --git a/protocol-designer/src/load-file/migration/8_2_2.ts b/protocol-designer/src/load-file/migration/8_2_2.ts new file mode 100644 index 00000000000..007aa288787 --- /dev/null +++ b/protocol-designer/src/load-file/migration/8_2_2.ts @@ -0,0 +1,51 @@ +import type { ProtocolFile } from '@opentrons/shared-data' +import type { DesignerApplicationData } from './utils/getLoadLiquidCommands' + +export const migrateFile = ( + appData: ProtocolFile +): ProtocolFile => { + const { designerApplication } = appData + + if (designerApplication == null || designerApplication?.data == null) { + throw Error('The designerApplication key in your file is corrupt.') + } + const savedStepForms = designerApplication.data + ?.savedStepForms as DesignerApplicationData['savedStepForms'] + + const savedStepsWithUpdatedHeaterShakerTimerField = Object.values( + savedStepForms + ).reduce((acc, form) => { + if (form.stepType === 'heaterShaker') { + const { id, heaterShakerSetTimer } = form + let newSetTimer = heaterShakerSetTimer + + if (heaterShakerSetTimer === 'false') { + newSetTimer = false + } else if (heaterShakerSetTimer === 'true') { + newSetTimer = true + } + return { + ...acc, + [id]: { + ...form, + heaterShakerSetTimer: newSetTimer, + }, + } + } + return acc + }, {}) + + return { + ...appData, + designerApplication: { + ...designerApplication, + data: { + ...designerApplication.data, + savedStepForms: { + ...designerApplication.data.savedStepForms, + ...savedStepsWithUpdatedHeaterShakerTimerField, + }, + }, + }, + } +} diff --git a/protocol-designer/src/load-file/migration/index.ts b/protocol-designer/src/load-file/migration/index.ts index 1ef3f346153..27afb8eb132 100644 --- a/protocol-designer/src/load-file/migration/index.ts +++ b/protocol-designer/src/load-file/migration/index.ts @@ -12,6 +12,8 @@ import { migrateFile as migrateFileSeven } from './7_0_0' import { migrateFile as migrateFileEight } from './8_0_0' import { migrateFile as migrateFileEightOne } from './8_1_0' import { migrateFile as migrateFileEightTwo } from './8_2_0' +import { migrateFile as migrateFileEightTwoPointTwo } from './8_2_2' + import type { PDProtocolFile } from '../../file-types' export const OLDEST_MIGRATEABLE_VERSION = '1.0.0' @@ -54,6 +56,8 @@ const allMigrationsByVersion: MigrationsByVersion = { '8.1.0': migrateFileEightOne, // @ts-expect-error '8.2.0': migrateFileEightTwo, + // @ts-expect-error + '8.2.2': migrateFileEightTwoPointTwo, } export const migration = ( file: any diff --git a/protocol-designer/src/steplist/formLevel/stepFormToArgs/test/heaterShakerFormToArgs.test.ts b/protocol-designer/src/steplist/formLevel/stepFormToArgs/test/heaterShakerFormToArgs.test.ts index 4329e6ca4f6..2a664085113 100644 --- a/protocol-designer/src/steplist/formLevel/stepFormToArgs/test/heaterShakerFormToArgs.test.ts +++ b/protocol-designer/src/steplist/formLevel/stepFormToArgs/test/heaterShakerFormToArgs.test.ts @@ -9,7 +9,7 @@ describe('heaterShakerFormToArgs', () => { id: 'id', stepDetails: 'step details', moduleId: 'moduleId', - heaterShakerSetTimer: 'true', + heaterShakerSetTimer: true, setHeaterShakerTemperature: true, setShake: true, latchOpen: false, @@ -35,7 +35,7 @@ describe('heaterShakerFormToArgs', () => { id: 'id', stepDetails: 'step details', moduleId: 'moduleId', - heaterShakerSetTimer: 'false', + heaterShakerSetTimer: false, setHeaterShakerTemperature: true, setShake: false, latchOpen: false, From c7521976766e0412250ac1e5c3c0e40de96d13d8 Mon Sep 17 00:00:00 2001 From: Shlok Amin Date: Tue, 17 Dec 2024 14:17:37 -0500 Subject: [PATCH 21/42] feat(opentrons-ai-client): add shared-data as dependency (#16663) --- opentrons-ai-client/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/opentrons-ai-client/package.json b/opentrons-ai-client/package.json index 9f636be46d9..a75473bd680 100644 --- a/opentrons-ai-client/package.json +++ b/opentrons-ai-client/package.json @@ -22,6 +22,7 @@ "@auth0/auth0-react": "2.2.4", "@fontsource/public-sans": "5.0.3", "@opentrons/components": "link:../components", + "@opentrons/shared-data": "link:../shared-data", "axios": "^0.21.1", "i18next": "^19.8.3", "jotai": "2.8.0", From f38bb0b6c0cd4cc51d6844f7c09abf8b44b10d61 Mon Sep 17 00:00:00 2001 From: koji Date: Wed, 18 Dec 2024 08:43:00 -0500 Subject: [PATCH 22/42] fix(protocol-designer): change initial value from null to true (#17133) * fix(protocol-designer): change initial value from null to true --- protocol-designer/src/analytics/reducers.ts | 4 ++-- protocol-designer/src/pages/Settings/index.tsx | 10 ++++------ protocol-designer/src/persist.ts | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/protocol-designer/src/analytics/reducers.ts b/protocol-designer/src/analytics/reducers.ts index 9c2427f603a..c894c6be3ce 100644 --- a/protocol-designer/src/analytics/reducers.ts +++ b/protocol-designer/src/analytics/reducers.ts @@ -5,11 +5,11 @@ import type { Action } from '../types' import type { SetOptIn } from './actions' import type { RehydratePersistedAction } from '../persist' export interface OptInState { - hasOptedIn: boolean | null + hasOptedIn: boolean appVersion?: string } const optInInitialState = { - hasOptedIn: null, + hasOptedIn: true, } // @ts-expect-error(sb, 2021-6-17): cannot use string literals as action type diff --git a/protocol-designer/src/pages/Settings/index.tsx b/protocol-designer/src/pages/Settings/index.tsx index 7165b5d68a8..63519226a92 100644 --- a/protocol-designer/src/pages/Settings/index.tsx +++ b/protocol-designer/src/pages/Settings/index.tsx @@ -42,7 +42,7 @@ export function Settings(): JSX.Element { const [showAnnouncementModal, setShowAnnouncementModal] = useState( false ) - const analytics = useSelector(analyticsSelectors.getHasOptedIn) + const { hasOptedIn } = useSelector(analyticsSelectors.getHasOptedIn) const flags = useSelector(getFeatureFlagData) const canClearHintDismissals = useSelector( tutorialSelectors.getCanClearHintDismissals @@ -274,13 +274,13 @@ export function Settings(): JSX.Element { data-testid="analyticsToggle" size="2rem" css={ - Boolean(analytics.hasOptedIn) + Boolean(hasOptedIn) ? TOGGLE_ENABLED_STYLES : TOGGLE_DISABLED_STYLES } onClick={() => dispatch( - analytics.hasOptedIn + hasOptedIn ? analyticsActions.optOut() : analyticsActions.optIn() ) @@ -288,9 +288,7 @@ export function Settings(): JSX.Element { > diff --git a/protocol-designer/src/persist.ts b/protocol-designer/src/persist.ts index 576ad937cc2..4c0bb6a1ed3 100644 --- a/protocol-designer/src/persist.ts +++ b/protocol-designer/src/persist.ts @@ -9,7 +9,7 @@ export interface RehydratePersistedAction { 'tutorial.dismissedHints'?: Record 'featureFlags.flags'?: Record 'analytics.hasOptedIn'?: { - hasOptedIn: boolean | null + hasOptedIn: boolean appVersion?: string } } From f8def7767d6a237c64cb18560fd24c02c45c0a17 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:35:48 -0500 Subject: [PATCH 23/42] feat(protocol-designer,-shared-data): add liquid class scaffolding to PD (#17126) This PR introduces initial work for liquid class support in protocol designer. I create a full liquid class interface based on the API's Pydantic model. I also add utilities for getting all liquid class definitions and a feature flag to hide liquid classes from the UI. Lastly, I add some of the basic functionality for assigning a liquid class to a defined liquid, and displaying that liquid class in LiquidCard. A liquid class assigned to a defined liquid will be accessible through extended existing selectors (allIngredientNamesIds) for step forms. closes AUTH-965 closes AUTH-968 --- .../assets/localization/en/feature_flags.json | 4 + .../src/assets/localization/en/liquids.json | 4 + .../src/feature-flags/reducers.ts | 2 + .../src/feature-flags/selectors.ts | 4 + protocol-designer/src/feature-flags/types.ts | 2 + .../__tests__/ingredients.test.ts | 2 + .../src/labware-ingred/selectors.ts | 1 + protocol-designer/src/labware-ingred/types.ts | 19 ++- protocol-designer/src/liquid-defs/utils.ts | 15 +++ .../AssignLiquidsModal/LiquidCard.tsx | 17 ++- .../AssignLiquidsModal/LiquidToolbox.tsx | 5 + .../organisms/DefineLiquidsModal/index.tsx | 65 +++++++++- .../__tests__/MaterialsListModal.test.tsx | 1 + .../__tests__/LiquidsOverflowMenu.test.tsx | 1 + .../ProtocolOverview/LiquidDefinitions.tsx | 111 ++++++++++++------ .../__tests__/LiquidDefinitions.test.tsx | 5 + shared-data/js/index.ts | 1 + shared-data/js/liquidClasses.ts | 8 ++ shared-data/js/types.ts | 100 ++++++++++++++++ 19 files changed, 312 insertions(+), 55 deletions(-) create mode 100644 protocol-designer/src/liquid-defs/utils.ts create mode 100644 shared-data/js/liquidClasses.ts diff --git a/protocol-designer/src/assets/localization/en/feature_flags.json b/protocol-designer/src/assets/localization/en/feature_flags.json index 9a13b327be8..92a074088ba 100644 --- a/protocol-designer/src/assets/localization/en/feature_flags.json +++ b/protocol-designer/src/assets/localization/en/feature_flags.json @@ -31,5 +31,9 @@ "OT_PD_ENABLE_REACT_SCAN": { "title": "Enable React Scan", "description": "Enable React Scan support for components rendering check" + }, + "OT_PD_ENABLE_LIQUID_CLASSES": { + "title": "Enable liquid classes", + "description": "Enable liquid classes support" } } diff --git a/protocol-designer/src/assets/localization/en/liquids.json b/protocol-designer/src/assets/localization/en/liquids.json index ebd4800dacb..36a31cf8116 100644 --- a/protocol-designer/src/assets/localization/en/liquids.json +++ b/protocol-designer/src/assets/localization/en/liquids.json @@ -10,6 +10,10 @@ "display_color": "Color", "liquid_volume": "Liquid volume by well", "liquid": "Liquid", + "liquid_class": { + "title": "Liquid class", + "tooltip": "Applies predefined pipetting settings to transfer and mix steps using this liquid" + }, "liquids_added": "Liquids added", "liquids": "Liquids", "microliters": "µL", diff --git a/protocol-designer/src/feature-flags/reducers.ts b/protocol-designer/src/feature-flags/reducers.ts index 42782c88479..bcffd39c5e7 100644 --- a/protocol-designer/src/feature-flags/reducers.ts +++ b/protocol-designer/src/feature-flags/reducers.ts @@ -30,6 +30,8 @@ const initialFlags: Flags = { OT_PD_ENABLE_HOT_KEYS_DISPLAY: process.env.OT_PD_ENABLE_HOT_KEYS_DISPLAY === '1' || true, OT_PD_ENABLE_REACT_SCAN: process.env.OT_PD_ENABLE_REACT_SCAN === '1' || false, + OT_PD_ENABLE_LIQUID_CLASSES: + process.env.OT_PD_ENABLE_REACT_SCAN === '1' || false, } // @ts-expect-error(sa, 2021-6-10): cannot use string literals as action type // TODO IMMEDIATELY: refactor this to the old fashioned way if we cannot have type safety: https://github.com/redux-utilities/redux-actions/issues/282#issuecomment-595163081 diff --git a/protocol-designer/src/feature-flags/selectors.ts b/protocol-designer/src/feature-flags/selectors.ts index 72b25fca895..6b8a70f8b30 100644 --- a/protocol-designer/src/feature-flags/selectors.ts +++ b/protocol-designer/src/feature-flags/selectors.ts @@ -45,3 +45,7 @@ export const getEnableReactScan: Selector = createSelector( getFeatureFlagData, flags => flags.OT_PD_ENABLE_REACT_SCAN ?? false ) +export const getEnableLiquidClasses: Selector = createSelector( + getFeatureFlagData, + flags => flags.OT_PD_ENABLE_LIQUID_CLASSES ?? false +) diff --git a/protocol-designer/src/feature-flags/types.ts b/protocol-designer/src/feature-flags/types.ts index 84bab18e474..6840786d149 100644 --- a/protocol-designer/src/feature-flags/types.ts +++ b/protocol-designer/src/feature-flags/types.ts @@ -36,6 +36,7 @@ export type FlagTypes = | 'OT_PD_ENABLE_RETURN_TIP' | 'OT_PD_ENABLE_HOT_KEYS_DISPLAY' | 'OT_PD_ENABLE_REACT_SCAN' + | 'OT_PD_ENABLE_LIQUID_CLASSES' // flags that are not in this list only show in prerelease mode export const userFacingFlags: FlagTypes[] = [ 'OT_PD_DISABLE_MODULE_RESTRICTIONS', @@ -49,5 +50,6 @@ export const allFlags: FlagTypes[] = [ 'OT_PD_ENABLE_COMMENT', 'OT_PD_ENABLE_RETURN_TIP', 'OT_PD_ENABLE_REACT_SCAN', + 'OT_PD_ENABLE_LIQUID_CLASSES', ] export type Flags = Partial> diff --git a/protocol-designer/src/labware-ingred/__tests__/ingredients.test.ts b/protocol-designer/src/labware-ingred/__tests__/ingredients.test.ts index b771cd16bbf..c81883001ac 100644 --- a/protocol-designer/src/labware-ingred/__tests__/ingredients.test.ts +++ b/protocol-designer/src/labware-ingred/__tests__/ingredients.test.ts @@ -19,6 +19,7 @@ describe('DUPLICATE_LABWARE action', () => { wellDetailsByLocation: null, concentration: '50 mol/ng', description: '', + liquidClass: null, displayColor: '#b925ff', serialize: false, }, @@ -27,6 +28,7 @@ describe('DUPLICATE_LABWARE action', () => { wellDetailsByLocation: null, concentration: '100%', description: '', + liquidClass: null, displayColor: '#ffd600', serialize: false, }, diff --git a/protocol-designer/src/labware-ingred/selectors.ts b/protocol-designer/src/labware-ingred/selectors.ts index eb7767af225..25ee8bc0966 100644 --- a/protocol-designer/src/labware-ingred/selectors.ts +++ b/protocol-designer/src/labware-ingred/selectors.ts @@ -113,6 +113,7 @@ const allIngredientNamesIds: Selector< ingredientId: ingredId, name: ingreds[ingredId].name, displayColor: ingreds[ingredId].displayColor, + liquidClass: ingreds[ingredId].liquidClass, })) }) const getLabwareSelectionMode: Selector = createSelector( diff --git a/protocol-designer/src/labware-ingred/types.ts b/protocol-designer/src/labware-ingred/types.ts index 6e9567722f3..6b7628735d8 100644 --- a/protocol-designer/src/labware-ingred/types.ts +++ b/protocol-designer/src/labware-ingred/types.ts @@ -19,23 +19,22 @@ export interface WellContents { selected?: boolean maxVolume?: number } -export type ContentsByWell = { - [wellName: string]: WellContents -} | null -export interface WellContentsByLabware { - [labwareId: string]: ContentsByWell -} +export type ContentsByWell = Record | null +export type WellContentsByLabware = Record // ==== INGREDIENTS ==== +// TODO(ND: 12/17/2024): add migration for liquids in >8.3.0 export type OrderedLiquids = Array<{ ingredientId: string - name: string | null | undefined - displayColor: string | null | undefined + name?: string | null + displayColor?: string | null + liquidClass?: string | null }> // TODO: Ian 2018-10-15 audit & rename these confusing types export interface LiquidGroup { - name: string | null | undefined - description: string | null | undefined + name: string | null + description: string | null displayColor: string + liquidClass: string | null serialize: boolean } export type IngredInputs = LiquidGroup & { diff --git a/protocol-designer/src/liquid-defs/utils.ts b/protocol-designer/src/liquid-defs/utils.ts new file mode 100644 index 00000000000..cb9bc9398c9 --- /dev/null +++ b/protocol-designer/src/liquid-defs/utils.ts @@ -0,0 +1,15 @@ +import { getAllLiquidClassDefs } from '@opentrons/shared-data' + +const liquidClassDefs = getAllLiquidClassDefs() +export const getLiquidClassDisplayName = ( + liquidClass: string | null +): string | null => { + if (liquidClass == null) { + return null + } + if (!(liquidClass in liquidClassDefs)) { + console.warn(`Liquid class ${liquidClass} not found`) + return null + } + return liquidClassDefs[liquidClass].displayName +} diff --git a/protocol-designer/src/organisms/AssignLiquidsModal/LiquidCard.tsx b/protocol-designer/src/organisms/AssignLiquidsModal/LiquidCard.tsx index a422b4b210e..4f33b968db4 100644 --- a/protocol-designer/src/organisms/AssignLiquidsModal/LiquidCard.tsx +++ b/protocol-designer/src/organisms/AssignLiquidsModal/LiquidCard.tsx @@ -20,6 +20,7 @@ import { } from '@opentrons/components' import { LINE_CLAMP_TEXT_STYLE } from '../../atoms' +import { getEnableLiquidClasses } from '../../feature-flags/selectors' import { removeWellsContents } from '../../labware-ingred/actions' import { selectors as labwareIngredSelectors } from '../../labware-ingred/selectors' import { getLabwareEntities } from '../../step-forms/selectors' @@ -34,7 +35,7 @@ interface LiquidCardProps { export function LiquidCard(props: LiquidCardProps): JSX.Element { const { info } = props - const { name, color, liquidIndex } = info + const { name, color, liquidClassDisplayName, liquidIndex } = info const { t } = useTranslation('liquids') const dispatch = useDispatch() const [isExpanded, setIsExpanded] = useState(false) @@ -49,6 +50,7 @@ export function LiquidCard(props: LiquidCardProps): JSX.Element { const allWellContentsForActiveItem = useSelector( wellContentsSelectors.getAllWellContentsForActiveItem ) + const enableLiquidClasses = useSelector(getEnableLiquidClasses) const wellContents = allWellContentsForActiveItem != null && labwareId != null ? allWellContentsForActiveItem[labwareId] @@ -104,13 +106,24 @@ export function LiquidCard(props: LiquidCardProps): JSX.Element { > - + {name} + {liquidClassDisplayName != null && enableLiquidClasses ? ( + + ) : null} { if (liquidGroupId != null) { @@ -107,13 +117,14 @@ export function DefineLiquidsModal( const initialValues: LiquidEditFormValues = { name: selectedIngredFields?.name ?? '', displayColor: selectedIngredFields?.displayColor ?? swatchColors(liquidId), + liquidClass: selectedIngredFields?.liquidClass ?? '', description: selectedIngredFields?.description ?? '', serialize: selectedIngredFields?.serialize ?? false, } const { handleSubmit, - formState: { errors, touchedFields }, + formState, control, watch, setValue, @@ -125,12 +136,15 @@ export function DefineLiquidsModal( }) const name = watch('name') const color = watch('displayColor') + const liquidClass = watch('liquidClass') + const { errors, touchedFields } = formState const handleLiquidEdits = (values: LiquidEditFormValues): void => { saveForm({ name: values.name, displayColor: values.displayColor, - description: values.description ?? null, + liquidClass: values.liquidClass ? values.liquidClass : null, + description: values.description ? values.description : null, serialize: values.serialize ?? false, }) } @@ -142,6 +156,15 @@ export function DefineLiquidsModal( return `#${toHex(r)}${toHex(g)}${toHex(b)}${toHex(alpha)}` } + const liquidClassOptions = [ + { name: 'Choose an option', value: '' }, + ...Object.entries(liquidClassDefs).map( + ([liquidClassDefName, { displayName }]) => { + return { name: displayName, value: liquidClassDefName } + } + ), + ] + return ( { @@ -182,6 +205,7 @@ export function DefineLiquidsModal( left="4.375rem" top="4.6875rem" ref={chooseColorWrapperRef} + zIndex={2} > - + + {enableLiquidClasses ? ( + + ( + value === liquidClass + ) ?? liquidClassOptions[0] + } + onClick={value => { + field.onChange(value) + setValue('liquidClass', value) + }} + /> + )} + /> + + ) : null} { ingredientId: mockId, name: 'mockName', displayColor: 'mockDisplayColor', + liquidClass: null, }, ], } diff --git a/protocol-designer/src/pages/Designer/__tests__/LiquidsOverflowMenu.test.tsx b/protocol-designer/src/pages/Designer/__tests__/LiquidsOverflowMenu.test.tsx index 45fbebe5494..6e646fb6db7 100644 --- a/protocol-designer/src/pages/Designer/__tests__/LiquidsOverflowMenu.test.tsx +++ b/protocol-designer/src/pages/Designer/__tests__/LiquidsOverflowMenu.test.tsx @@ -42,6 +42,7 @@ describe('SlotOverflowMenu', () => { displayColor: 'mockColor', name: 'mockname', ingredientId: '0', + liquidClass: null, }, ]) }) diff --git a/protocol-designer/src/pages/ProtocolOverview/LiquidDefinitions.tsx b/protocol-designer/src/pages/ProtocolOverview/LiquidDefinitions.tsx index 378f14e13ad..e9da36c4bae 100644 --- a/protocol-designer/src/pages/ProtocolOverview/LiquidDefinitions.tsx +++ b/protocol-designer/src/pages/ProtocolOverview/LiquidDefinitions.tsx @@ -1,4 +1,5 @@ import { useTranslation } from 'react-i18next' +import { useSelector } from 'react-redux' import { ALIGN_CENTER, DIRECTION_COLUMN, @@ -9,10 +10,42 @@ import { ListItemDescriptor, SPACING, StyledText, + Tag, } from '@opentrons/components' import { LINE_CLAMP_TEXT_STYLE } from '../../atoms' +import { getEnableLiquidClasses } from '../../feature-flags/selectors' +import { getLiquidClassDisplayName } from '../../liquid-defs/utils' -import type { AllIngredGroupFields } from '../../labware-ingred/types' +import type { + AllIngredGroupFields, + IngredInputs, +} from '../../labware-ingred/types' + +const getLiquidDescription = ( + liquid: IngredInputs, + enableLiquidClasses: boolean +): JSX.Element | null => { + const { description, liquidClass } = liquid + const liquidClassDisplayName = getLiquidClassDisplayName(liquidClass) + const liquidClassInfo = + !enableLiquidClasses || liquidClassDisplayName == null ? null : ( + + ) + + return liquidClassInfo == null && !description ? null : ( + + {description ? ( + + {description} + + ) : null} + {liquidClassInfo} + + ) +} interface LiquidDefinitionsProps { allIngredientGroupFields: AllIngredGroupFields @@ -22,6 +55,7 @@ export function LiquidDefinitions({ allIngredientGroupFields, }: LiquidDefinitionsProps): JSX.Element { const { t } = useTranslation('protocol_overview') + const enableLiquidClasses = useSelector(getEnableLiquidClasses) return ( @@ -30,43 +64,46 @@ export function LiquidDefinitions({ {Object.keys(allIngredientGroupFields).length > 0 ? ( - Object.values(allIngredientGroupFields).map((liquid, index) => ( - - - - { + console.log(getLiquidDescription(liquid, enableLiquidClasses)) + return ( + + - {liquid.name} - - - } - content={ - - {liquid.description != null && liquid.description !== '' - ? liquid.description - : t('na')} - - } - /> - - )) + + + {liquid.name} + + + } + content={ + getLiquidDescription(liquid, enableLiquidClasses) ?? ( + + {t('na')} + + ) + } + /> + + ) + }) ) : ( )} diff --git a/protocol-designer/src/pages/ProtocolOverview/__tests__/LiquidDefinitions.test.tsx b/protocol-designer/src/pages/ProtocolOverview/__tests__/LiquidDefinitions.test.tsx index 832cea4d800..ff4af37fa4a 100644 --- a/protocol-designer/src/pages/ProtocolOverview/__tests__/LiquidDefinitions.test.tsx +++ b/protocol-designer/src/pages/ProtocolOverview/__tests__/LiquidDefinitions.test.tsx @@ -8,6 +8,8 @@ import { LiquidDefinitions } from '../LiquidDefinitions' import type { ComponentProps } from 'react' import type { InfoScreen } from '@opentrons/components' +vi.mock('../../../feature-flags/selectors') + vi.mock('@opentrons/components', async importOriginal => { const actual = await importOriginal() return { @@ -21,6 +23,7 @@ const mockAllIngredientGroupFields = { name: 'EtOH', displayColor: '#b925ff', description: 'Immer fisch Hergestllter EtOH', + liquidClass: null, serialize: false, liquidGroupId: '0', }, @@ -28,6 +31,7 @@ const mockAllIngredientGroupFields = { name: '10mM Tris pH8,5', displayColor: '#ffd600', description: null, + liquidClass: null, serialize: false, liquidGroupId: '1', }, @@ -35,6 +39,7 @@ const mockAllIngredientGroupFields = { name: 'Amplicon PCR sample + AMPure XP beads', displayColor: '#9dffd8', description: '25µl Amplicon PCR + 20 µl AMPure XP beads', + liquidClass: 'Water', serialize: false, liquidGroupId: '2', }, diff --git a/shared-data/js/index.ts b/shared-data/js/index.ts index 9a8d2e6c39f..50be81a940e 100644 --- a/shared-data/js/index.ts +++ b/shared-data/js/index.ts @@ -10,6 +10,7 @@ export * from './gripper' export * from './helpers' export * from './labware' export * from './labwareTools' +export * from './liquidClasses' export * from './modules' export * from './pipettes' export * from './protocols' diff --git a/shared-data/js/liquidClasses.ts b/shared-data/js/liquidClasses.ts new file mode 100644 index 00000000000..d97db8afa47 --- /dev/null +++ b/shared-data/js/liquidClasses.ts @@ -0,0 +1,8 @@ +import waterV1Uncasted from '../liquid-class/definitions/1/water.json' +import type { LiquidClass } from '.' + +const waterV1 = waterV1Uncasted as LiquidClass + +const defs = { waterV1 } + +export const getAllLiquidClassDefs = (): Record => defs diff --git a/shared-data/js/types.ts b/shared-data/js/types.ts index 71c932a35d4..6abe511bb8f 100644 --- a/shared-data/js/types.ts +++ b/shared-data/js/types.ts @@ -693,6 +693,106 @@ export interface Liquid { displayColor?: string } +// TODO(ND, 12/17/2024): investigate why typescript doesn't allow Array<[number, number]> +type LiquidHandlingPropertyByVolume = number[][] +type PositionReference = + | 'well-bottom' + | 'well-top' + | 'well-center' + | 'liquid-meniscus' +type BlowoutLocation = 'source' | 'destination' | 'trash' +interface DelayParams { + duration: number +} +interface DelayProperties { + enable: boolean + params?: DelayParams +} +interface TouchTipParams { + zOffset: number + mmToEdge: number + speed: number +} +interface TouchTipProperties { + enable: boolean + params?: TouchTipParams +} + +interface MixParams { + repetitions: number + volume: number +} +interface MixProperties { + enable: boolean + params?: MixParams +} +interface BlowoutParams { + location: BlowoutLocation + flowRate: number +} +interface BlowoutProperties { + enable: boolean + params?: BlowoutParams +} +interface Submerge { + positionReference: PositionReference + offset: Coordinates + speed: number + delay: DelayProperties +} +interface BaseRetract { + positionReference: PositionReference + offset: Coordinates + speed: number + airGapByVolume: LiquidHandlingPropertyByVolume + touchTip: TouchTipProperties + delay: DelayProperties +} +type RetractAspirate = BaseRetract +interface RetractDispense extends BaseRetract { + blowout: BlowoutProperties +} +interface BaseLiquidHandlingProperties { + submerge: Submerge + retract: RetractType + positionReference: PositionReference + offset: Coordinates + flowRateByVolume: LiquidHandlingPropertyByVolume + correctionByVolume: LiquidHandlingPropertyByVolume + delay: DelayProperties +} +interface AspirateProperties + extends BaseLiquidHandlingProperties { + preWet: boolean + mix: MixProperties +} +interface SingleDispenseProperties + extends BaseLiquidHandlingProperties { + mix: MixProperties + pushOutByVolume: LiquidHandlingPropertyByVolume +} +interface MultiDispenseProperties { + conditioningByVolume: LiquidHandlingPropertyByVolume + disposalByVolume: LiquidHandlingPropertyByVolume +} +interface ByTipTypeSetting { + tiprack: string + aspirate: AspirateProperties + singleDispense: SingleDispenseProperties + multiDispense?: MultiDispenseProperties +} +interface ByPipetteSetting { + pipetteModel: string + byTipType: ByTipTypeSetting[] +} +export interface LiquidClass { + liquidClassName: string + displayName: string + schemaVersion: number + namespace: string + byPipette: ByPipetteSetting[] +} + export interface AnalysisError { id: string detail: string From 20841218483ba7b9ec590a340c27a72bc8149b6e Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Wed, 18 Dec 2024 09:41:14 -0500 Subject: [PATCH 24/42] fix(app): fix back to back manual move commands on desktop app (#17129) Closes RQA-3728 Since the introduction of the move labware intervention deck map, chaining back to back move interventions has posed a challenge, see comments in #13005. The setTimeout solution proposed in the linked PR effectively worked, and this code looks like it got dropped at some point. However, there are other ways of doing the same thing that are more React Spring-esque, using the API's reset property. --- .../MoveLabwareInterventionContent.tsx | 1 - .../hardware-sim/Deck/MoveLabwareOnDeck.tsx | 34 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx b/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx index af561b6c15d..556c051d32d 100644 --- a/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx +++ b/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx @@ -191,7 +191,6 @@ export function MoveLabwareInterventionContent({ { + if (shouldReset) { + setShouldReset(false) + return + } + + const isNewPosition = + previousInitialRef.current?.x !== initialPosition.x || + previousInitialRef.current?.y !== initialPosition.y || + previousFinalRef.current?.x !== finalPosition.x || + previousFinalRef.current?.y !== finalPosition.y + + if (isNewPosition) { + setShouldReset(true) + } + + previousInitialRef.current = initialPosition + previousFinalRef.current = finalPosition + }, [initialPosition, finalPosition]) + + const previousInitialRef = React.useRef(initialPosition) + const previousFinalRef = React.useRef(finalPosition) + + return shouldReset +} /** * These animated components needs to be split out because react-spring and styled-components don't play nice * @see https://github.com/pmndrs/react-spring/issues/1515 */ From c24cdfb3d1fb65756cc681435f51f97eec65e310 Mon Sep 17 00:00:00 2001 From: Anthony Ngumah <68346382+AnthonyNASC20@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:59:46 -0500 Subject: [PATCH 25/42] feat(abr-testing): pull protocol from failing robot (#17125) Added feature to pull python protocol file from specifed robot with run error, as well as additional error handling # Overview Pulls python protocol file from robot with error and attaches to JIRA ticket. ## Test Plan and Hands on Testing Tested manually --- .../data_collection/abr_robot_error.py | 73 ++++++++++++++++--- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/abr-testing/abr_testing/data_collection/abr_robot_error.py b/abr-testing/abr_testing/data_collection/abr_robot_error.py index 73cf12c6253..75e6bcde34e 100644 --- a/abr-testing/abr_testing/data_collection/abr_robot_error.py +++ b/abr-testing/abr_testing/data_collection/abr_robot_error.py @@ -11,11 +11,35 @@ import sys import json import re +from pathlib import Path import pandas as pd from statistics import mean, StatisticsError from abr_testing.tools import plate_reader +def retrieve_protocol_file( + protocol_id: str, + robot_ip: str, + storage: str, +) -> Path | str: + """Find and copy protocol file on robot with error.""" + protocol_dir = f"/var/lib/opentrons-robot-server/7.1/protocols/{protocol_id}" + + print(f"FILE TO FIND: {protocol_dir}/{protocol_id}") + # Copy protocol file found in robot oto host computer + save_dir = Path(f"{storage}/protocol_errors") + command = ["scp", "-r", f"root@{robot_ip}:{protocol_dir}", save_dir] + try: + # If file found and copied return path to file + subprocess.run(command, check=True) # type: ignore + print("File transfer successful!") + return save_dir + except subprocess.CalledProcessError as e: + print(f"Error during file transfer: {e}") + # Return empty string if file can't be copied + return "" + + def compare_current_trh_to_average( robot: str, start_time: Any, @@ -38,9 +62,13 @@ def compare_current_trh_to_average( # Find average conditions of errored time period df_all_trh = pd.DataFrame(all_trh_data) # Convert timestamps to datetime objects - df_all_trh["Timestamp"] = pd.to_datetime( - df_all_trh["Timestamp"], format="mixed", utc=True - ).dt.tz_localize(None) + print(f'TIMESTAMP: {df_all_trh["Timestamp"]}') + try: + df_all_trh["Timestamp"] = pd.to_datetime( + df_all_trh["Timestamp"], format="mixed", utc=True + ).dt.tz_localize(None) + except Exception: + print(f'The following timestamp is invalid: {df_all_trh["Timestamp"]}') # Ensure start_time is timezone-naive start_time = start_time.replace(tzinfo=None) relevant_temp_rhs = df_all_trh[ @@ -245,9 +273,10 @@ def get_user_id(user_file_path: str, assignee_name: str) -> str: return assignee_id -def get_error_runs_from_robot(ip: str) -> List[str]: +def get_error_runs_from_robot(ip: str) -> Tuple[List[str], List[str]]: """Get runs that have errors from robot.""" error_run_ids = [] + protocol_ids = [] response = requests.get( f"http://{ip}:31950/runs", headers={"opentrons-version": "3"} ) @@ -255,10 +284,13 @@ def get_error_runs_from_robot(ip: str) -> List[str]: run_list = run_data.get("data", []) for run in run_list: run_id = run["id"] + protocol_id = run["protocolId"] num_of_errors = len(run["errors"]) if not run["current"] and num_of_errors > 0: error_run_ids.append(run_id) - return error_run_ids + # Protocol ID will identify the correct folder on the robot of the protocol file + protocol_ids.append(protocol_id) + return (error_run_ids, protocol_ids) def get_robot_state( @@ -335,7 +367,7 @@ def get_robot_state( def get_run_error_info_from_robot( - ip: str, one_run: str, storage_directory: str + ip: str, one_run: str, storage_directory: str, protocol_found: bool ) -> Tuple[str, str, str, List[str], List[str], str, str]: """Get error information from robot to fill out ticket.""" description = dict() @@ -369,6 +401,9 @@ def get_run_error_info_from_robot( description["protocol_name"] = results["protocol"]["metadata"].get( "protocolName", "" ) + + # If Protocol was successfully retrieved from the robot + description["protocol_found_on_robot"] = protocol_found # Get start and end time of run start_time = datetime.strptime( results.get("startedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z" @@ -511,12 +546,21 @@ def get_run_error_info_from_robot( users_file_path = ticket.get_jira_users(storage_directory) assignee_id = get_user_id(users_file_path, assignee) run_log_file_path = "" + protocol_found = False try: - error_runs = get_error_runs_from_robot(ip) + error_runs, protocol_ids = get_error_runs_from_robot(ip) except requests.exceptions.InvalidURL: print("Invalid IP address.") sys.exit() if len(run_or_other) < 1: + # Retrieve the most recently run protocol file + protocol_files_path = retrieve_protocol_file( + protocol_ids[-1], ip, storage_directory + ) + # Set protocol_found to true if python protocol was successfully copied over + if protocol_files_path: + protocol_found = True + one_run = error_runs[-1] # Most recent run with error. ( summary, @@ -526,7 +570,9 @@ def get_run_error_info_from_robot( labels, whole_description_str, run_log_file_path, - ) = get_run_error_info_from_robot(ip, one_run, storage_directory) + ) = get_run_error_info_from_robot( + ip, one_run, storage_directory, protocol_found + ) else: ( summary, @@ -566,8 +612,15 @@ def get_run_error_info_from_robot( # OPEN TICKET issue_url = ticket.open_issue(issue_key) # MOVE FILES TO ERROR FOLDER. + print(protocol_files_path) error_files = [saved_file_path_calibration, run_log_file_path] + file_paths - error_folder_path = os.path.join(storage_directory, issue_key) + + # Move protocol file(s) to error folder + if protocol_files_path: + for file in os.listdir(protocol_files_path): + error_files.append(os.path.join(protocol_files_path, file)) + + error_folder_path = os.path.join(storage_directory, "issue_key") os.makedirs(error_folder_path, exist_ok=True) for source_file in error_files: try: @@ -577,7 +630,7 @@ def get_run_error_info_from_robot( shutil.move(source_file, destination_file) except shutil.Error: continue - # POST FILES TO TICKET + # POST ALL FILES TO TICKET list_of_files = os.listdir(error_folder_path) for file in list_of_files: file_to_attach = os.path.join(error_folder_path, file) From bc17aa4666eabc1736126c89bee1af161d5deae6 Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Wed, 18 Dec 2024 10:16:00 -0500 Subject: [PATCH 26/42] fix(protocol-designer): highlight used wells when selected on step (#17136) closes AUTH-1190 --- .../ProtocolSteps/Timeline/TerminalItemStep.tsx | 2 +- .../src/top-selectors/substep-highlight.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/TerminalItemStep.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/TerminalItemStep.tsx index 39fd70a9f78..ffb13d31a7d 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/TerminalItemStep.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/TerminalItemStep.tsx @@ -1,4 +1,5 @@ import { useSelector, useDispatch } from 'react-redux' +import { useTranslation } from 'react-i18next' import { useConditionalConfirm } from '@opentrons/components' import { getHoveredTerminalItemId, @@ -28,7 +29,6 @@ import type { } from '../../../../ui/steps' import type { TerminalItemId } from '../../../../steplist' import type { ThunkDispatch } from '../../../../types' -import { useTranslation } from 'react-i18next' export interface TerminalItemStepProps { id: TerminalItemId diff --git a/protocol-designer/src/top-selectors/substep-highlight.ts b/protocol-designer/src/top-selectors/substep-highlight.ts index 049bd59e7df..8724f86a909 100644 --- a/protocol-designer/src/top-selectors/substep-highlight.ts +++ b/protocol-designer/src/top-selectors/substep-highlight.ts @@ -4,7 +4,11 @@ import { ALL, COLUMN, getWellNamePerMultiTip } from '@opentrons/shared-data' import * as StepGeneration from '@opentrons/step-generation' import { selectors as stepFormSelectors } from '../step-forms' import { selectors as fileDataSelectors } from '../file-data' -import { getHoveredStepId, getHoveredSubstep } from '../ui/steps' +import { + getHoveredStepId, + getHoveredSubstep, + getSelectedStepId, +} from '../ui/steps' import { getWellSetForMultichannel } from '../utils' import type { WellGroup } from '@opentrons/components' import type { @@ -275,6 +279,7 @@ export const wellHighlightsByLabwareId: Selector< getHoveredSubstep, fileDataSelectors.getSubsteps, stepFormSelectors.getOrderedStepIds, + getSelectedStepId, ( robotStateTimeline, invariantContext, @@ -282,10 +287,11 @@ export const wellHighlightsByLabwareId: Selector< hoveredStepId, hoveredSubstep, substepsById, - orderedStepIds + orderedStepIds, + selectedStepId ) => { const timeline = robotStateTimeline.timeline - const stepId = hoveredStepId + const stepId = hoveredStepId || selectedStepId const timelineIndex = orderedStepIds.findIndex(i => i === stepId) const frame = timeline[timelineIndex] const robotState = frame && frame.robotState From 82aef48e50a9c57f9127d7f5794755dc5a31374a Mon Sep 17 00:00:00 2001 From: Rhyann Clarke <146747548+rclarke0@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:31:56 -0500 Subject: [PATCH 27/42] feat (abr-testing): Lengthen ABR Protocols, Add Protocol Versioning, Add Liquid Waste Probing and Recording (#17137) # Overview ABR Protocol Improvements: Lengthen protocols, Add Version numbers, Add Liquid Waste Probing ## Test Plan and Hands on Testing Protocols have been running for ~ 2-5 days depending on the robot to ensure functionality ## Changelog - The protocol version number is commented at the beginning of the protocol and recorded in the ABR google sheet - All protocols now have a clean up step to move all liquids into liquid waste - At the end of the protocol the liquid waste liquid height is measured in the ABR google sheet ## Review requests ## Risk assessment --------- Co-authored-by: Tony Ngumah --- .../data_collection/abr_google_drive.py | 31 +- .../data_collection/abr_robot_error.py | 14 +- .../data_collection/read_robot_logs.py | 70 +- .../data_collection/single_run_log_reader.py | 5 +- .../10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py | 222 ++-- .../11_Dynabeads_IP_Flex_96well_RIT.py | 212 ++-- .../12_KAPA HyperPlus Library Prep.py | 300 ++--- .../1_Simple Normalize Long Right.py | 288 +++-- .../active_protocols/2_BMS_PCR_Protocol.py | 108 +- .../active_protocols/3_Tartrazine Protocol.py | 206 +++- .../4_Illumina DNA Enrichment.py | 1016 +++++++++++++++++ ...omplex protocol with single tip Pick Up.py | 188 +-- .../6_Omega_HDQ_DNA_Cells-Flex_96_channel.py | 301 +++-- .../7_HDQ_DNA_Bacteria_Flex.py | 115 +- .../8_Illumina and Plate Reader.py | 158 ++- .../9_Magmax_RNA_Cells_Flex.py | 257 +++-- .../protocols/csv_parameters/1_samplevols.csv | 97 ++ .../protocols/csv_parameters/2_samplevols.csv | 96 +- abr-testing/abr_testing/protocols/helpers.py | 180 ++- .../10_ZymoBIOMICS Magbead Liquid Setup.py | 31 +- .../11_Dynabeads RIT Liquid Setup.py | 25 +- ...APA HyperPlus Library Prep Liquid Setup.py | 2 +- .../1_Simple normalize long Liquid Setup.py | 14 +- .../2_BMS_PCR_protocol Liquid Setup.py | 10 +- .../3_Tartrazine Liquid Setup.py | 91 +- .../4_Illumina DNA Enrichment Liquid Setup.py | 25 +- .../5_96ch Complex Protocol Liquid Setup.py | 10 +- ...DQ DNA Bacteria Extraction Liquid Setup.py | 34 +- ...ermo MagMax RNA Extraction Liquid Setup.py | 49 +- .../test_protocols/tc_lid_x_offset_test.py | 14 +- abr-testing/abr_testing/tools/abr_scale.py | 14 +- abr-testing/abr_testing/tools/abr_setup.py | 8 +- 32 files changed, 2993 insertions(+), 1198 deletions(-) create mode 100644 abr-testing/abr_testing/protocols/active_protocols/4_Illumina DNA Enrichment.py create mode 100644 abr-testing/abr_testing/protocols/csv_parameters/1_samplevols.csv diff --git a/abr-testing/abr_testing/data_collection/abr_google_drive.py b/abr-testing/abr_testing/data_collection/abr_google_drive.py index 8f82567a7d1..655200745a9 100644 --- a/abr-testing/abr_testing/data_collection/abr_google_drive.py +++ b/abr-testing/abr_testing/data_collection/abr_google_drive.py @@ -34,16 +34,13 @@ def create_data_dictionary( runs_to_save: Union[Set[str], str], storage_directory: str, issue_url: str, - plate: str, - accuracy: Any, hellma_plate_standards: List[Dict[str, Any]], -) -> Tuple[List[List[Any]], List[str], List[List[Any]], List[str], List[List[Any]]]: +) -> Tuple[List[List[Any]], List[str], List[List[Any]], List[str]]: """Pull data from run files and format into a dictionary.""" runs_and_robots: List[Any] = [] runs_and_lpc: List[Dict[str, Any]] = [] headers: List[str] = [] headers_lpc: List[str] = [] - list_of_heights: List[List[Any]] = [[], [], [], [], [], [], [], []] hellma_plate_orientation = False # default hellma plate is not rotated. for filename in os.listdir(storage_directory): file_path = os.path.join(storage_directory, filename) @@ -103,12 +100,15 @@ def create_data_dictionary( run_time_min = run_time.total_seconds() / 60 except ValueError: pass # Handle datetime parsing errors if necessary + # Get protocol version # + version_number = read_robot_logs.get_protocol_version_number(file_results) if run_time_min > 0: run_row = { "Robot": robot, "Run_ID": run_id, "Protocol_Name": protocol_name, + "Protocol Version": version_number, "Software Version": software_version, "Date": start_date, "Start_Time": start_time_str, @@ -130,13 +130,10 @@ def create_data_dictionary( plate_reader_dict = read_robot_logs.plate_reader_commands( file_results, hellma_plate_standards, hellma_plate_orientation ) - list_of_heights = read_robot_logs.liquid_height_commands( - file_results, list_of_heights - ) notes = {"Note1": "", "Jira Link": issue_url} + liquid_height = read_robot_logs.get_liquid_waste_height(file_results) plate_measure = { - "Plate Measured": plate, - "End Volume Accuracy (%)": accuracy, + "Liquid Waste Height (mm)": liquid_height, "Average Temp (oC)": "", "Average RH(%)": "", } @@ -173,7 +170,6 @@ def create_data_dictionary( headers, transposed_runs_and_lpc, headers_lpc, - list_of_heights, ) @@ -211,26 +207,15 @@ def run( headers, transposed_runs_and_lpc, headers_lpc, - list_of_heights, ) = create_data_dictionary( missing_runs_from_gs, storage_directory, "", - "", - "", - hellma_plate_standards=file_values, + file_values, ) start_row = google_sheet.get_index_row() + 1 google_sheet.batch_update_cells(transposed_runs_and_robots, "A", start_row, "0") - # Record Liquid Heights Found - google_sheet_ldf = google_sheets_tool.google_sheet( - credentials_path, google_sheet_name, 2 - ) - google_sheet_ldf.get_row(1) - start_row_lhd = google_sheet_ldf.get_index_row() + 1 - google_sheet_ldf.batch_update_cells( - list_of_heights, "A", start_row_lhd, "2075262446" - ) + # Add LPC to google sheet google_sheet_lpc = google_sheets_tool.google_sheet(credentials_path, "ABR-LPC", 0) start_row_lpc = google_sheet_lpc.get_index_row() + 1 diff --git a/abr-testing/abr_testing/data_collection/abr_robot_error.py b/abr-testing/abr_testing/data_collection/abr_robot_error.py index 75e6bcde34e..c2dadaae54c 100644 --- a/abr-testing/abr_testing/data_collection/abr_robot_error.py +++ b/abr-testing/abr_testing/data_collection/abr_robot_error.py @@ -667,28 +667,16 @@ def get_run_error_info_from_robot( headers, runs_and_lpc, headers_lpc, - list_of_heights, ) = abr_google_drive.create_data_dictionary( run_id, error_folder_path, issue_url, - "", - "", - hellma_plate_standards=file_values, + file_values, ) start_row = google_sheet.get_index_row() + 1 google_sheet.batch_update_cells(runs_and_robots, "A", start_row, "0") print("Wrote run to ABR-run-data") - # Record Liquid Heights Found - google_sheet_ldf = google_sheets_tool.google_sheet( - credentials_path, google_sheet_name, 4 - ) - start_row_lhd = google_sheet_ldf.get_index_row() + 1 - google_sheet_ldf.batch_update_cells( - list_of_heights, "A", start_row_lhd, "1795535088" - ) - print("wrote liquid heights found.") # Add LPC to google sheet google_sheet_lpc = google_sheets_tool.google_sheet( credentials_path, "ABR-LPC", 0 diff --git a/abr-testing/abr_testing/data_collection/read_robot_logs.py b/abr-testing/abr_testing/data_collection/read_robot_logs.py index 7bc83e0a54b..0a098835cf7 100644 --- a/abr-testing/abr_testing/data_collection/read_robot_logs.py +++ b/abr-testing/abr_testing/data_collection/read_robot_logs.py @@ -134,7 +134,8 @@ def match_pipette_to_action( left_pipette_add = 0 for command in commandTypes: command_type = command_dict["commandType"] - command_pipette = command_dict.get("pipetteId", "") + command_params = command_dict.get("params", "") + command_pipette = command_params.get("pipetteId", "") if command_type == command and command_pipette == right_pipette: right_pipette_add = 1 elif command_type == command and command_pipette == left_pipette: @@ -213,6 +214,35 @@ def instrument_commands( return pipette_dict +def get_comment_result_by_string(file_results: Dict[str, Any], key_phrase: str) -> str: + """Get comment string based off ky phrase.""" + commandData = file_results.get("commands", "") + result_str = command_str = "" + for command in commandData: + commandType = command["commandType"] + if commandType == "comment": + command_str = command["params"].get("message", "") + try: + result_str = command_str.split(key_phrase)[1] + except IndexError: + continue + return result_str + + +def get_protocol_version_number(file_results: Dict[str, Any]) -> str: + """Get protocol version number.""" + return get_comment_result_by_string(file_results, "Protocol Version: ") + + +def get_liquid_waste_height(file_results: Dict[str, Any]) -> float: + """Find liquid waste height.""" + result_str = get_comment_result_by_string( + file_results, "Liquid Waste Total Height: " + ) + height = float(result_str) + return height + + def liquid_height_commands( file_results: Dict[str, Any], all_heights_list: List[List[Any]] ) -> List[List[Any]]: @@ -220,6 +250,9 @@ def liquid_height_commands( commandData = file_results.get("commands", "") robot = file_results.get("robot_name", "") run_id = file_results.get("run_id", "") + list_of_heights = [] + print(robot) + liquid_waste_height = 0.0 for command in commandData: commandType = command["commandType"] if commandType == "comment": @@ -236,16 +269,24 @@ def liquid_height_commands( well_location = str(entry.split(", ")[1].split(" ")[0]) slot_location = str(entry.split("slot ")[1].split(")")[0]) labware_name = str(entry.split("of ")[1].split(" on")[0]) - all_heights_list[0].append(robot) - all_heights_list[1].append(run_id) - all_heights_list[2].append(comment_time) - all_heights_list[3].append(labware_type) - all_heights_list[4].append(labware_name) - all_heights_list[5].append(slot_location) - all_heights_list[6].append(well_location) - all_heights_list[7].append(height) + if labware_name == "Liquid Waste": + liquid_waste_height += height + one_entry = { + "Timestamp": comment_time, + "Labware Name": labware_name, + "Labware Type": labware_type, + "Slot Location": slot_location, + "Well Location": well_location, + "All Heights (mm)": height, + } + list_of_heights.append(one_entry) except (IndexError, ValueError): continue + if len(list_of_heights) > 0: + all_heights_list[0].append(robot) + all_heights_list[1].append(run_id) + all_heights_list[2].append(list_of_heights) + all_heights_list[3].append(liquid_waste_height) return all_heights_list @@ -281,10 +322,13 @@ def plate_reader_commands( read = "yes" elif read == "yes" and commandType == "comment": result = command["params"].get("message", "") - if "result:" in result: - plate_name = result.split("result:")[0] - formatted_result = result.split("result: ")[1] - print(formatted_result) + if "result:" in result or "Result:" in result: + try: + plate_name = result.split("result:")[0] + formatted_result = result.split("result: ")[1] + except IndexError: + plate_name = result.split("Result:")[0] + formatted_result = result.split("Result: ")[1] result_dict = eval(formatted_result) result_dict_keys = list(result_dict.keys()) if len(result_dict_keys) > 1: diff --git a/abr-testing/abr_testing/data_collection/single_run_log_reader.py b/abr-testing/abr_testing/data_collection/single_run_log_reader.py index a61670e6d12..bf10347faff 100644 --- a/abr-testing/abr_testing/data_collection/single_run_log_reader.py +++ b/abr-testing/abr_testing/data_collection/single_run_log_reader.py @@ -34,14 +34,11 @@ header, runs_and_lpc, lpc_headers, - list_of_heights, ) = abr_google_drive.create_data_dictionary( run_ids_in_storage, run_log_file_path, "", - "", - "", - hellma_plate_standards=file_values, + file_values, ) print("list_of_heights not recorded.") transposed_list = list(zip(*runs_and_robots)) diff --git a/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py b/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py index 9631b442694..9e93e597bbd 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py +++ b/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py @@ -17,7 +17,7 @@ "protocolName": "Flex ZymoBIOMICS Magbead DNA Extraction: Cells", } -requirements = {"robotType": "OT-3", "apiLevel": "2.21"} +requirements = {"robotType": "Flex", "apiLevel": "2.21"} """ Slot A1: Tips 1000 Slot A2: Tips 1000 @@ -41,11 +41,12 @@ Wells 1-12 - 9,000 ul """ -whichwash = 1 +whichwash = 0 +wash_volume_tracker = 0.0 sample_max = 48 tip1k = 0 -tip200 = 0 drop_count = 0 +m1000_tips = 0 def add_parameters(parameters: protocol_api.ParameterContext) -> None: @@ -53,28 +54,40 @@ def add_parameters(parameters: protocol_api.ParameterContext) -> None: helpers.create_hs_speed_parameter(parameters) helpers.create_single_pipette_mount_parameter(parameters) helpers.create_dot_bottom_parameter(parameters) + helpers.create_deactivate_modules_parameter(parameters) -def run(ctx: protocol_api.ProtocolContext) -> None: +def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol Set Up.""" - heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] - mount = ctx.params.pipette_mount # type: ignore[attr-defined] - dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] + heater_shaker_speed = protocol.params.heater_shaker_speed # type: ignore[attr-defined] + mount = protocol.params.pipette_mount # type: ignore[attr-defined] + dot_bottom = protocol.params.dot_bottom # type: ignore[attr-defined] + deactivate_modules_bool = protocol.params.deactivate_modules # type: ignore[attr-defined] + helpers.comment_protocol_version(protocol, "01") + dry_run = False TIP_TRASH = ( False # True = Used tips go in Trash, False = Used tips go back into rack ) res_type = "nest_12_reservoir_15ml" - - num_samples = 8 - wash1_vol = 500.0 - wash2_vol = wash3_vol = 900.0 - lysis_vol = 200.0 + global m1000_tips + num_samples = 96 + wash1_vol = wash2_vol = wash3_vol = 400.0 + lysis_vol = 90.0 sample_vol = 10.0 # Sample should be pelleted tissue/bacteria/cells bind_vol = 600.0 bind2_vol = 500.0 elution_vol = 75.0 + def tipcheck(m1000: InstrumentContext) -> None: + """Tip tracking function.""" + global m1000_tips + if m1000_tips >= 3 * 96: + m1000.reset_tipracks() + m1000_tips == 0 + m1000.pick_up_tip() + m1000_tips += 8 + # Protocol Parameters deepwell_type = "nest_96_wellplate_2ml_deep" @@ -97,37 +110,41 @@ def run(ctx: protocol_api.ProtocolContext) -> None: bead_vol = 25.0 starting_vol = lysis_vol + sample_vol binding_buffer_vol = bind_vol + bead_vol - ctx.load_trash_bin("A3") - h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] + protocol.load_trash_bin("A3") + h_s: HeaterShakerContext = protocol.load_module( + helpers.hs_str, "D1" + ) # type: ignore[assignment] labware_name = "Samples" sample_plate, h_s_adapter = helpers.load_hs_adapter_and_labware( deepwell_type, h_s, labware_name ) h_s.close_labware_latch() - temp: TemperatureModuleContext = ctx.load_module( + temp: TemperatureModuleContext = protocol.load_module( helpers.temp_str, "D3" ) # type: ignore[assignment] elutionplate, temp_adapter = helpers.load_temp_adapter_and_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", temp, "Elution Plate" ) - magblock: MagneticBlockContext = ctx.load_module( + magblock: MagneticBlockContext = protocol.load_module( helpers.mag_str, "C1" ) # type: ignore[assignment] - waste_reservoir = ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + waste_reservoir = protocol.load_labware( + "nest_1_reservoir_290ml", "B3", "Liquid Waste" + ) waste = waste_reservoir.wells()[0].top() - res1 = ctx.load_labware(res_type, "D2", "reagent reservoir 1") - res2 = ctx.load_labware(res_type, "C2", "reagent reservoir 2") + res1 = protocol.load_labware(res_type, "D2", "reagent reservoir 1") + res2 = protocol.load_labware(res_type, "C2", "reagent reservoir 2") + res3 = protocol.load_labware(res_type, "B2", "reagent reservoir 3") num_cols = math.ceil(num_samples / 8) # Load tips and combine all similar boxes - tips1000 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "A1", "Tips 1") - tips1001 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "A2", "Tips 2") - tips1002 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "B1", "Tips 3") - tips = [*tips1000.wells()[num_samples:96], *tips1001.wells(), *tips1002.wells()] + tips1000 = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "A1", "Tips 1") + tips1001 = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "A2", "Tips 2") + tips1002 = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "B1", "Tips 3") tips_sn = tips1000.wells()[:num_samples] # load instruments - m1000 = ctx.load_instrument( + m1000 = protocol.load_instrument( "flex_8channel_1000", mount, tip_racks=[tips1000, tips1001, tips1002] ) @@ -135,50 +152,32 @@ def run(ctx: protocol_api.ProtocolContext) -> None: Here is where you can define the locations of your reagents. """ lysis_ = res1.wells()[0] - binding_buffer = res1.wells()[1:4] - bind2_res = res1.wells()[4:8] - wash1 = res1.wells()[6:8] - elution_solution = res1.wells()[-1] - wash2 = res2.wells()[:6] - wash3 = res2.wells()[6:] - + binding_buffer = res1.wells()[1:8] + bind2_res = res1.wells()[8:12] + all_washes = res2.wells()[1:] + elution_solution = res2.wells()[0] + all_washes.extend(res3.wells()[:2]) samples_m = sample_plate.rows()[0][:num_cols] elution_samples_m = elutionplate.rows()[0][:num_cols] # Redefine per well for liquid definitions samps = sample_plate.wells()[: (8 * num_cols)] - liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { "Lysis and PK": [{"well": lysis_, "volume": 12320.0}], "Beads and Binding": [{"well": binding_buffer, "volume": 11875.0}], "Binding 2": [{"well": bind2_res, "volume": 13500.0}], - "Final Elution": [{"well": elution_solution, "volume": 52000}], + "Final Elution": [{"well": elution_solution, "volume": 1200.0}], "Samples": [{"well": samps, "volume": 0.0}], - "Reagents": [{"well": res2.wells(), "volume": 9000.0}], + "Reagents": [{"well": all_washes, "volume": 9800.0}], } - flattened_list_of_wells = helpers.find_liquid_height_of_loaded_liquids( - ctx, liquid_vols_and_wells, m1000 - ) + helpers.find_liquid_height_of_loaded_liquids(protocol, liquid_vols_and_wells, m1000) m1000.flow_rate.aspirate = 300 m1000.flow_rate.dispense = 300 m1000.flow_rate.blow_out = 300 - def tiptrack(tipbox: List[Well]) -> None: - """Track Tips.""" - global tip1k - global drop_count - if tipbox == tips: - m1000.pick_up_tip(tipbox[int(tip1k)]) - tip1k = tip1k + 8 - - drop_count = drop_count + 8 - if drop_count >= 150: - drop_count = 0 - ctx.pause("Please empty the waste bin of all the tips before continuing.") - def remove_supernatant(vol: float) -> None: """Remove supernatant.""" - ctx.comment("-----Removing Supernatant-----") + protocol.comment("-----Removing Supernatant-----") m1000.flow_rate.aspirate = 30 num_trans = math.ceil(vol / 980) vol_per_trans = vol / num_trans @@ -198,7 +197,7 @@ def remove_supernatant(vol: float) -> None: m1000.flow_rate.aspirate = 300 # Transfer from Magdeck plate to H-S - helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + helpers.move_labware_to_hs(protocol, sample_plate, h_s, h_s_adapter) def bead_mixing( well: Well, pip: InstrumentContext, mvol: float, reps: int = 8 @@ -261,6 +260,7 @@ def mixing(well: Well, pip: InstrumentContext, mvol: float, reps: int = 8) -> No dispensing at the top and 2 cycles of aspirating from middle, dispensing at the bottom """ + pip.liquid_presence_detection = False center = well.top(5) asp = well.bottom(1) disp = well.top(-8) @@ -290,15 +290,18 @@ def mixing(well: Well, pip: InstrumentContext, mvol: float, reps: int = 8) -> No def lysis(vol: float, source: Well) -> None: """Lysis.""" - ctx.comment("-----Beginning Lysis Steps-----") - ctx.pause(msg="\n Hello \n - step 1 \n - step 2") + protocol.comment("-----Beginning Lysis Steps-----") num_transfers = math.ceil(vol / 980) - tiptrack(tips) + tipcheck(m1000) + total_lysis_aspirated = 0.0 for i in range(num_cols): src = source tvol = vol / num_transfers # Mix Shield and PK before transferring first time if i == 0: + m1000.liquid_presence_detection = ( + False # turn off liquid detection during mixing + ) for x in range(lysis_rep_1): m1000.aspirate(vol, src.bottom(1)) m1000.dispense(vol, src.bottom(8)) @@ -308,15 +311,14 @@ def lysis(vol: float, source: Well) -> None: m1000.aspirate(tvol, src.bottom(1)) m1000.air_gap(10) m1000.dispense(m1000.current_volume, samples_m[i].top()) - + total_lysis_aspirated += tvol * 8 # Mix shield and pk with samples for i in range(num_cols): if i != 0: - tiptrack(tips) + tipcheck(m1000) mixing(samples_m[i], m1000, tvol, reps=lysis_rep_2) m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, lysis_incubation, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, lysis_incubation, True) def bind(vol1: float, vol2: float) -> None: """Binding. @@ -334,9 +336,9 @@ def bind(vol1: float, vol2: float) -> None: supernatant to the final clean elutions PCR plate. """ - ctx.comment("-----Beginning Binding Steps-----") + protocol.comment("-----Beginning Binding Steps-----") for i, well in enumerate(samples_m): - tiptrack(tips) + tipcheck(m1000) num_trans = math.ceil(vol1 / 980) vol_per_trans = vol1 / num_trans source = binding_buffer[i // 2] @@ -360,15 +362,19 @@ def bind(vol1: float, vol2: float) -> None: m1000.air_gap(10) m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed * 0.9, bind_time_1, True) + helpers.set_hs_speed( + protocol, h_s, heater_shaker_speed * 0.9, bind_time_1, True + ) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) for bindi in np.arange( settling_time + 1, 0, -0.5 ): # Settling time delay with countdown timer - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(bindi) + " minutes left in the incubation.", ) @@ -376,8 +382,8 @@ def bind(vol1: float, vol2: float) -> None: # remove initial supernatant remove_supernatant(vol1 + starting_vol) - ctx.comment("-----Beginning Bind #2 Steps-----") - tiptrack(tips) + protocol.comment("-----Beginning Bind #2 Steps-----") + tipcheck(m1000) for i, well in enumerate(samples_m): num_trans = math.ceil(vol2 / 980) vol_per_trans = vol2 / num_trans @@ -402,20 +408,22 @@ def bind(vol1: float, vol2: float) -> None: for i in range(num_cols): if i != 0: - tiptrack(tips) + tipcheck(m1000) bead_mixing( samples_m[i], m1000, vol_per_trans, reps=3 if not dry_run else 1 ) m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, bind_time_2, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, bind_time_2, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) for bindi in np.arange( settling_time + 1, 0, -0.5 ): # Settling time delay with countdown timer - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(bindi) + " minutes left in the incubation.", ) @@ -426,52 +434,43 @@ def bind(vol1: float, vol2: float) -> None: def wash(vol: float, source: List[Well]) -> None: """Wash Steps.""" global whichwash # Defines which wash the protocol is on to log on the app - - if source == wash1: - whichwash = 1 - const = 6 // len(source) - if source == wash2: - whichwash = 2 - const = 6 // len(source) - height = 1 - if source == wash3: - whichwash = 3 - const = 6 // len(source) - height = 1 - - ctx.comment("-----Wash #" + str(whichwash) + " is starting now------") + protocol.comment("-----Now starting Wash #" + str(whichwash) + "-----") + global wash_volume_tracker num_trans = math.ceil(vol / 980) vol_per_trans = vol / num_trans - tiptrack(tips) + tipcheck(m1000) for i, m in enumerate(samples_m): - if source == wash1: - if i == 0 or i == 3: - height = 10 - else: - height = 1 - src = source[i // const] + src = source[whichwash] for n in range(num_trans): if m1000.current_volume > 0: m1000.dispense(m1000.current_volume, src.top()) m1000.require_liquid_presence(src) m1000.transfer( vol_per_trans, - src.bottom(height), + src.bottom(dot_bottom), m.top(), air_gap=20, new_tip="never", ) + wash_volume_tracker += vol_per_trans * 8 + if wash_volume_tracker >= 9600: + whichwash += 1 + src = source[whichwash] + protocol.comment(f"new wash source {whichwash}") + wash_volume_tracker = 0.0 m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed * 0.9, wash_time, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed * 0.9, wash_time, True) - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) for washi in np.arange( settling_time, 0, -0.5 ): # settling time timer for washes - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(washi) @@ -483,27 +482,31 @@ def wash(vol: float, source: List[Well]) -> None: remove_supernatant(vol) def elute(vol: float) -> None: - tiptrack(tips) + tipcheck(m1000) + total_elution_vol = 0.0 for i, m in enumerate(samples_m): m1000.require_liquid_presence(elution_solution) m1000.aspirate(vol, elution_solution) m1000.air_gap(20) m1000.dispense(m1000.current_volume, m.top(-3)) + total_elution_vol += vol m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed * 0.9, wash_time, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed * 0.9, wash_time, True) # Transfer back to magnet - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) for elutei in np.arange(settling_time, 0, -0.5): - ctx.delay( + protocol.delay( minutes=0.5, msg="Incubating on MagDeck for " + str(elutei) + " more minutes.", ) for i, (m, e) in enumerate(zip(samples_m, elution_samples_m)): - tiptrack(tips) + tipcheck(m1000) m1000.flow_rate.dispense = 100 m1000.flow_rate.aspirate = 25 m1000.transfer( @@ -521,16 +524,23 @@ def elute(vol: float) -> None: """ lysis(lysis_vol, lysis_) bind(binding_buffer_vol, bind2_vol) - wash(wash1_vol, wash1) - wash(wash2_vol, wash2) - wash(wash3_vol, wash3) + wash(wash1_vol, all_washes) + wash(wash2_vol, all_washes) + wash(wash3_vol, all_washes) h_s.set_and_wait_for_temperature(55) for beaddry in np.arange(drybeads, 0, -0.5): - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(beaddry) + " minutes left in the drying step.", ) elute(elution_vol) h_s.deactivate_heater() - flattened_list_of_wells.extend([waste_reservoir["A1"], elutionplate["A1"]]) - helpers.find_liquid_height_of_all_wells(ctx, m1000, flattened_list_of_wells) + helpers.clean_up_plates( + m1000, + [elutionplate, sample_plate, res1, res3, res2], + waste_reservoir["A1"], + 1000, + ) + helpers.find_liquid_height_of_all_wells(protocol, m1000, [waste_reservoir["A1"]]) + if deactivate_modules_bool: + helpers.deactivate_modules(protocol) diff --git a/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py b/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py index e885ec45a5e..44db654cc1f 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py +++ b/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py @@ -1,5 +1,5 @@ """Immunoprecipitation by Dynabeads.""" -from opentrons.protocol_api import ProtocolContext, ParameterContext, Well +from opentrons.protocol_api import ProtocolContext, ParameterContext, Well, Labware from opentrons.protocol_api.module_contexts import ( HeaterShakerContext, TemperatureModuleContext, @@ -15,7 +15,7 @@ } requirements = { - "robotType": "OT-3", + "robotType": "Flex", "apiLevel": "2.21", } @@ -25,6 +25,7 @@ def add_parameters(parameters: ParameterContext) -> None: helpers.create_hs_speed_parameter(parameters) helpers.create_two_pipette_mount_parameters(parameters) helpers.create_dot_bottom_parameter(parameters) + helpers.create_deactivate_modules_parameter(parameters) NUM_COL = 12 @@ -34,7 +35,7 @@ def add_parameters(parameters: ParameterContext) -> None: BEADS_VOL = 50 AB_VOL = 50 SAMPLE_VOL = 200 -WASH_TIMES = 3 +WASH_TIMES = 6 WASH_VOL = 200 ELUTION_VOL = 50 @@ -48,64 +49,78 @@ def add_parameters(parameters: ParameterContext) -> None: TIP_TRASH = False -def run(ctx: ProtocolContext) -> None: +def run(protocol: ProtocolContext) -> None: """Protocol.""" # defining variables inside def run - heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] - ASP_HEIGHT = ctx.params.dot_bottom # type: ignore[attr-defined] - single_channel_mount = ctx.params.pipette_mount_1 # type: ignore[attr-defined] - eight_channel_mount = ctx.params.pipette_mount_2 # type: ignore[attr-defined] + heater_shaker_speed = protocol.params.heater_shaker_speed # type: ignore[attr-defined] + ASP_HEIGHT = protocol.params.dot_bottom # type: ignore[attr-defined] + single_channel_mount = protocol.params.pipette_mount_1 # type: ignore[attr-defined] + eight_channel_mount = protocol.params.pipette_mount_2 # type: ignore[attr-defined] + deactivate_modules_bool = protocol.params.deactivate_modules # type: ignore[attr-defined] + helpers.comment_protocol_version(protocol, "01") + MIX_SPEED = heater_shaker_speed MIX_SEC = 10 # if on deck: - INCUBATION_SPEEND = heater_shaker_speed * 0.5 + INCUBATION_SPEED = heater_shaker_speed * 0.5 INCUBATION_MIN = 60 # load labware - sample_plate = ctx.load_labware("nest_96_wellplate_2ml_deep", "B2", "samples") - wash_res = ctx.load_labware("nest_12_reservoir_15ml", "B1", "wash") - reagent_res = ctx.load_labware( + sample_plate_1 = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "B2", "sample plate 1" + ) + sample_plate_2 = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "C4", "sample plate 2" + ) + + wash_res = protocol.load_labware("nest_12_reservoir_15ml", "B1", "wash") + reagent_res = protocol.load_labware( "opentrons_15_tuberack_nest_15ml_conical", "C3", "reagents" ) - waste_res = ctx.load_labware("nest_1_reservoir_290ml", "D2", "waste") + waste_res = protocol.load_labware("nest_1_reservoir_290ml", "D2", "Liquid Waste") - tips = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "B3") - tips_sample = ctx.load_labware( + tips = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "B3") + tips_sample = protocol.load_labware( "opentrons_flex_96_tiprack_1000ul", "A2", "sample tips" ) tips_sample_loc = tips_sample.wells()[:95] if READY_FOR_SDSPAGE == 0: - tips_elu = ctx.load_labware( + tips_elu = protocol.load_labware( "opentrons_flex_96_tiprack_1000ul", "A1", "elution tips" ) tips_elu_loc = tips_elu.wells()[:95] - tips_reused = ctx.load_labware( + tips_reused = protocol.load_labware( "opentrons_flex_96_tiprack_1000ul", "C2", "reused tips" ) tips_reused_loc = tips_reused.wells()[:95] - p1000 = ctx.load_instrument( + p1000 = protocol.load_instrument( "flex_8channel_1000", eight_channel_mount, tip_racks=[tips] ) - p1000_single = ctx.load_instrument( + p1000_single = protocol.load_instrument( "flex_1channel_1000", single_channel_mount, tip_racks=[tips] ) - h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] + h_s: HeaterShakerContext = protocol.load_module( + helpers.hs_str, "D1" + ) # type: ignore[assignment] working_plate, h_s_adapter = helpers.load_hs_adapter_and_labware( "nest_96_wellplate_2ml_deep", h_s, "Working Plate" ) if READY_FOR_SDSPAGE == 0: - temp: TemperatureModuleContext = ctx.load_module( + temp: TemperatureModuleContext = protocol.load_module( helpers.temp_str, "D3" ) # type: ignore[assignment] final_plate, temp_adapter = helpers.load_temp_adapter_and_labware( "nest_96_wellplate_2ml_deep", temp, "Final Plate" ) - mag: MagneticBlockContext = ctx.load_module(helpers.mag_str, "C1") # type: ignore[assignment] + mag: MagneticBlockContext = protocol.load_module( + helpers.mag_str, "C1" + ) # type: ignore[assignment] # liquids - samples = sample_plate.rows()[0][:NUM_COL] # 1 + samples1 = sample_plate_1.rows()[0][:NUM_COL] # 1 + samples2 = sample_plate_2.rows()[0][:NUM_COL] # 1 beads = reagent_res.wells()[0] # 2 ab = reagent_res.wells()[1] # 3 elu = reagent_res.wells()[2] # 4 @@ -119,14 +134,15 @@ def run(ctx: ProtocolContext) -> None: liquid_vols_and_wells: Dict[ str, List[Dict[str, Union[Well, List[Well], float]]] ] = { - "Beads": [{"well": beads, "volume": 4900.0}], - "AB": [{"well": ab, "volume": 4900.0}], - "Elution": [{"well": elu, "volume": 4900.0}], - "Wash": [{"well": wash, "volume": 750.0}], - "Samples": [{"well": samples, "volume": 250.0}], + "Beads": [{"well": beads, "volume": 9800.0}], + "AB": [{"well": ab, "volume": 9800.0}], + "Elution": [{"well": elu, "volume": 9800.0}], + "Wash": [{"well": wash, "volume": 1500.0}], + "Samples 1": [{"well": samples1, "volume": 250.0}], + "Samples 2": [{"well": samples2, "volume": 250.0}], } helpers.find_liquid_height_of_loaded_liquids( - ctx, liquid_vols_and_wells, p1000_single + protocol, liquid_vols_and_wells, p1000_single ) def transfer_plate_to_plate( @@ -193,9 +209,6 @@ def discard(vol3: float, start: List[Well]) -> None: """Discard function.""" global waste_vol global waste_vol_chk - if waste_vol_chk >= WASTE_VOL_MAX: - ctx.pause("Empty Liquid Waste") - waste_vol_chk = 0 waste_vol = 0.0 for k in range(NUM_COL): p1000.pick_up_tip(tips_reused_loc[k * 8]) @@ -210,64 +223,77 @@ def discard(vol3: float, start: List[Well]) -> None: waste_vol_chk = waste_vol_chk + waste_vol # protocol - - # Add beads, samples and antibody solution - h_s.close_labware_latch() - transfer_well_to_plate(BEADS_VOL, beads, working_wells, 2) - - helpers.move_labware_from_hs_to_destination(ctx, working_plate, h_s, mag) - - ctx.delay(minutes=MAG_DELAY_MIN) - discard(BEADS_VOL * 1.1, working_cols) - - helpers.move_labware_to_hs(ctx, working_plate, h_s, h_s_adapter) - - transfer_plate_to_plate(SAMPLE_VOL, samples, working_cols, 1) - transfer_well_to_plate(AB_VOL, ab, working_wells, 3) - - h_s.set_and_wait_for_shake_speed(rpm=MIX_SPEED) - ctx.delay(seconds=MIX_SEC) - - h_s.set_and_wait_for_shake_speed(rpm=INCUBATION_SPEEND) - ctx.delay(seconds=INCUBATION_MIN * 60) - h_s.deactivate_shaker() - - helpers.move_labware_from_hs_to_destination(ctx, working_plate, h_s, mag) - - ctx.delay(minutes=MAG_DELAY_MIN) - vol_total = SAMPLE_VOL + AB_VOL - discard(vol_total * 1.1, working_cols) - - # Wash - for _ in range(WASH_TIMES): - helpers.move_labware_to_hs(ctx, working_plate, h_s, h_s_adapter) - - transfer_well_to_plate(WASH_VOL, wash, working_cols, 5) - helpers.set_hs_speed(ctx, h_s, MIX_SPEED, MIX_SEC / 60, True) - helpers.move_labware_from_hs_to_destination(ctx, working_plate, h_s, mag) - ctx.delay(minutes=MAG_DELAY_MIN) - discard(WASH_VOL * 1.1, working_cols) - - # Elution - helpers.move_labware_to_hs(ctx, working_plate, h_s, h_s_adapter) - - transfer_well_to_plate(ELUTION_VOL, elu, working_wells, 4) - if READY_FOR_SDSPAGE == 1: - ctx.pause("Seal the Working Plate") - h_s.set_and_wait_for_temperature(70) - helpers.set_hs_speed(ctx, h_s, MIX_SPEED, (MIX_SEC / 60) + 10, True) - h_s.deactivate_heater() - h_s.open_labware_latch() - ctx.pause("Protocol Complete") - - elif READY_FOR_SDSPAGE == 0: - helpers.set_hs_speed(ctx, h_s, MIX_SPEED, (MIX_SEC / 60) + 2, True) - - temp.set_temperature(4) - helpers.move_labware_from_hs_to_destination(ctx, working_plate, h_s, mag) - ctx.delay(minutes=MAG_DELAY_MIN) - transfer_plate_to_plate(ELUTION_VOL * 1.1, working_cols, final_cols, 6) - temp.deactivate() - end_wells_to_probe = [reagent_res["A1"], reagent_res["B1"], reagent_res["C1"]] - end_wells_to_probe.extend(wash_res.wells()) - helpers.find_liquid_height_of_all_wells(ctx, p1000_single, end_wells_to_probe) + def run(sample_plate: Labware) -> None: + """Protocol.""" + # Add beads, samples and antibody solution + samples = sample_plate.rows()[0][:NUM_COL] # 1 + h_s.close_labware_latch() + transfer_well_to_plate(BEADS_VOL, beads, working_wells, 2) + + helpers.move_labware_from_hs_to_destination(protocol, working_plate, h_s, mag) + + protocol.delay(minutes=MAG_DELAY_MIN) + discard(BEADS_VOL * 1.1, working_cols) + + helpers.move_labware_to_hs(protocol, working_plate, h_s, h_s_adapter) + + transfer_plate_to_plate(SAMPLE_VOL, samples, working_cols, 1) + transfer_well_to_plate(AB_VOL, ab, working_wells, 3) + + h_s.set_and_wait_for_shake_speed(rpm=MIX_SPEED) + protocol.delay(seconds=MIX_SEC) + + h_s.set_and_wait_for_shake_speed(rpm=INCUBATION_SPEED) + protocol.delay(seconds=INCUBATION_MIN * 60) + h_s.deactivate_shaker() + + helpers.move_labware_from_hs_to_destination(protocol, working_plate, h_s, mag) + + protocol.delay(minutes=MAG_DELAY_MIN) + vol_total = SAMPLE_VOL + AB_VOL + discard(vol_total * 1.1, working_cols) + + # Wash + for _ in range(WASH_TIMES): + helpers.move_labware_to_hs(protocol, working_plate, h_s, h_s_adapter) + + transfer_well_to_plate(WASH_VOL, wash, working_cols, 5) + helpers.set_hs_speed(protocol, h_s, MIX_SPEED, MIX_SEC / 60, True) + helpers.move_labware_from_hs_to_destination( + protocol, working_plate, h_s, mag + ) + protocol.delay(minutes=MAG_DELAY_MIN) + discard(WASH_VOL * 1.1, working_cols) + # Elution + helpers.move_labware_to_hs(protocol, working_plate, h_s, h_s_adapter) + transfer_well_to_plate(ELUTION_VOL, elu, working_wells, 4) + if READY_FOR_SDSPAGE == 1: + protocol.pause("Seal the Working Plate") + h_s.set_and_wait_for_temperature(70) + helpers.set_hs_speed(protocol, h_s, MIX_SPEED, (MIX_SEC / 60) + 10, True) + h_s.deactivate_heater() + h_s.open_labware_latch() + protocol.pause("Protocol Complete") + elif READY_FOR_SDSPAGE == 0: + helpers.set_hs_speed(protocol, h_s, MIX_SPEED, (MIX_SEC / 60) + 2, True) + + temp.set_temperature(4) + helpers.move_labware_from_hs_to_destination( + protocol, working_plate, h_s, mag + ) + protocol.delay(minutes=MAG_DELAY_MIN) + transfer_plate_to_plate(ELUTION_VOL * 1.1, working_cols, final_cols, 6) + temp.deactivate() + helpers.clean_up_plates(p1000_single, [sample_plate], waste, 1000) + helpers.move_labware_to_hs(protocol, working_plate, h_s, h_s_adapter) + + run(sample_plate_1) + # swap plates + protocol.move_labware(sample_plate_1, "B4", True) + protocol.move_labware(sample_plate_2, "B2", True) + run(sample_plate_2) + + helpers.clean_up_plates(p1000_single, [wash_res], waste, 1000) + helpers.find_liquid_height_of_all_wells(protocol, p1000_single, [waste_res["A1"]]) + if deactivate_modules_bool: + helpers.deactivate_modules(protocol) diff --git a/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py b/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py index 75658f11438..ff38e8cf7c7 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py +++ b/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py @@ -18,7 +18,7 @@ metadata = { "protocolName": "KAPA HyperPlus Library Preparation", - "author": "Your Name ", + "author": "Tony Ngumah ", } requirements = {"robotType": "Flex", "apiLevel": "2.21"} @@ -41,6 +41,7 @@ def add_parameters(parameters: ParameterContext) -> None: helpers.create_disposable_lid_parameter(parameters) helpers.create_tc_lid_deck_riser_parameter(parameters) helpers.create_two_pipette_mount_parameters(parameters) + helpers.create_deactivate_modules_parameter(parameters) parameters.add_int( variable_name="num_samples", display_name="number of samples", @@ -68,22 +69,25 @@ def add_parameters(parameters: ParameterContext) -> None: ) -def run(ctx: ProtocolContext) -> None: +def run(protocol: ProtocolContext) -> None: """Protocol.""" USE_GRIPPER = True - trash_tips = ctx.params.trash_tips # type: ignore[attr-defined] - dry_run = ctx.params.dry_run # type: ignore[attr-defined] - pipette_1000_mount = ctx.params.pipette_mount_1 # type: ignore[attr-defined] - pipette_50_mount = ctx.params.pipette_mount_2 # type: ignore[attr-defined] - deck_riser = ctx.params.deck_riser # type: ignore[attr-defined] + deactivate_mods = protocol.params.deactivate_modules # type: ignore[attr-defined] + trash_tips = protocol.params.trash_tips # type: ignore[attr-defined] + dry_run = protocol.params.dry_run # type: ignore[attr-defined] + pipette_1000_mount = protocol.params.pipette_mount_1 # type: ignore[attr-defined] + pipette_50_mount = protocol.params.pipette_mount_2 # type: ignore[attr-defined] + deck_riser = protocol.params.deck_riser # type: ignore[attr-defined] + helpers.comment_protocol_version(protocol, "01") + REUSE_ETOH_TIPS = True REUSE_RSB_TIPS = ( True # Reuse tips for RSB buffer (adding RSB, mixing, and transferring) ) REUSE_REMOVE_TIPS = True # Reuse tips for supernatant removal - num_samples = ctx.params.num_samples # type: ignore[attr-defined] - PCRCYCLES = ctx.params.PCR_CYCLES # type: ignore[attr-defined] - disposable_lid = ctx.params.disposable_lid # type: ignore[attr-defined] + num_samples = protocol.params.num_samples # type: ignore[attr-defined] + PCRCYCLES = protocol.params.PCR_CYCLES # type: ignore[attr-defined] + disposable_lid = protocol.params.disposable_lid # type: ignore[attr-defined] Fragmentation_time = 10 ligation_tc_time = 15 used_lids: List[Labware] = [] @@ -111,10 +115,10 @@ def run(ctx: ProtocolContext) -> None: # etoh_vol = 400.0 # Importing Labware, Modules and Instruments - magblock: MagneticBlockContext = ctx.load_module( + magblock: MagneticBlockContext = protocol.load_module( helpers.mag_str, "D2" ) # type: ignore[assignment] - temp_mod: TemperatureModuleContext = ctx.load_module( + temp_mod: TemperatureModuleContext = protocol.load_module( helpers.temp_str, "B3" ) # type: ignore[assignment] temp_plate, temp_adapter = helpers.load_temp_adapter_and_labware( @@ -125,7 +129,7 @@ def run(ctx: ProtocolContext) -> None: if not dry_run: temp_mod.set_temperature(4) - tc_mod: ThermocyclerContext = ctx.load_module(helpers.tc_str) # type: ignore[assignment] + tc_mod: ThermocyclerContext = protocol.load_module(helpers.tc_str) # type: ignore[assignment] # Just in case tc_mod.open_lid() @@ -134,32 +138,32 @@ def run(ctx: ProtocolContext) -> None: ) samples_flp = FLP_plate.rows()[0][:num_cols] - sample_plate = ctx.load_labware( + sample_plate = protocol.load_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", "D1", "Sample Plate 1" ) - sample_plate_2 = ctx.load_labware( + sample_plate_2 = protocol.load_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", "B2", "Sample Plate 2" ) samples_2 = sample_plate_2.rows()[0][:num_cols] samples = sample_plate.rows()[0][:num_cols] - reservoir = ctx.load_labware( + reservoir = protocol.load_labware( "nest_96_wellplate_2ml_deep", "C2", "Beads + Buffer + Ethanol" ) # Load tipracks - tiprack_50_1 = ctx.load_labware("opentrons_flex_96_tiprack_50ul", "A3") - tiprack_50_2 = ctx.load_labware("opentrons_flex_96_tiprack_50ul", "A2") + tiprack_50_1 = protocol.load_labware("opentrons_flex_96_tiprack_50ul", "A3") + tiprack_50_2 = protocol.load_labware("opentrons_flex_96_tiprack_50ul", "A2") - tiprack_200_1 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "C1") - tiprack_200_2 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "C3") + tiprack_200_1 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "C1") + tiprack_200_2 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "C3") if trash_tips: - ctx.load_waste_chute() + protocol.load_waste_chute() unused_lids: List[Labware] = [] # Load TC Lids if disposable_lid: - unused_lids = helpers.load_disposable_lids(ctx, 5, ["C4"], deck_riser) + unused_lids = helpers.load_disposable_lids(protocol, 5, ["C4"], deck_riser) # Import Global Variables global tip50 @@ -168,12 +172,12 @@ def run(ctx: ProtocolContext) -> None: global p200_rack_count tip_count = {1000: 0, 50: 0} - p200 = ctx.load_instrument( + p200 = protocol.load_instrument( "flex_8channel_1000", pipette_1000_mount, tip_racks=[tiprack_200_1, tiprack_200_2], ) - p50 = ctx.load_instrument( + p50 = protocol.load_instrument( "flex_8channel_50", pipette_50_mount, tip_racks=[tiprack_50_1, tiprack_50_2] ) @@ -224,7 +228,7 @@ def run(ctx: ProtocolContext) -> None: waste2 = reservoir.columns()[7] waste2_res = waste2[0] - helpers.find_liquid_height_of_loaded_liquids(ctx, liquid_vols_and_wells, p50) + helpers.find_liquid_height_of_loaded_liquids(protocol, liquid_vols_and_wells, p50) def tip_track(pipette: InstrumentContext, tip_count: Dict) -> None: """Track tip usage.""" @@ -248,19 +252,19 @@ def run_tag_profile( ) -> Tuple[List[Labware], List[Labware]]: """Run Tag Profile.""" # Presetting Thermocycler Temps - ctx.comment( + protocol.comment( "****Starting Fragmentation Profile (37C for 10 minutes with 100C lid)****" ) tc_mod.set_lid_temperature(100) tc_mod.set_block_temperature(37) # Move Plate to TC - ctx.comment("****Moving Plate to Pre-Warmed TC Module Block****") - ctx.move_labware(sample_plate, tc_mod, use_gripper=USE_GRIPPER) + protocol.comment("****Moving Plate to Pre-Warmed TC Module Block****") + protocol.move_labware(sample_plate, tc_mod, use_gripper=USE_GRIPPER) if disposable_lid: lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( - ctx, unused_lids, used_lids, sample_plate, tc_mod + protocol, unused_lids, used_lids, sample_plate, tc_mod ) else: tc_mod.close_lid() @@ -271,13 +275,13 @@ def run_tag_profile( if disposable_lid: if len(used_lids) <= 1: - ctx.move_labware(lid_on_plate, "D4", use_gripper=True) + protocol.move_labware(lid_on_plate, "D4", use_gripper=True) else: - ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + protocol.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) # #Move Plate to H-S - ctx.comment("****Moving Plate off of TC****") + protocol.comment("****Moving Plate off of TC****") - ctx.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) + protocol.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) return unused_lids, used_lids def run_er_profile( @@ -285,19 +289,19 @@ def run_er_profile( ) -> Tuple[List[Labware], List[Labware]]: """End Repair Profile.""" # Presetting Thermocycler Temps - ctx.comment( + protocol.comment( "****Starting End Repair Profile (65C for 30 minutes with 100C lid)****" ) tc_mod.set_lid_temperature(100) tc_mod.set_block_temperature(65) # Move Plate to TC - ctx.comment("****Moving Plate to Pre-Warmed TC Module Block****") - ctx.move_labware(sample_plate, tc_mod, use_gripper=USE_GRIPPER) + protocol.comment("****Moving Plate to Pre-Warmed TC Module Block****") + protocol.move_labware(sample_plate, tc_mod, use_gripper=USE_GRIPPER) if disposable_lid: lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( - ctx, unused_lids, used_lids, sample_plate, tc_mod + protocol, unused_lids, used_lids, sample_plate, tc_mod ) else: tc_mod.close_lid() @@ -311,13 +315,13 @@ def run_er_profile( if disposable_lid: # move lid if len(used_lids) <= 1: - ctx.move_labware(lid_on_plate, "C4", use_gripper=True) + protocol.move_labware(lid_on_plate, "C4", use_gripper=True) else: - ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + protocol.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) # #Move Plate to H-S - ctx.comment("****Moving Plate off of TC****") + protocol.comment("****Moving Plate off of TC****") - ctx.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) + protocol.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) return unused_lids, used_lids def run_ligation_profile( @@ -325,20 +329,20 @@ def run_ligation_profile( ) -> Tuple[List[Labware], List[Labware]]: """Run Ligation Profile.""" # Presetting Thermocycler Temps - ctx.comment( + protocol.comment( "****Starting Ligation Profile (20C for 15 minutes with 100C lid)****" ) tc_mod.set_lid_temperature(100) tc_mod.set_block_temperature(20) # Move Plate to TC - ctx.comment("****Moving Plate to Pre-Warmed TC Module Block****") + protocol.comment("****Moving Plate to Pre-Warmed TC Module Block****") - ctx.move_labware(sample_plate, tc_mod, use_gripper=USE_GRIPPER) + protocol.move_labware(sample_plate, tc_mod, use_gripper=USE_GRIPPER) if disposable_lid: lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( - ctx, unused_lids, used_lids, sample_plate, tc_mod + protocol, unused_lids, used_lids, sample_plate, tc_mod ) else: tc_mod.close_lid() @@ -353,14 +357,14 @@ def run_ligation_profile( tc_mod.open_lid() if disposable_lid: if len(used_lids) <= 1: - ctx.move_labware(lid_on_plate, "C4", use_gripper=True) + protocol.move_labware(lid_on_plate, "C4", use_gripper=True) else: - ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + protocol.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) # #Move Plate to H-S - ctx.comment("****Moving Plate off of TC****") + protocol.comment("****Moving Plate off of TC****") - ctx.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) + protocol.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) return unused_lids, used_lids def run_amplification_profile( @@ -368,27 +372,27 @@ def run_amplification_profile( ) -> Tuple[List[Labware], List[Labware]]: """Run Amplification Profile.""" # Presetting Thermocycler Temps - ctx.comment( + protocol.comment( "Amplification Profile (37C for 5 min, 50C for 5 min with 100C lid)" ) tc_mod.set_lid_temperature(100) tc_mod.set_block_temperature(98) # Move Plate to TC - ctx.comment("****Moving Sample Plate onto TC****") - ctx.move_labware(sample_plate_2, tc_mod, use_gripper=USE_GRIPPER) + protocol.comment("****Moving Sample Plate onto TC****") + protocol.move_labware(sample_plate_2, tc_mod, use_gripper=USE_GRIPPER) if not dry_run: tc_mod.set_lid_temperature(105) if disposable_lid: lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( - ctx, unused_lids, used_lids, sample_plate_2, tc_mod + protocol, unused_lids, used_lids, sample_plate_2, tc_mod ) else: tc_mod.close_lid() if not dry_run: helpers.perform_pcr( - ctx, + protocol, tc_mod, initial_denature_time_sec=45, denaturation_time_sec=15, @@ -401,16 +405,16 @@ def run_amplification_profile( tc_mod.open_lid() if disposable_lid: if len(used_lids) <= 1: - ctx.move_labware(lid_on_plate, "C4", use_gripper=True) + protocol.move_labware(lid_on_plate, "C4", use_gripper=True) else: - ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + protocol.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) # Move Sample Plate to H-S - ctx.comment("****Moving Sample Plate back to H-S****") - ctx.move_labware(sample_plate_2, "D1", use_gripper=USE_GRIPPER) + protocol.comment("****Moving Sample Plate back to H-S****") + protocol.move_labware(sample_plate_2, "D1", use_gripper=USE_GRIPPER) # get FLP plate out of the way - ctx.comment("****Moving FLP Plate back to TC****") - ctx.move_labware(FLP_plate, tc_mod, use_gripper=USE_GRIPPER) + protocol.comment("****Moving FLP Plate back to TC****") + protocol.move_labware(FLP_plate, tc_mod, use_gripper=USE_GRIPPER) return unused_lids, used_lids def mix_beads( @@ -463,39 +467,39 @@ def mix_beads( def remove_supernatant(well: Well, vol: float, waste_: Well, column: int) -> None: """Remove supernatant.""" - ctx.comment("-------Removing " + str(vol) + "ul of Supernatant-------") + protocol.comment("-------Removing " + str(vol) + "ul of Supernatant-------") p200.flow_rate.aspirate = 15 num_trans = math.ceil(vol / 190) vol_per_trans = vol / num_trans tip_track(p200, tip_count) for x in range(num_trans): p200.aspirate(vol_per_trans / 2, well.bottom(0.2)) - ctx.delay(seconds=1) + protocol.delay(seconds=1) p200.aspirate(vol_per_trans / 2, well.bottom(0.2)) p200.air_gap(10) p200.dispense(p200.current_volume, waste_) p200.air_gap(10) if REUSE_REMOVE_TIPS: p200.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") else: if trash_tips: p200.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p200.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") p200.flow_rate.aspirate = 150 def Fragmentation( unused_lids: List[Labware], used_lids: List[Labware] ) -> Tuple[List[Labware], List[Labware]]: """Fragmentation Function.""" - ctx.comment("-------Starting Fragmentation-------") + protocol.comment("-------Starting Fragmentation-------") for i in range(num_cols): - ctx.comment("Mixing and Transfering beads to column " + str(i + 1)) + protocol.comment("Mixing and Transfering beads to column " + str(i + 1)) p50.flow_rate.dispense = 15 tip_track(p50, tip_count) @@ -512,10 +516,10 @@ def Fragmentation( p50.flow_rate.dispense = 150 if trash_tips: p50.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") unused_lids, used_lids = run_tag_profile( unused_lids, used_lids @@ -526,11 +530,11 @@ def end_repair( unused_lids: List[Labware], used_lids: List[Labware] ) -> Tuple[List[Labware], List[Labware]]: """End Repair Function.""" - ctx.comment("-------Starting end_repair-------") + protocol.comment("-------Starting end_repair-------") for i in range(num_cols): - ctx.comment( + protocol.comment( "**** Mixing and Transfering beads to column " + str(i + 1) + " ****" ) @@ -549,10 +553,10 @@ def end_repair( p50.flow_rate.dispense = 150 if trash_tips: p50.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") unused_lids, used_lids = run_er_profile( unused_lids, used_lids @@ -565,8 +569,8 @@ def index_ligation( unused_lids: List[Labware], used_lids: List[Labware] ) -> Tuple[List[Labware], List[Labware]]: """Index Ligation.""" - ctx.comment("-------Ligating Indexes-------") - ctx.comment("-------Adding and Mixing ELM-------") + protocol.comment("-------Ligating Indexes-------") + protocol.comment("-------Adding and Mixing ELM-------") for i in samples: tip_track(p50, tip_count) p50.aspirate(ligation_vol, ligation_res) @@ -581,13 +585,13 @@ def index_ligation( p50.flow_rate.dispense = 150 if trash_tips: p50.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") # Add and mix adapters - ctx.comment("-------Adding and Mixing Adapters-------") + protocol.comment("-------Adding and Mixing Adapters-------") for i_well, x_well in zip(samples, adapters): tip_track(p50, tip_count) p50.aspirate(adapter_vol, x_well) @@ -600,10 +604,10 @@ def index_ligation( p50.dispense(40, i_well.bottom(8)) if trash_tips: p50.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") p50.flow_rate.aspirate = 150 p50.flow_rate.dispense = 150 @@ -613,13 +617,13 @@ def index_ligation( def lib_cleanup() -> None: """Litigation Clean up.""" - ctx.comment("-------Starting Cleanup-------") - ctx.comment("-------Adding and Mixing Cleanup Beads-------") + protocol.comment("-------Starting Cleanup-------") + protocol.comment("-------Adding and Mixing Cleanup Beads-------") # Move FLP plate off magnetic module if it's there if FLP_plate.parent == magblock: - ctx.comment("****Moving FLP Plate off Magnetic Module****") - ctx.move_labware(FLP_plate, tc_mod, use_gripper=USE_GRIPPER) + protocol.comment("****Moving FLP Plate off Magnetic Module****") + protocol.move_labware(FLP_plate, tc_mod, use_gripper=USE_GRIPPER) for x, i in enumerate(samples): mix_beads(p200, bead_res, bead_vol_1, 7 if x == 0 else 2, x) @@ -636,22 +640,22 @@ def lib_cleanup() -> None: p200.flow_rate.dispense = 150 if trash_tips: p200.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p200.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") - ctx.delay( + protocol.delay( minutes=bead_inc, msg="Please wait " + str(bead_inc) + " minutes while samples incubate at RT.", ) - ctx.comment("****Moving Labware to Magnet for Pelleting****") - ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) + protocol.comment("****Moving Labware to Magnet for Pelleting****") + protocol.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) - ctx.delay(minutes=4.5, msg="Time for Pelleting") + protocol.delay(minutes=4.5, msg="Time for Pelleting") for col, i in enumerate(samples): remove_supernatant(i, 130, waste1_res, col) @@ -661,7 +665,7 @@ def lib_cleanup() -> None: p200.flow_rate.aspirate = 75 p200.flow_rate.dispense = 75 for y in range(2 if not dry_run else 1): - ctx.comment(f"-------Wash # {y+1} with Ethanol-------") + protocol.comment(f"-------Wash # {y+1} with Ethanol-------") if y == 0: # First wash this_res = etoh1_res this_waste_res = waste1_res @@ -672,42 +676,42 @@ def lib_cleanup() -> None: p200.aspirate(150, this_res) p200.air_gap(10) p200.dispense(p200.current_volume, i.top()) - ctx.delay(seconds=1) + protocol.delay(seconds=1) p200.air_gap(10) if not REUSE_ETOH_TIPS: p200.drop_tip() if trash_tips else p200.return_tip() - ctx.delay(seconds=10) + protocol.delay(seconds=10) # Remove the ethanol wash for x, i in enumerate(samp_list): tip_track(p200, tip_count) p200.aspirate(155, i) p200.air_gap(10) p200.dispense(p200.current_volume, this_waste_res) - ctx.delay(seconds=1) + protocol.delay(seconds=1) p200.air_gap(10) if trash_tips: p200.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p200.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") p200.flow_rate.aspirate = 150 p200.flow_rate.dispense = 150 # Wash complete, move on to drying steps. - ctx.delay(minutes=2, msg="Allow 3 minutes for residual ethanol to dry") + protocol.delay(minutes=2, msg="Allow 3 minutes for residual ethanol to dry") # Return Plate to H-S from Magnet - ctx.comment("****Moving sample plate off of Magnet****") - ctx.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) + protocol.comment("****Moving sample plate off of Magnet****") + protocol.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) # Adding RSB and Mixing for col, i in enumerate(samp_list): - ctx.comment(f"****Adding RSB to Columns: {col+1}****") + protocol.comment(f"****Adding RSB to Columns: {col+1}****") tip_track(p50, tip_count) p50.aspirate(rsb_vol_1, rsb_res) p50.air_gap(5) @@ -723,23 +727,23 @@ def lib_cleanup() -> None: p50.air_gap(5) if REUSE_RSB_TIPS: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") else: if trash_tips: p50.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") - ctx.delay( + protocol.delay( minutes=3, msg="Allow 3 minutes for incubation and liquid aggregation." ) - ctx.comment("****Move Samples to Magnet for Pelleting****") - ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) + protocol.comment("****Move Samples to Magnet for Pelleting****") + protocol.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) - ctx.delay(minutes=2, msg="Please allow 2 minutes for beads to pellet.") + protocol.delay(minutes=2, msg="Please allow 2 minutes for beads to pellet.") p200.flow_rate.aspirate = 10 for i_int, (s, e) in enumerate(zip(samp_list, samples_2)): @@ -750,31 +754,31 @@ def lib_cleanup() -> None: p50.air_gap(5) if trash_tips: p50.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") # move new sample plate to D1 or heatershaker - ctx.comment("****Moving sample plate off of Magnet****") - ctx.move_labware(sample_plate_2, "D1", use_gripper=USE_GRIPPER) + protocol.comment("****Moving sample plate off of Magnet****") + protocol.move_labware(sample_plate_2, "D1", use_gripper=USE_GRIPPER) # Keep Sample PLate 1 to B2 - ctx.comment("****Moving Sample_plate_1 Plate off magnet to B2****") - ctx.move_labware(sample_plate, "B2", use_gripper=USE_GRIPPER) + protocol.comment("****Moving Sample_plate_1 Plate off magnet to B2****") + protocol.move_labware(sample_plate, "B2", use_gripper=USE_GRIPPER) - ctx.comment("****Moving FLP Plate off TC****") - ctx.move_labware(FLP_plate, magblock, use_gripper=USE_GRIPPER) + protocol.comment("****Moving FLP Plate off TC****") + protocol.move_labware(FLP_plate, magblock, use_gripper=USE_GRIPPER) def lib_amplification( unused_lids: List[Labware], used_lids: List[Labware] ) -> Tuple[List[Labware], List[Labware]]: """Library Amplification.""" - ctx.comment("-------Starting lib_amplification-------") + protocol.comment("-------Starting lib_amplification-------") for i in range(num_cols): - ctx.comment( + protocol.comment( "**** Mixing and Transfering beads to column " + str(i + 1) + " ****" ) mix_beads( @@ -795,10 +799,10 @@ def lib_amplification( p50.flow_rate.dispense = 150 if trash_tips: p50.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") unused_lids, used_lids = run_amplification_profile( unused_lids, used_lids @@ -807,8 +811,8 @@ def lib_amplification( def lib_cleanup_2() -> None: """Final Library Clean up.""" - ctx.comment("-------Starting Cleanup-------") - ctx.comment("-------Adding and Mixing Cleanup Beads-------") + protocol.comment("-------Starting Cleanup-------") + protocol.comment("-------Adding and Mixing Cleanup Beads-------") for x, i in enumerate(samples_2): mix_beads(p200, bead_res, bead_vol_2, 7 if x == 0 else 2, x) tip_track(p200, tip_count) @@ -826,22 +830,22 @@ def lib_cleanup_2() -> None: p200.flow_rate.dispense = 150 if trash_tips: p200.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p200.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") - ctx.delay( + protocol.delay( minutes=bead_inc, msg="Please wait " + str(bead_inc) + " minutes while samples incubate at RT.", ) - ctx.comment("****Moving Labware to Magnet for Pelleting****") - ctx.move_labware(sample_plate_2, magblock, use_gripper=USE_GRIPPER) + protocol.comment("****Moving Labware to Magnet for Pelleting****") + protocol.move_labware(sample_plate_2, magblock, use_gripper=USE_GRIPPER) - ctx.delay(minutes=4.5, msg="Time for Pelleting") + protocol.delay(minutes=4.5, msg="Time for Pelleting") for col, i in enumerate(samples_2): remove_supernatant(i, 130, waste1_res, col) @@ -851,7 +855,7 @@ def lib_cleanup_2() -> None: p200.flow_rate.aspirate = 75 p200.flow_rate.dispense = 75 for y in range(2 if not dry_run else 1): - ctx.comment(f"-------Wash # {y+1} with Ethanol-------") + protocol.comment(f"-------Wash # {y+1} with Ethanol-------") if y == 0: # First wash this_res = etoh1_res this_waste_res = waste1_res @@ -862,41 +866,41 @@ def lib_cleanup_2() -> None: p200.aspirate(150, this_res) p200.air_gap(10) p200.dispense(p200.current_volume, i.top()) - ctx.delay(seconds=1) + protocol.delay(seconds=1) p200.air_gap(10) if not REUSE_ETOH_TIPS: p200.drop_tip() if trash_tips else p200.return_tip() - ctx.delay(seconds=10) + protocol.delay(seconds=10) # Remove the ethanol wash for x, i in enumerate(samp_list_2): tip_track(p200, tip_count) p200.aspirate(155, i) p200.air_gap(10) p200.dispense(p200.current_volume, this_waste_res) - ctx.delay(seconds=1) + protocol.delay(seconds=1) p200.air_gap(10) if trash_tips: p200.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p200.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") p200.flow_rate.aspirate = 150 p200.flow_rate.dispense = 150 # Washes Complete, Move on to Drying Steps - ctx.delay(minutes=3, msg="Allow 3 minutes for residual ethanol to dry") + protocol.delay(minutes=3, msg="Allow 3 minutes for residual ethanol to dry") - ctx.comment("****Moving sample plate off of Magnet****") - ctx.move_labware(sample_plate_2, "D1", use_gripper=USE_GRIPPER) + protocol.comment("****Moving sample plate off of Magnet****") + protocol.move_labware(sample_plate_2, "D1", use_gripper=USE_GRIPPER) # Adding RSB and Mixing for col, i in enumerate(samp_list_2): - ctx.comment(f"****Adding RSB to Columns: {col+1}****") + protocol.comment(f"****Adding RSB to Columns: {col+1}****") tip_track(p50, tip_count) p50.aspirate(rsb_vol_2, rsb_res) p50.air_gap(5) @@ -912,23 +916,23 @@ def lib_cleanup_2() -> None: p50.air_gap(5) if REUSE_RSB_TIPS: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") else: if trash_tips: p50.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") - ctx.delay( + protocol.delay( minutes=3, msg="Allow 3 minutes for incubation and liquid aggregation." ) - ctx.comment("****Move Samples to Magnet for Pelleting****") - ctx.move_labware(sample_plate_2, magblock, use_gripper=USE_GRIPPER) + protocol.comment("****Move Samples to Magnet for Pelleting****") + protocol.move_labware(sample_plate_2, magblock, use_gripper=USE_GRIPPER) - ctx.delay(minutes=2, msg="Please allow 2 minutes for beads to pellet.") + protocol.delay(minutes=2, msg="Please allow 2 minutes for beads to pellet.") p200.flow_rate.aspirate = 10 for i_int, (s, e) in enumerate(zip(samp_list_2, samples_flp)): @@ -939,10 +943,10 @@ def lib_cleanup_2() -> None: p50.air_gap(5) if trash_tips: p50.drop_tip() - ctx.comment("****Dropping Tip in Waste shoot****") + protocol.comment("****Dropping Tip in Waste shoot****") else: p50.return_tip() - ctx.comment("****Dropping Tip Back in Tip Box****") + protocol.comment("****Dropping Tip Back in Tip Box****") # Set Block Temp for Final Plate tc_mod.set_block_temperature(4) @@ -963,4 +967,6 @@ def lib_cleanup_2() -> None: waste2_res = waste2[0] end_probed_wells = [waste1_res, waste2_res] - helpers.find_liquid_height_of_all_wells(ctx, p50, end_probed_wells) + helpers.find_liquid_height_of_all_wells(protocol, p50, end_probed_wells) + if deactivate_mods: + helpers.deactivate_modules(protocol) diff --git a/abr-testing/abr_testing/protocols/active_protocols/1_Simple Normalize Long Right.py b/abr-testing/abr_testing/protocols/active_protocols/1_Simple Normalize Long Right.py index 525a82c3095..6162e6ab34e 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/1_Simple Normalize Long Right.py +++ b/abr-testing/abr_testing/protocols/active_protocols/1_Simple Normalize Long Right.py @@ -4,10 +4,12 @@ ParameterContext, Labware, SINGLE, + ALL, InstrumentContext, Well, ) from abr_testing.protocols import helpers +from typing import List, Dict metadata = { "protocolName": "Simple Normalize Long with LPD and Single Tip", @@ -15,16 +17,14 @@ "source": "Protocol Library", } -requirements = { - "robotType": "Flex", - "apiLevel": "2.21", -} +requirements = {"robotType": "Flex", "apiLevel": "2.21"} def add_parameters(parameters: ParameterContext) -> None: """Parameters.""" helpers.create_single_pipette_mount_parameter(parameters) - helpers.create_tip_size_parameter(parameters) + helpers.create_csv_parameter(parameters) + helpers.create_dot_bottom_parameter(parameters) def get_next_tip_by_row(tip_rack: Labware, pipette: InstrumentContext) -> Well | None: @@ -79,149 +79,68 @@ def get_next_tip_by_row(tip_rack: Labware, pipette: InstrumentContext) -> Well | def run(protocol: ProtocolContext) -> None: """Protocol.""" - tip_type = protocol.params.tip_size # type: ignore[attr-defined] + dot_bottom = protocol.params.dot_bottom # type: ignore[attr-defined] mount_pos = protocol.params.pipette_mount # type: ignore[attr-defined] + all_data = protocol.params.parameters_csv.parse_as_csv() # type: ignore[attr-defined] + data = all_data[1:] + helpers.comment_protocol_version(protocol, "01") # DECK SETUP AND LABWARE protocol.comment("THIS IS A NO MODULE RUN") - tiprack_x_1 = protocol.load_labware(tip_type, "D1") - tiprack_x_2 = protocol.load_labware(tip_type, "D2") - tiprack_x_3 = protocol.load_labware(tip_type, "B1") + tiprack_x_1 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "D1") + tiprack_x_2 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "D2") + tiprack_x_3 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "A1") sample_plate_1 = protocol.load_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", "D3" ) reservoir = protocol.load_labware("nest_12_reservoir_15ml", "B3") + waste_reservoir = protocol.load_labware( + "nest_1_reservoir_195ml", "C1", "Liquid Waste" + ) sample_plate_2 = protocol.load_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", "C2" ) sample_plate_3 = protocol.load_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", "B2" ) + sample_plate_4 = protocol.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "A2" + ) protocol.load_trash_bin("A3") - # reagent + # reagentg146 Dye_1 = reservoir["A1"] Dye_2 = reservoir["A2"] Dye_3 = reservoir["A3"] Diluent_1 = reservoir["A4"] Diluent_2 = reservoir["A5"] + Diluent_3 = reservoir["A6"] # pipette p1000 = protocol.load_instrument( "flex_8channel_1000", mount_pos, liquid_presence_detection=True ) + p1000_single = protocol.load_instrument( + "flex_1channel_1000", + "right", + liquid_presence_detection=True, + tip_racks=[tiprack_x_2, tiprack_x_3], + ) # LOAD LIQUIDS liquid_volumes = [675.0, 675.0, 675.0, 675.0, 675.0] - wells = [Dye_1, Dye_2, Dye_3, Diluent_1, Diluent_2] + wells = [Dye_1, Dye_2, Dye_3, Diluent_1, Diluent_2, Diluent_3] helpers.load_wells_with_water(protocol, wells, liquid_volumes) - + liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { + "Dye": [{"well": [Dye_1, Dye_2, Dye_3], "volume": 675.0}], + "Diluent": [{"well": [Diluent_1, Diluent_2, Diluent_3], "volume": 675.0}], + } current_rack = tiprack_x_1 # CONFIGURE SINGLE LAYOUT - p1000.configure_nozzle_layout( - style=SINGLE, start="H1", tip_racks=[tiprack_x_1, tiprack_x_2, tiprack_x_3] + p1000.configure_nozzle_layout(style=SINGLE, start="H1", tip_racks=[tiprack_x_1]) + helpers.find_liquid_height_of_loaded_liquids( + protocol, liquid_vols_and_wells, p1000_single ) - helpers.find_liquid_height_of_all_wells(protocol, p1000, wells) - sample_quant_csv = """ - sample_plate_1, Sample_well,DYE,DILUENT - sample_plate_1,A1,0,100 - sample_plate_1,B1,5,95 - sample_plate_1,C1,10,90 - sample_plate_1,D1,20,80 - sample_plate_1,E1,40,60 - sample_plate_1,F1,15,40 - sample_plate_1,G1,40,20 - sample_plate_1,H1,40,0 - sample_plate_1,A2,35,65 - sample_plate_1,B2,38,42 - sample_plate_1,C2,42,58 - sample_plate_1,D2,32,8 - sample_plate_1,E2,38,12 - sample_plate_1,F2,26,74 - sample_plate_1,G2,31,69 - sample_plate_1,H2,46,4 - sample_plate_1,A3,47,13 - sample_plate_1,B3,42,18 - sample_plate_1,C3,46,64 - sample_plate_1,D3,48,22 - sample_plate_1,E3,26,74 - sample_plate_1,F3,34,66 - sample_plate_1,G3,43,37 - sample_plate_1,H3,20,80 - sample_plate_1,A4,44,16 - sample_plate_1,B4,49,41 - sample_plate_1,C4,48,42 - sample_plate_1,D4,44,16 - sample_plate_1,E4,47,53 - sample_plate_1,F4,47,33 - sample_plate_1,G4,42,48 - sample_plate_1,H4,39,21 - sample_plate_1,A5,30,20 - sample_plate_1,B5,36,14 - sample_plate_1,C5,31,59 - sample_plate_1,D5,38,52 - sample_plate_1,E5,36,4 - sample_plate_1,F5,32,28 - sample_plate_1,G5,35,55 - sample_plate_1,H5,39,1 - sample_plate_1,A6,31,59 - sample_plate_1,B6,20,80 - sample_plate_1,C6,38,2 - sample_plate_1,D6,34,46 - sample_plate_1,E6,30,70 - sample_plate_1,F6,32,58 - sample_plate_1,G6,21,79 - sample_plate_1,H6,38,52 - sample_plate_1,A7,33,27 - sample_plate_1,B7,34,16 - sample_plate_1,C7,40,60 - sample_plate_1,D7,34,26 - sample_plate_1,E7,30,20 - sample_plate_1,F7,44,56 - sample_plate_1,G7,26,74 - sample_plate_1,H7,45,55 - sample_plate_1,A8,39,1 - sample_plate_1,B8,38,2 - sample_plate_1,C8,34,66 - sample_plate_1,D8,39,11 - sample_plate_1,E8,46,54 - sample_plate_1,F8,37,63 - sample_plate_1,G8,38,42 - sample_plate_1,H8,34,66 - sample_plate_1,A9,44,56 - sample_plate_1,B9,39,11 - sample_plate_1,C9,30,70 - sample_plate_1,D9,37,33 - sample_plate_1,E9,46,54 - sample_plate_1,F9,39,21 - sample_plate_1,G9,29,41 - sample_plate_1,H9,23,77 - sample_plate_1,A10,26,74 - sample_plate_1,B10,39,1 - sample_plate_1,C10,31,49 - sample_plate_1,D10,38,62 - sample_plate_1,E10,29,1 - sample_plate_1,F10,21,79 - sample_plate_1,G10,29,41 - sample_plate_1,H10,28,42 - sample_plate_1,A11,15,55 - sample_plate_1,B11,28,72 - sample_plate_1,C11,11,49 - sample_plate_1,D11,34,66 - sample_plate_1,E11,27,73 - sample_plate_1,F11,30,40 - sample_plate_1,G11,33,67 - sample_plate_1,H11,31,39 - sample_plate_1,A12,39,31 - sample_plate_1,B12,47,53 - sample_plate_1,C12,46,54 - sample_plate_1,D12,13,7 - sample_plate_1,E12,34,46 - sample_plate_1,F12,45,35 - sample_plate_1,G12,28,42 - sample_plate_1,H12,37,63 - """ - data = [r.split(",") for r in sample_quant_csv.strip().splitlines() if r][1:] for X in range(1): protocol.comment("==============================================") protocol.comment("Adding Dye Sample Plate 1") @@ -232,8 +151,8 @@ def run(protocol: ProtocolContext) -> None: well = get_next_tip_by_row(current_rack, p1000) p1000.pick_up_tip(well) while current < len(data): - CurrentWell = str(data[current][1]) - DyeVol = float(data[current][2]) + CurrentWell = str(data[current][0]) + DyeVol = float(data[current][1]) if DyeVol != 0 and DyeVol < 100: p1000.liquid_presence_detection = False p1000.transfer( @@ -245,7 +164,7 @@ def run(protocol: ProtocolContext) -> None: if DyeVol > 20: wells.append(sample_plate_1.wells_by_name()[CurrentWell]) current += 1 - p1000.blow_out() + p1000.blow_out(location=waste_reservoir["A1"]) p1000.touch_tip() p1000.drop_tip() p1000.liquid_presence_detection = True @@ -256,34 +175,34 @@ def run(protocol: ProtocolContext) -> None: current = 0 while current < len(data): - CurrentWell = str(data[current][1]) + CurrentWell = str(data[current][0]) DilutionVol = float(data[current][2]) if DilutionVol != 0 and DilutionVol < 100: well = get_next_tip_by_row(current_rack, p1000) p1000.pick_up_tip(well) - p1000.aspirate(DilutionVol, Diluent_1.bottom(z=2)) + p1000.aspirate(DilutionVol, Diluent_1.bottom(z=dot_bottom)) p1000.dispense( DilutionVol, sample_plate_1.wells_by_name()[CurrentWell].top(z=0.2) ) if DilutionVol > 20: wells.append(sample_plate_1.wells_by_name()[CurrentWell]) - p1000.blow_out() + p1000.blow_out(location=waste_reservoir["A1"]) p1000.touch_tip() p1000.drop_tip() current += 1 + protocol.comment("Changing pipette configuration to 8ch.") + protocol.comment("==============================================") protocol.comment("Adding Dye Sample Plate 2") protocol.comment("==============================================") - current = 0 - well = get_next_tip_by_row(tiprack_x_2, p1000) - p1000.pick_up_tip(well) + p1000_single.pick_up_tip() while current < len(data): - CurrentWell = str(data[current][1]) - DyeVol = float(data[current][2]) + CurrentWell = str(data[current][0]) + DyeVol = float(data[current][1]) if DyeVol != 0 and DyeVol < 100: - p1000.transfer( + p1000_single.transfer( DyeVol, Dye_2.bottom(z=2), sample_plate_2.wells_by_name()[CurrentWell].top(z=1), @@ -292,9 +211,9 @@ def run(protocol: ProtocolContext) -> None: if DyeVol > 20: wells.append(sample_plate_2.wells_by_name()[CurrentWell]) current += 1 - p1000.blow_out() - p1000.touch_tip() - p1000.drop_tip() + p1000_single.blow_out(location=waste_reservoir["A1"]) + p1000_single.touch_tip() + p1000_single.return_tip() protocol.comment("==============================================") protocol.comment("Adding Diluent Sample Plate 2") @@ -302,20 +221,19 @@ def run(protocol: ProtocolContext) -> None: current = 0 while current < len(data): - CurrentWell = str(data[current][1]) + CurrentWell = str(data[current][0]) DilutionVol = float(data[current][2]) if DilutionVol != 0 and DilutionVol < 100: - well = get_next_tip_by_row(tiprack_x_2, p1000) - p1000.pick_up_tip(well) - p1000.aspirate(DilutionVol, Diluent_2.bottom(z=2)) - p1000.dispense( + p1000_single.pick_up_tip() + p1000_single.aspirate(DilutionVol, Diluent_2.bottom(z=dot_bottom)) + p1000_single.dispense( DilutionVol, sample_plate_2.wells_by_name()[CurrentWell].top(z=0.2) ) if DilutionVol > 20: wells.append(sample_plate_2.wells_by_name()[CurrentWell]) - p1000.blow_out() - p1000.touch_tip() - p1000.drop_tip() + p1000_single.blow_out(location=waste_reservoir["A1"]) + p1000_single.touch_tip() + p1000_single.return_tip() current += 1 protocol.comment("==============================================") @@ -323,14 +241,13 @@ def run(protocol: ProtocolContext) -> None: protocol.comment("==============================================") current = 0 - well = get_next_tip_by_row(tiprack_x_3, p1000) - p1000.pick_up_tip(well) + p1000_single.pick_up_tip() while current < len(data): - CurrentWell = str(data[current][1]) - DyeVol = float(data[current][2]) + CurrentWell = str(data[current][0]) + DyeVol = float(data[current][1]) if DyeVol != 0 and DyeVol < 100: - p1000.liquid_presence_detection = False - p1000.transfer( + p1000_single.liquid_presence_detection = False + p1000_single.transfer( DyeVol, Dye_3.bottom(z=2), sample_plate_3.wells_by_name()[CurrentWell].top(z=1), @@ -341,14 +258,85 @@ def run(protocol: ProtocolContext) -> None: if DyeVol > 20: wells.append(sample_plate_3.wells_by_name()[CurrentWell]) current += 1 - p1000.liquid_presence_detection = True - p1000.blow_out() - p1000.touch_tip() - p1000.drop_tip() + p1000_single.liquid_presence_detection = True + p1000_single.blow_out(location=waste_reservoir["A1"]) + p1000_single.touch_tip() + p1000_single.return_tip() protocol.comment("==============================================") protocol.comment("Adding Diluent Sample Plate 3") protocol.comment("==============================================") + current = 0 + while current < len(data): + CurrentWell = str(data[current][0]) + DilutionVol = float(data[current][2]) + if DilutionVol != 0 and DilutionVol < 100: + p1000_single.pick_up_tip() + p1000_single.aspirate(DilutionVol, Diluent_3.bottom(z=dot_bottom)) + p1000_single.dispense( + DilutionVol, sample_plate_3.wells_by_name()[CurrentWell].top(z=0.2) + ) + if DilutionVol > 20: + wells.append(sample_plate_3.wells_by_name()[CurrentWell]) + p1000_single.blow_out(location=waste_reservoir["A1"]) + p1000_single.touch_tip() + p1000_single.return_tip() + current += 1 + protocol.comment("==============================================") + protocol.comment("Adding Dye Sample Plate 4") + protocol.comment("==============================================") + p1000_single.reset_tipracks() current = 0 - # Probe heights - helpers.find_liquid_height_of_all_wells(protocol, p1000, wells) + p1000_single.pick_up_tip() + while current < len(data): + CurrentWell = str(data[current][0]) + DyeVol = float(data[current][1]) + if DyeVol != 0 and DyeVol < 100: + p1000_single.liquid_presence_detection = False + p1000_single.transfer( + DyeVol, + Dye_3.bottom(z=2), + sample_plate_4.wells_by_name()[CurrentWell].top(z=1), + blow_out=True, + blowout_location="destination well", + new_tip="never", + ) + if DyeVol > 20: + wells.append(sample_plate_4.wells_by_name()[CurrentWell]) + current += 1 + p1000_single.liquid_presence_detection = True + p1000_single.blow_out(location=waste_reservoir["A1"]) + p1000_single.touch_tip() + p1000_single.return_tip() + protocol.comment("==============================================") + protocol.comment("Adding Diluent Sample Plate 4") + protocol.comment("==============================================") + current = 0 + while current < len(data): + CurrentWell = str(data[current][0]) + DilutionVol = float(data[current][2]) + if DilutionVol != 0 and DilutionVol < 100: + p1000_single.pick_up_tip() + p1000_single.aspirate(DilutionVol, Diluent_3.bottom(z=dot_bottom)) + p1000_single.dispense( + DilutionVol, sample_plate_4.wells_by_name()[CurrentWell].top(z=0.2) + ) + if DilutionVol > 20: + wells.append(sample_plate_4.wells_by_name()[CurrentWell]) + p1000_single.blow_out(location=waste_reservoir["A1"]) + p1000_single.touch_tip() + p1000_single.return_tip() + current += 1 + + current = 0 + # Probe heights + p1000.configure_nozzle_layout(style=ALL, tip_racks=[tiprack_x_3]) + helpers.clean_up_plates( + p1000, + [sample_plate_1, sample_plate_2, sample_plate_3, sample_plate_4], + waste_reservoir["A1"], + 200, + ) + helpers.find_liquid_height_of_all_wells( + protocol, p1000_single, [waste_reservoir["A1"]] + ) diff --git a/abr-testing/abr_testing/protocols/active_protocols/2_BMS_PCR_Protocol.py b/abr-testing/abr_testing/protocols/active_protocols/2_BMS_PCR_Protocol.py index 24e7358f6e1..3b11b51b7fe 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/2_BMS_PCR_Protocol.py +++ b/abr-testing/abr_testing/protocols/active_protocols/2_BMS_PCR_Protocol.py @@ -5,7 +5,7 @@ ThermocyclerContext, TemperatureModuleContext, ) -from opentrons.protocol_api import SINGLE, Well +from opentrons.protocol_api import SINGLE, Well, ALL from abr_testing.protocols import helpers from typing import List, Dict @@ -14,7 +14,7 @@ "protocolName": "PCR Protocol with TC Auto Sealing Lid", "author": "Rami Farawi None: @@ -23,81 +23,79 @@ def add_parameters(parameters: ParameterContext) -> None: helpers.create_disposable_lid_parameter(parameters) helpers.create_csv_parameter(parameters) helpers.create_tc_lid_deck_riser_parameter(parameters) + helpers.create_deactivate_modules_parameter(parameters) -def run(ctx: ProtocolContext) -> None: +def run(protocol: ProtocolContext) -> None: """Protocol.""" - pipette_mount = ctx.params.pipette_mount # type: ignore[attr-defined] - disposable_lid = ctx.params.disposable_lid # type: ignore[attr-defined] - parsed_csv = ctx.params.parameters_csv.parse_as_csv() # type: ignore[attr-defined] - deck_riser = ctx.params.deck_riser # type: ignore[attr-defined] + pipette_mount = protocol.params.pipette_mount # type: ignore[attr-defined] + disposable_lid = protocol.params.disposable_lid # type: ignore[attr-defined] + parsed_csv = protocol.params.parameters_csv.parse_as_csv() # type: ignore[attr-defined] + deck_riser = protocol.params.deck_riser # type: ignore[attr-defined] + deactivate_modules_bool = protocol.params.deactivate_modules # type: ignore[attr-defined] + helpers.comment_protocol_version(protocol, "01") rxn_vol = 50 real_mode = True # DECK SETUP AND LABWARE - tc_mod: ThermocyclerContext = ctx.load_module( + tc_mod: ThermocyclerContext = protocol.load_module( helpers.tc_str ) # type: ignore[assignment] tc_mod.open_lid() tc_mod.set_lid_temperature(105) - temp_mod: TemperatureModuleContext = ctx.load_module( + temp_mod: TemperatureModuleContext = protocol.load_module( helpers.temp_str, location="D3" ) # type: ignore[assignment] reagent_rack = temp_mod.load_labware( - "opentrons_24_aluminumblock_nest_1.5ml_snapcap" - ) # check if 2mL - - dest_plate = tc_mod.load_labware( - "opentrons_96_wellplate_200ul_pcr_full_skirt" - ) # do I change this to tough plate if they run pcr? - - source_plate = ctx.load_labware( - "opentrons_96_wellplate_200ul_pcr_full_skirt", location="D1" - ) # do I change this to their plate? + "opentrons_24_aluminumblock_nest_1.5ml_snapcap", "Reagent Rack" + ) + dest_plate_1 = tc_mod.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "Destination Plate 1" + ) + source_plate_1 = protocol.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "D1", "DNA Plate 1" + ) + waste = protocol.load_labware("nest_1_reservoir_195ml", "D2", "Liquid Waste") + liquid_waste = waste["A1"] tiprack_50 = [ - ctx.load_labware("opentrons_flex_96_tiprack_50ul", slot) for slot in [8, 9] + protocol.load_labware("opentrons_flex_96_tiprack_50ul", slot) for slot in [8, 9] ] # Opentrons tough pcr auto sealing lids if disposable_lid: - unused_lids = helpers.load_disposable_lids(ctx, 3, ["C3"], deck_riser) + unused_lids = helpers.load_disposable_lids(protocol, 3, ["C3"], deck_riser) used_lids: List[Labware] = [] # LOAD PIPETTES - p50 = ctx.load_instrument( + p50 = protocol.load_instrument( "flex_8channel_50", pipette_mount, tip_racks=tiprack_50, liquid_presence_detection=True, ) p50.configure_nozzle_layout(style=SINGLE, start="A1", tip_racks=tiprack_50) - ctx.load_trash_bin("A3") + protocol.load_trash_bin("A3") temp_mod.set_temperature(4) # LOAD LIQUIDS water: Well = reagent_rack["B1"] mmx_pic: List[Well] = reagent_rack.rows()[0] - dna_pic: List[Well] = source_plate.wells() + dna_pic: List[Well] = source_plate_1.wells() liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { - "Water": [{"well": water, "volume": 1500.0}], - "Mastermix": [{"well": mmx_pic, "volume": 1500.0}], - "DNA": [{"well": dna_pic, "volume": 50.0}], + "Water": [{"well": water, "volume": 500.0}], + "Mastermix": [{"well": mmx_pic, "volume": 500.0}], + "DNA": [{"well": dna_pic, "volume": 100.0}], } - helpers.load_wells_with_custom_liquids(ctx, liquid_vols_and_wells) - wells_to_probe = [[water], mmx_pic, dna_pic] - wells_to_probe_flattened = [ - well for list_of_wells in wells_to_probe for well in list_of_wells - ] - helpers.find_liquid_height_of_all_wells(ctx, p50, wells_to_probe_flattened) + helpers.find_liquid_height_of_loaded_liquids(protocol, liquid_vols_and_wells, p50) # adding water - ctx.comment("\n\n----------ADDING WATER----------\n") + protocol.comment("\n\n----------ADDING WATER----------\n") p50.pick_up_tip() - # p50.aspirate(40, water) # prewet - # p50.dispense(40, water) + p50.aspirate(40, water) # prewet + p50.dispense(40, water) parsed_csv = parsed_csv[1:] num_of_rows = len(parsed_csv) for row_index in range(num_of_rows): @@ -112,13 +110,13 @@ def run(ctx: ProtocolContext) -> None: p50.configure_for_volume(water_vol) p50.aspirate(water_vol, water) - p50.dispense(water_vol, dest_plate[dest_well], rate=0.5) + p50.dispense(water_vol, dest_plate_1[dest_well], rate=0.5) p50.configure_for_volume(50) - # p50.blow_out() + p50.blow_out() p50.drop_tip() # adding Mastermix - ctx.comment("\n\n----------ADDING MASTERMIX----------\n") + protocol.comment("\n\n----------ADDING MASTERMIX----------\n") for i, row in enumerate(parsed_csv): p50.pick_up_tip() mmx_vol = row[3] @@ -144,8 +142,8 @@ def run(ctx: ProtocolContext) -> None: break p50.configure_for_volume(mmx_vol) p50.aspirate(mmx_vol, reagent_rack[mmx_tube]) - p50.dispense(mmx_vol, dest_plate[dest_well].top()) - ctx.delay(seconds=2) + p50.dispense(mmx_vol, dest_plate_1[dest_well].top()) + protocol.delay(seconds=2) p50.blow_out() p50.touch_tip() p50.configure_for_volume(50) @@ -154,7 +152,7 @@ def run(ctx: ProtocolContext) -> None: p50.drop_tip() # adding DNA - ctx.comment("\n\n----------ADDING DNA----------\n") + protocol.comment("\n\n----------ADDING DNA----------\n") for row in parsed_csv: dna_vol = row[2] if dna_vol.lower() == "x": @@ -168,29 +166,28 @@ def run(ctx: ProtocolContext) -> None: if dna_vol == 0: break p50.configure_for_volume(dna_vol) - p50.aspirate(dna_vol, source_plate[dest_and_source_well]) - p50.dispense(dna_vol, dest_plate[dest_and_source_well], rate=0.5) + p50.aspirate(dna_vol, source_plate_1[dest_and_source_well]) + p50.dispense(dna_vol, dest_plate_1[dest_and_source_well], rate=0.5) p50.mix( 10, 0.7 * rxn_vol if 0.7 * rxn_vol < 30 else 30, - dest_plate[dest_and_source_well], + dest_plate_1[dest_and_source_well], ) p50.drop_tip() p50.configure_for_volume(50) - wells_to_probe_flattened.append(dest_plate[dest_well]) - ctx.comment("\n\n-----------Running PCR------------\n") + protocol.comment("\n\n-----------Running PCR------------\n") if real_mode: if disposable_lid: lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( - ctx, unused_lids, used_lids, dest_plate, tc_mod + protocol, unused_lids, used_lids, dest_plate_1, tc_mod ) else: tc_mod.close_lid() helpers.perform_pcr( - ctx, + protocol, tc_mod, initial_denature_time_sec=120, denaturation_time_sec=10, @@ -205,9 +202,16 @@ def run(ctx: ProtocolContext) -> None: tc_mod.open_lid() if disposable_lid: if len(used_lids) <= 1: - ctx.move_labware(lid_on_plate, "C2", use_gripper=True) + protocol.move_labware(lid_on_plate, "C2", use_gripper=True) else: - ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + protocol.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) p50.drop_tip() p50.configure_nozzle_layout(style=SINGLE, start="A1", tip_racks=tiprack_50) - helpers.find_liquid_height_of_all_wells(ctx, p50, wells_to_probe_flattened) + mmx_pic.append(water) + # Empty plates into liquid waste + p50.configure_nozzle_layout(style=ALL, tip_racks=tiprack_50) + helpers.clean_up_plates(p50, [source_plate_1, dest_plate_1], liquid_waste, 50) + # Probe liquid waste + helpers.find_liquid_height_of_all_wells(protocol, p50, [liquid_waste]) + if deactivate_modules_bool: + helpers.deactivate_modules(protocol) diff --git a/abr-testing/abr_testing/protocols/active_protocols/3_Tartrazine Protocol.py b/abr-testing/abr_testing/protocols/active_protocols/3_Tartrazine Protocol.py index 66db85468f4..9916ef7f7fc 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/3_Tartrazine Protocol.py +++ b/abr-testing/abr_testing/protocols/active_protocols/3_Tartrazine Protocol.py @@ -1,5 +1,10 @@ """Tartrazine Protocol.""" -from opentrons.protocol_api import ProtocolContext, ParameterContext, Well +from opentrons.protocol_api import ( + ProtocolContext, + ParameterContext, + Well, + InstrumentContext, +) from abr_testing.protocols import helpers from opentrons.protocol_api.module_contexts import ( AbsorbanceReaderContext, @@ -23,101 +28,172 @@ def add_parameters(parameters: ParameterContext) -> None: parameters.add_int( variable_name="number_of_plates", display_name="Number of Plates", - default=4, + default=1, minimum=1, maximum=4, ) + helpers.create_channel_parameter(parameters) + helpers.create_plate_reader_compatible_labware_parameter(parameters) -def run(ctx: ProtocolContext) -> None: +def run(protocol: ProtocolContext) -> None: """Protocol.""" - number_of_plates = ctx.params.number_of_plates # type: ignore [attr-defined] + # Load parameters + number_of_plates = protocol.params.number_of_plates # type: ignore [attr-defined] + channels = protocol.params.channels # type: ignore [attr-defined] + plate_type = protocol.params.labware_plate_reader_compatible # type: ignore [attr-defined] + + helpers.comment_protocol_version(protocol, "01") # Plate Reader - plate_reader: AbsorbanceReaderContext = ctx.load_module( + plate_reader: AbsorbanceReaderContext = protocol.load_module( helpers.abs_mod_str, "A3" ) # type: ignore[assignment] - hs: HeaterShakerContext = ctx.load_module(helpers.hs_str, "A1") # type: ignore[assignment] - hs_adapter = hs.load_adapter("opentrons_universal_flat_adapter") - tube_rack = ctx.load_labware( - "opentrons_10_tuberack_nest_4x50ml_6x15ml_conical", "C2", "Reagent Tube" - ) - tartrazine_tube = tube_rack["A3"] - water_tube_1 = tube_rack["A4"] - water_tube_2 = tube_rack["B3"] - sample_plate_1 = ctx.load_labware( - "corning_96_wellplate_360ul_flat", "D1", "Sample Plate 1" - ) - sample_plate_2 = ctx.load_labware( - "corning_96_wellplate_360ul_flat", "D2", "Sample Plate 2" + hs: HeaterShakerContext = protocol.load_module(helpers.hs_str, "A1") # type: ignore[assignment] + # Load Plates based off of number_of_plates parameter + available_deck_slots = ["D1", "D2", "C1", "B1"] + sample_plate_list = [] + for plate_num, slot in zip(range(number_of_plates), available_deck_slots): + plate = protocol.load_labware(plate_type, slot, f"Sample Plate {plate_num + 1}") + sample_plate_list.append(plate) + available_tip_rack_slots = ["D3", "C3", "B3", "B2"] + # LOAD PIPETTES AND TIP RACKS + # 50 CHANNEL + tip_racks_50 = [] + for plate_num, slot_2 in zip(range(number_of_plates), available_tip_rack_slots): + tiprack_50 = protocol.load_labware("opentrons_flex_96_tiprack_50ul", slot_2) + tip_racks_50.append(tiprack_50) + p50 = protocol.load_instrument( + f"flex_{channels}_50", "left", tip_racks=tip_racks_50 ) - sample_plate_3 = ctx.load_labware( - "corning_96_wellplate_360ul_flat", "C1", "Sample Plate 3" - ) - sample_plate_4 = ctx.load_labware( - "corning_96_wellplate_360ul_flat", "B1", "Sample Plate 4" + # 1000 CHANNEL + tiprack_1000_1 = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "A2") + p1000 = protocol.load_instrument( + f"flex_{channels}_1000", "right", tip_racks=[tiprack_1000_1] ) + # DETERMINE RESERVOIR BASED OFF # OF PIPETTE CHANNELS + # 1 CHANNEL = TUBE RACK + if p50.active_channels == 1: + reservoir = protocol.load_labware( + "opentrons_10_tuberack_nest_4x50ml_6x15ml_conical", "C2", "Reservoir" + ) + water_max_vol = reservoir["A3"].max_volume - 500 + reservoir_wells = reservoir.wells()[6:] # Skip first 4 bc they are 15ml + else: + # 8 CHANNEL = 12 WELL RESERVOIR + reservoir = protocol.load_labware("nest_12_reservoir_15ml", "C2", "Reservoir") + water_max_vol = reservoir["A1"].max_volume - 500 + reservoir_wells = reservoir.wells()[ + 1: + ] # Skip A1 as it's reserved for tartrazine - sample_plate_list = [sample_plate_1, sample_plate_2, sample_plate_3, sample_plate_4] - tiprack_50_1 = ctx.load_labware("opentrons_flex_96_tiprack_50ul", "D3") - tiprack_50_2 = ctx.load_labware("opentrons_flex_96_tiprack_50ul", "C3") - tiprack_50_3 = ctx.load_labware("opentrons_flex_96_tiprack_50ul", "B3") - tiprack_1000_1 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "A2") - tip_racks = [tiprack_50_1, tiprack_50_2, tiprack_50_3] + # LABEL RESERVOIR WELLS AND DETERMINE NEEDED LIQUID + tartrazine_well = reservoir["A1"] + # NEEDED TARTRAZINE + needed_tartrazine: float = ( + float(number_of_plates) * 96.0 + ) * 10.0 + 1000.0 # loading extra as a safety factor + # NEEDED WATER + needed_water: float = ( + float(number_of_plates) * 96.0 * 250 + ) # loading extra as a safety factor + # CALCULATING NEEDED # OF WATER WELLS + needed_wells = round(needed_water / water_max_vol) + water_wells = [] + for i in range(needed_wells + 1): + water_wells.append(reservoir_wells[i]) - # Pipette - p50 = ctx.load_instrument("flex_1channel_50", "left", tip_racks=tip_racks) - p1000 = ctx.load_instrument( - "flex_1channel_1000", "right", tip_racks=[tiprack_1000_1] - ) + def _mix_tartrazine(pipette: InstrumentContext, well_to_probe: Well) -> None: + """Mix Tartrazine.""" + # Mix step is needed to ensure tartrazine does not settle between plates. + pipette.pick_up_tip() + top_of_tartrazine = helpers.find_liquid_height(pipette, well_to_probe) + for i in range(20): + p50.aspirate(1, well_to_probe.bottom(z=1)) + p50.dispense(1, well_to_probe.bottom(z=top_of_tartrazine + 1)) + pipette.return_tip() - # Probe wells + # LOAD LIQUIDS AND PROBE WELLS liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { - "Tartrazine": [{"well": tartrazine_tube, "volume": 45.0}], - "Water": [{"well": [water_tube_1, water_tube_2], "volume": 45.0}], + "Tartrazine": [{"well": tartrazine_well, "volume": needed_tartrazine}], + "Water": [{"well": water_wells, "volume": water_max_vol}], } - helpers.find_liquid_height_of_loaded_liquids(ctx, liquid_vols_and_wells, p50) - + helpers.find_liquid_height_of_loaded_liquids(protocol, liquid_vols_and_wells, p50) + tip_count = 1 * p50.active_channels # number of 50 ul tip uses. + p50.reset_tipracks() i = 0 all_percent_error_dict = {} cv_dict = {} - vol = 0.0 - tip_count = 0 + vol = 0.0 # counter to track available water volume + water_tip_count = 0 * p1000.active_channels # number of 1000 ul tip uses + well_num = 0 # index of well being used for water for sample_plate in sample_plate_list[:number_of_plates]: - deck_locations = ["D1", "D2", "C1", "B1"] - p1000.pick_up_tip() - for well in sample_plate.wells(): - if vol < 45000: - tube_of_choice = water_tube_1 + return_location = sample_plate.parent + # Mix Tartrazine to ensure no settling as occurred + _mix_tartrazine(p50, tartrazine_well) + tip_count += 1 * p50.active_channels + # Determine list of wells to probe + if p50.active_channels == 1: + well_list = sample_plate.wells() + elif p50.active_channels == 8: + well_list = sample_plate.rows()[0] + for well in well_list: + p1000.pick_up_tip() + # Determine which water well to aspirate from. + if vol < water_max_vol - 6000: + well_of_choice = water_wells[well_num] else: - tube_of_choice = water_tube_2 + well_num += 1 + well_of_choice = water_wells[well_num] + vol = 0.0 p50.pick_up_tip() - p1000.aspirate(190, tube_of_choice) - p1000.air_gap(5) - p1000.dispense(5, well.top()) + p1000.aspirate(190, well_of_choice) + p1000.air_gap(10) + p1000.dispense(10, well.top()) p1000.dispense(190, well) - vol += 190 - height = helpers.find_liquid_height(p50, tartrazine_tube) - p50.aspirate(10, tartrazine_tube.bottom(z=height)) + # Two blow outs ensures water is completely removed from pipette + p1000.blow_out(well.top()) + protocol.delay(minutes=0.1) + p1000.blow_out(well.top()) + vol += 190 * p1000.active_channels + # Probe to find liquid height of tartrazine to ensure correct amount is aspirated + height = helpers.find_liquid_height(p50, tartrazine_well) + if height <= 0.0: + # If a negative tartrazine height is found, + # the protocol will pause, prompt a refill, and reprobe. + protocol.pause("Fill tartrazine") + height = helpers.find_liquid_height(p50, tartrazine_well) + p50.aspirate(10, tartrazine_well.bottom(z=height), rate=0.15) p50.air_gap(5) p50.dispense(5, well.top()) - p50.dispense(10, well.bottom(z=0.5)) + p50.dispense(10, well.bottom(z=0.5), rate=0.15) + p50.blow_out() + protocol.delay(minutes=0.1) p50.blow_out() p50.return_tip() - tip_count += 1 - if tip_count >= (96 * 3): + tip_count += p50.active_channels + if tip_count >= (96 * len(tip_racks_50)): p50.reset_tipracks() - p1000.return_tip() - helpers.move_labware_to_hs(ctx, sample_plate, hs, hs_adapter) - helpers.set_hs_speed(ctx, hs, 1500, 2.0, True) + tip_count = 0 + p1000.return_tip() + water_tip_count += p1000.active_channels + if water_tip_count >= 96: + p1000.reset_tipracks() + water_tip_count = 0 + # Move labware to heater shaker to be mixed + helpers.move_labware_to_hs(protocol, sample_plate, hs, hs) + helpers.set_hs_speed(protocol, hs, 1500, 2.0, True) hs.open_labware_latch() + # Initialize plate reader plate_reader.close_lid() plate_reader.initialize("single", [450]) plate_reader.open_lid() - ctx.move_labware(sample_plate, plate_reader, use_gripper=True) + # Move sample plate into plate reader + protocol.move_labware(sample_plate, plate_reader, use_gripper=True) sample_plate_name = "sample plate_" + str(i + 1) csv_string = sample_plate_name + "_" + str(datetime.now()) plate_reader.close_lid() result = plate_reader.read(csv_string) + # Calculate CV and % error of expected value. for wavelength in result: dict_of_wells = result[wavelength] readings_and_wells = dict_of_wells.items() @@ -145,11 +221,15 @@ def run(ctx: ProtocolContext) -> None: "SD": standard_deviation, "Avg Percent Error": avg_percent_error, } + # Move Plate back to original location all_percent_error_dict[sample_plate_name] = percent_error_dict plate_reader.open_lid() - ctx.move_labware(sample_plate, deck_locations[i], use_gripper=True) + protocol.comment( + f"------plate {sample_plate}. {cv_dict[sample_plate_name]}------" + ) + protocol.move_labware(sample_plate, return_location, use_gripper=True) i += 1 # Print percent error dictionary - ctx.comment("Percent Error: " + str(all_percent_error_dict)) + protocol.comment("Percent Error: " + str(all_percent_error_dict)) # Print cv dictionary - ctx.comment("Plate Reader result: " + str(cv_dict)) + protocol.comment("Plate Reader Result: " + str(cv_dict)) diff --git a/abr-testing/abr_testing/protocols/active_protocols/4_Illumina DNA Enrichment.py b/abr-testing/abr_testing/protocols/active_protocols/4_Illumina DNA Enrichment.py new file mode 100644 index 00000000000..ff9a9807c92 --- /dev/null +++ b/abr-testing/abr_testing/protocols/active_protocols/4_Illumina DNA Enrichment.py @@ -0,0 +1,1016 @@ +"""DVT1ABR4: Illumina DNA Enrichment.""" +from opentrons.protocol_api import ( + ParameterContext, + ProtocolContext, + Labware, + Well, + InstrumentContext, +) +from opentrons import types +from abr_testing.protocols import helpers +from opentrons.protocol_api.module_contexts import ( + HeaterShakerContext, + MagneticBlockContext, + ThermocyclerContext, + TemperatureModuleContext, +) +from opentrons.hardware_control.modules.types import ThermocyclerStep +from typing import List, Dict + + +metadata = { + "protocolName": "Illumina DNA Enrichment v4 with TC Auto Sealing Lid", + "author": "Opentrons ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.21", +} + +# SCRIPT SETTINGS +DRYRUN = False # True = skip incubation times, shorten mix, for testing purposes +USE_GRIPPER = True # True = Uses Gripper, False = Manual Move +TIP_TRASH = False # True = Used tips go in Trash, False = Used tips go back into rack +HYBRID_PAUSE = True # True = sets a pause on the Hybridization + +# PROTOCOL SETTINGS +COLUMNS = 4 # 1-4 +HYBRIDDECK = True +HYBRIDTIME = 1.6 # Hours + +# PROTOCOL BLOCKS +STEP_VOLPOOL = 0 +STEP_HYB = 0 +STEP_CAPTURE = 1 +STEP_WASH = 1 +STEP_PCR = 1 +STEP_PCRDECK = 1 +STEP_CLEANUP = 1 + +p200_tips = 0 +p50_tips = 0 +total_waste_volume = 0.0 + + +RUN = 1 + + +def add_parameters(parameters: ParameterContext) -> None: + """Add parameters.""" + helpers.create_hs_speed_parameter(parameters) + helpers.create_dot_bottom_parameter(parameters) + helpers.create_disposable_lid_parameter(parameters) + helpers.create_tc_lid_deck_riser_parameter(parameters) + helpers.create_disposable_lid_trash_location(parameters) + helpers.create_deactivate_modules_parameter(parameters) + + +def run(protocol: ProtocolContext) -> None: + """Protocol.""" + heater_shaker_speed = protocol.params.heater_shaker_speed # type: ignore[attr-defined] + dot_bottom = protocol.params.dot_bottom # type: ignore[attr-defined] + disposable_lid = protocol.params.disposable_lid # type: ignore[attr-defined] + deck_riser = protocol.params.deck_riser # type: ignore[attr-defined] + trash_lid = protocol.params.trash_lid # type: ignore[attr-defined] + deactivate_modules_bool = protocol.params.deactivate_modules # type: ignore[attr-defined] + helpers.comment_protocol_version(protocol, "01") + + unused_lids: List[Labware] = [] + used_lids: List[Labware] = [] + global p200_tips + global p50_tips + + protocol.comment("THIS IS A DRY RUN") if DRYRUN else protocol.comment( + "THIS IS A REACTION RUN" + ) + protocol.comment("USED TIPS WILL GO IN TRASH") if TIP_TRASH else protocol.comment( + "USED TIPS WILL BE RE-RACKED" + ) + + # DECK SETUP AND LABWARE + # ========== FIRST ROW =========== + heatershaker: HeaterShakerContext = protocol.load_module( + helpers.hs_str, "1" + ) # type: ignore[assignment] + heatershaker.close_labware_latch() + sample_plate_2 = heatershaker.load_labware( + "thermoscientificnunc_96_wellplate_1300ul" + ) + reservoir = protocol.load_labware("nest_96_wellplate_2ml_deep", "2", "Liquid Waste") + temp_block: TemperatureModuleContext = protocol.load_module( + helpers.temp_str, "3" + ) # type: ignore[assignment] + reagent_plate, temp_adapter = helpers.load_temp_adapter_and_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", temp_block, "Reagent Plate" + ) + # ========== SECOND ROW ========== + MAG_PLATE_SLOT: MagneticBlockContext = protocol.load_module( + helpers.mag_str, "C1" + ) # type: ignore[assignment] + tiprack_200_1 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "5") + tiprack_50_1 = protocol.load_labware("opentrons_flex_96_tiprack_50ul", "6") + # Opentrons tough pcr auto sealing lids + if disposable_lid: + unused_lids = helpers.load_disposable_lids(protocol, 3, ["C4"], deck_riser) + # ========== THIRD ROW =========== + thermocycler: ThermocyclerContext = protocol.load_module( + helpers.tc_str + ) # type: ignore[assignment] + sample_plate_1 = thermocycler.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt" + ) + thermocycler.open_lid() + tiprack_200_2 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "8") + tiprack_50_2 = protocol.load_labware("opentrons_flex_96_tiprack_50ul", "9") + # ========== FOURTH ROW ========== + tiprack_200_3 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "11") + trash_bin = protocol.load_trash_bin("A3") + # reagent + AMPure = reservoir["A1"] + SMB = reservoir["A2"] + + EtOH = reservoir["A4"] + RSB = reservoir["A5"] + Liquid_trash_well_1 = reservoir["A9"] + Liquid_trash_well_2 = reservoir["A10"] + Liquid_trash_well_3 = reservoir["A11"] + Liquid_trash_well_4 = reservoir["A12"] + liquid_trash_list = { + Liquid_trash_well_1: 0.0, + Liquid_trash_well_2: 0.0, + Liquid_trash_well_3: 0.0, + Liquid_trash_well_4: 0.0, + } + + def trash_liquid( + protocol: ProtocolContext, + pipette: InstrumentContext, + vol_to_trash: float, + liquid_trash_list: Dict[Well, float], + ) -> None: + """Determine which wells to use as liquid waste.""" + remaining_volume = vol_to_trash + max_capacity = 1500.0 + # Determine liquid waste location depending on current total volume + # Distribute the liquid volume sequentially + for well, current_volume in liquid_trash_list.items(): + if remaining_volume <= 0.0: + break + available_capacity = max_capacity - current_volume + if available_capacity < remaining_volume: + continue + pipette.dispense(remaining_volume, well.top()) + protocol.delay(minutes=0.1) + pipette.blow_out(well.top()) + liquid_trash_list[well] += remaining_volume + if pipette.current_volume <= 0.0: + break + + # Will Be distributed during the protocol + EEW_1 = sample_plate_2.wells_by_name()["A9"] + EEW_2 = sample_plate_2.wells_by_name()["A10"] + EEW_3 = sample_plate_2.wells_by_name()["A11"] + EEW_4 = sample_plate_2.wells_by_name()["A12"] + + NHB2 = reagent_plate.wells_by_name()["A1"] + Panel = reagent_plate.wells_by_name()["A2"] + EHB2 = reagent_plate.wells_by_name()["A3"] + Elute = reagent_plate.wells_by_name()["A4"] + ET2 = reagent_plate.wells_by_name()["A5"] + PPC = reagent_plate.wells_by_name()["A6"] + EPM = reagent_plate.wells_by_name()["A7"] + + # pipette + p1000 = protocol.load_instrument( + "flex_8channel_1000", + "left", + tip_racks=[tiprack_200_1, tiprack_200_2, tiprack_200_3], + ) + p50 = protocol.load_instrument( + "flex_8channel_50", "right", tip_racks=[tiprack_50_1, tiprack_50_2] + ) + reagent_plate.columns()[3] + # Load liquids and probe + liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { + "Reagents": [ + {"well": reagent_plate.columns()[3], "volume": 75.0}, + {"well": reagent_plate.columns()[4], "volume": 15.0}, + {"well": reagent_plate.columns()[5], "volume": 20.0}, + {"well": reagent_plate.columns()[6], "volume": 65.0}, + ], + "AMPure": [{"well": reservoir.columns()[0], "volume": 120.0}], + "SMB": [{"well": reservoir.columns()[1], "volume": 750.0}], + "EtOH": [{"well": reservoir.columns()[3], "volume": 900.0}], + "RSB": [{"well": reservoir.columns()[4], "volume": 96.0}], + "Wash": [ + {"well": sample_plate_2.columns()[8], "volume": 1000.0}, + {"well": sample_plate_2.columns()[9], "volume": 1000.0}, + {"well": sample_plate_2.columns()[10], "volume": 1000.0}, + {"well": sample_plate_2.columns()[11], "volume": 1000.0}, + ], + "Samples": [{"well": sample_plate_1.wells(), "volume": 150.0}], + } + helpers.find_liquid_height_of_loaded_liquids(protocol, liquid_vols_and_wells, p50) + # tip and sample tracking + if COLUMNS == 1: + column_1_list = ["A1"] # Plate 1 + column_2_list = ["A1"] # Plate 2 + column_3_list = ["A4"] # Plate 2 + column_4_list = ["A4"] # Plate 1 + column_5_list = ["A7"] # Plate 2 + column_6_list = ["A7"] # Plate 1 + WASHES = [EEW_1] + if COLUMNS == 2: + column_1_list = ["A1", "A2"] # Plate 1 + column_2_list = ["A1", "A2"] # Plate 2 + column_3_list = ["A4", "A5"] # Plate 2 + column_4_list = ["A4", "A5"] # Plate 1 + column_5_list = ["A7", "A8"] # Plate 2 + column_6_list = ["A7", "A8"] # Plate 1 + WASHES = [EEW_1, EEW_2] + if COLUMNS == 3: + column_1_list = ["A1", "A2", "A3"] # Plate 1 + column_2_list = ["A1", "A2", "A3"] # Plate 2 + column_3_list = ["A4", "A5", "A6"] # Plate 2 + column_4_list = ["A4", "A5", "A6"] # Plate 1 + column_5_list = ["A7", "A8", "A9"] # Plate 2 + column_6_list = ["A7", "A8", "A9"] # Plate 1 + WASHES = [EEW_1, EEW_2, EEW_3] + if COLUMNS == 4: + column_1_list = ["A1", "A2", "A3", "A4"] # Plate 1 + column_2_list = ["A1", "A2", "A3", "A4"] # Plate 2 + column_3_list = ["A5", "A6", "A7", "A8"] # Plate 2 + column_4_list = ["A5", "A6", "A7", "A8"] # Plate 1 + column_5_list = ["A9", "A10", "A11", "A12"] # Plate 2 + column_6_list = ["A9", "A10", "A11", "A12"] # Plate 1 + WASHES = [EEW_1, EEW_2, EEW_3, EEW_4] + + def tipcheck() -> None: + """Tip tracking function.""" + if p200_tips >= 3 * 12: + p1000.reset_tipracks() + p200_tips == 0 + if p50_tips >= 2 * 12: + p50.reset_tipracks() + p50_tips == 0 + + # commands + for loop in range(RUN): + thermocycler.open_lid() + heatershaker.open_labware_latch() + if DRYRUN is False: + if STEP_HYB == 1: + protocol.comment("SETTING THERMO and TEMP BLOCK Temperature") + thermocycler.set_block_temperature(4) + thermocycler.set_lid_temperature(100) + temp_block.set_temperature(4) + else: + protocol.comment("SETTING THERMO and TEMP BLOCK Temperature") + thermocycler.set_block_temperature(58) + thermocycler.set_lid_temperature(58) + heatershaker.set_and_wait_for_temperature(58) + heatershaker.close_labware_latch() + + # Sample Plate contains 30ul of DNA + + if STEP_VOLPOOL == 1: + protocol.comment("==============================================") + protocol.comment("--> Quick Vol Pool") + protocol.comment("==============================================") + + if STEP_HYB == 1: + protocol.comment("==============================================") + protocol.comment("--> HYB") + protocol.comment("==============================================") + + protocol.comment("--> Adding NHB2") + NHB2Vol = 50 + for loop, X in enumerate(column_1_list): + p50.pick_up_tip() + p50.aspirate(NHB2Vol, NHB2.bottom(z=dot_bottom)) # original = () + p50.dispense( + NHB2Vol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("--> Adding Panel") + PanelVol = 10 + for loop, X in enumerate(column_1_list): + p50.pick_up_tip() + p50.aspirate(PanelVol, Panel.bottom(z=dot_bottom)) # original = () + p50.dispense( + PanelVol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("--> Adding EHB2") + EHB2Vol = 10 + EHB2MixRep = 10 if DRYRUN is False else 1 + EHB2MixVol = 90 + for loop, X in enumerate(column_1_list): + p1000.pick_up_tip() + p1000.aspirate(EHB2Vol, EHB2.bottom(z=dot_bottom)) # original = () + p1000.dispense( + EHB2Vol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p1000.move_to(sample_plate_1[X].bottom(z=dot_bottom)) # original = () + p1000.mix(EHB2MixRep, EHB2MixVol) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p50_tips += 1 + tipcheck() + + if HYBRIDDECK: + protocol.comment("Hybridize on Deck") + if disposable_lid: + ( + lid_on_plate, + unused_lids, + used_lids, + ) = helpers.use_disposable_lid_with_tc( + protocol, unused_lids, used_lids, sample_plate_1, thermocycler + ) + else: + thermocycler.close_lid() + if DRYRUN is False: + profile_TAGSTOP: List[ThermocyclerStep] = [ + {"temperature": 98, "hold_time_minutes": 5}, + {"temperature": 97, "hold_time_minutes": 1}, + {"temperature": 95, "hold_time_minutes": 1}, + {"temperature": 93, "hold_time_minutes": 1}, + {"temperature": 91, "hold_time_minutes": 1}, + {"temperature": 89, "hold_time_minutes": 1}, + {"temperature": 87, "hold_time_minutes": 1}, + {"temperature": 85, "hold_time_minutes": 1}, + {"temperature": 83, "hold_time_minutes": 1}, + {"temperature": 81, "hold_time_minutes": 1}, + {"temperature": 79, "hold_time_minutes": 1}, + {"temperature": 77, "hold_time_minutes": 1}, + {"temperature": 75, "hold_time_minutes": 1}, + {"temperature": 73, "hold_time_minutes": 1}, + {"temperature": 71, "hold_time_minutes": 1}, + {"temperature": 69, "hold_time_minutes": 1}, + {"temperature": 67, "hold_time_minutes": 1}, + {"temperature": 65, "hold_time_minutes": 1}, + {"temperature": 63, "hold_time_minutes": 1}, + {"temperature": 62, "hold_time_minutes": HYBRIDTIME * 60}, + ] + thermocycler.execute_profile( + steps=profile_TAGSTOP, repetitions=1, block_max_volume=100 + ) + thermocycler.set_block_temperature(62) + if HYBRID_PAUSE: + protocol.comment("HYBRIDIZATION PAUSED") + thermocycler.set_block_temperature(10) + thermocycler.open_lid() + if disposable_lid: + if trash_lid: + protocol.move_labware(lid_on_plate, trash_bin, use_gripper=True) + elif len(used_lids) <= 1: + protocol.move_labware(lid_on_plate, "B4", use_gripper=True) + else: + protocol.move_labware( + lid_on_plate, used_lids[-2], use_gripper=True + ) + else: + protocol.comment("Hybridize off Deck") + + if STEP_CAPTURE == 1: + protocol.comment("==============================================") + protocol.comment("--> Capture") + protocol.comment("==============================================") + # Standard Setup + + if DRYRUN is False: + protocol.comment("SETTING THERMO and TEMP BLOCK Temperature") + thermocycler.set_block_temperature(58) + thermocycler.set_lid_temperature(58) + + if DRYRUN is False: + heatershaker.set_and_wait_for_temperature(58) + + protocol.comment("--> Transfer Hybridization") + TransferSup = 100 + for loop, X in enumerate(column_1_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_1[X].bottom(z=0.5)) + p1000.aspirate(TransferSup + 1, rate=0.25) + p1000.dispense( + TransferSup + 1, sample_plate_2[column_2_list[loop]].bottom(z=1) + ) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + if disposable_lid: + ( + lid_on_plate, + unused_lids, + used_lids, + ) = helpers.use_disposable_lid_with_tc( + protocol, + unused_lids, + used_lids, + sample_plate_1, + thermocycler, + ) + else: + thermocycler.close_lid() + + protocol.comment("--> ADDING SMB") + SMBVol = 250 + SMBMixRPM = heater_shaker_speed + SMBMixRep = 5.0 if DRYRUN is False else 0.1 # minutes + SMBPremix = 3 if DRYRUN is False else 1 + # ============================== + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.mix(SMBPremix, 200, SMB.bottom(z=1)) + p1000.aspirate(SMBVol / 2, SMB.bottom(z=1), rate=0.25) + p1000.dispense(SMBVol / 2, sample_plate_2[X].top(z=-7), rate=0.25) + p1000.aspirate(SMBVol / 2, SMB.bottom(z=1), rate=0.25) + p1000.dispense(SMBVol / 2, sample_plate_2[X].bottom(z=1), rate=0.25) + p1000.default_speed = 5 + p1000.move_to(sample_plate_2[X].bottom(z=5)) + for Mix in range(2): + p1000.aspirate(100, rate=0.5) + p1000.move_to(sample_plate_2[X].bottom(z=1)) + p1000.aspirate(80, rate=0.5) + p1000.dispense(80, rate=0.5) + p1000.move_to(sample_plate_2[X].bottom(z=5)) + p1000.dispense(100, rate=0.5) + Mix += 1 + p1000.blow_out(sample_plate_2[X].top(z=-7)) + p1000.default_speed = 400 + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.move_to(sample_plate_2[X].top(z=0)) + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + # ============================== + helpers.set_hs_speed(protocol, heatershaker, SMBMixRPM, SMBMixRep, True) + + # GRIPPER MOVE sample_plate_2 FROM heatershaker TO MAGPLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, MAG_PLATE_SLOT + ) + + thermocycler.open_lid() + if disposable_lid: + if trash_lid: + protocol.move_labware(lid_on_plate, trash_bin, use_gripper=True) + elif len(used_lids) <= 1: + protocol.move_labware(lid_on_plate, "B4", use_gripper=True) + else: + protocol.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + + if DRYRUN is False: + protocol.delay(minutes=2) + + protocol.comment("==============================================") + protocol.comment("--> WASH") + protocol.comment("==============================================") + # Setting Labware to Resume at Cleanup 1 + + protocol.comment("--> Remove SUPERNATANT") + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(4)) + p1000.aspirate(200, rate=0.25) + trash_liquid(protocol, p1000, 200.0, liquid_trash_list) + p1000.move_to(sample_plate_2[X].bottom(0.5)) + p1000.aspirate(200, rate=0.25) + trash_liquid(protocol, p1000, 200.0, liquid_trash_list) + p1000.aspirate(20) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + # GRIPPER MOVE sample_plate_2 FROM MAGPLATE TO heatershaker + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + + protocol.comment("--> Repeating 6 washes") + washreps = 6 + washcount = 0 + for wash in range(washreps): + + protocol.comment("--> Adding EEW") + EEWVol = 200 + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.aspirate( + EEWVol, WASHES[loop].bottom(z=dot_bottom) + ) # original = () + p1000.dispense( + EEWVol, sample_plate_2[X].bottom(z=dot_bottom) + ) # original = () + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + helpers.set_hs_speed( + protocol, heatershaker, int(heater_shaker_speed * 0.9), 4.0, True + ) + heatershaker.open_labware_latch() + + if DRYRUN is False: + protocol.delay(seconds=5 * 60) + + # GRIPPER MOVE sample_plate_2 FROM heatershaker TO MAGPLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, MAG_PLATE_SLOT + ) + + if DRYRUN is False: + protocol.delay(seconds=1 * 60) + + protocol.comment("--> Removing Supernatant") + RemoveSup = 200 + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=3.5)) + p1000.aspirate(RemoveSup - 100, rate=0.25) + protocol.delay(minutes=0.1) + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(100, rate=0.25) + trash_liquid(protocol, p1000, RemoveSup, liquid_trash_list) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM MAGPLATE TO heatershaker + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + washcount += 1 + + protocol.comment("--> Adding EEW") + EEWVol = 200 + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.aspirate( + EEWVol, WASHES[loop].bottom(z=dot_bottom) + ) # original = () + p1000.dispense( + EEWVol, sample_plate_2[X].bottom(z=dot_bottom) + ) # original = () + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + helpers.set_hs_speed( + protocol, heatershaker, int(heater_shaker_speed * 0.9), 4.0, True + ) + + if DRYRUN is False: + protocol.delay(seconds=1 * 60) + + protocol.comment("--> Transfer Hybridization") + TransferSup = 200 + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(TransferSup, rate=0.25) + p1000.dispense( + TransferSup, sample_plate_2[column_3_list[loop]].bottom(z=1) + ) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + if DRYRUN is False: + protocol.delay(seconds=5 * 60) + + # GRIPPER MOVE sample_plate_2 FROM heatershaker TO MAGPLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, MAG_PLATE_SLOT + ) + if DRYRUN is False: + protocol.delay(seconds=1 * 60) + + protocol.comment("--> Removing Supernatant") + RemoveSup = 200 + for loop, X in enumerate(column_3_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=3.5)) + p1000.aspirate(RemoveSup - 100, rate=0.25) + protocol.delay(minutes=0.1) + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(100, rate=0.25) + p1000.move_to(sample_plate_2[X].top(z=0.5)) + trash_liquid(protocol, p1000, 100, liquid_trash_list) + p1000.aspirate(20) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + protocol.comment("--> Removing Residual") + for loop, X in enumerate(column_3_list): + p50.pick_up_tip() + p50.move_to(sample_plate_2[X].bottom(z=dot_bottom)) # original = z=0 + p50.aspirate(50, rate=0.25) + p50.default_speed = 200 + trash_liquid(protocol, p50, 50, liquid_trash_list) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("==============================================") + protocol.comment("--> ELUTE") + protocol.comment("==============================================") + + protocol.comment("--> Adding Elute") + EluteVol = 23 + for loop, X in enumerate(column_3_list): + p50.pick_up_tip() + p50.aspirate(EluteVol, Elute.bottom(z=dot_bottom)) # original = () + p50.dispense( + EluteVol, sample_plate_2[X].bottom(z=dot_bottom) + ) # original = () + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM MAGPLATE TO heatershaker + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + # ============================================================================================ + helpers.set_hs_speed( + protocol, heatershaker, int(heater_shaker_speed * 0.9), 2.0, True + ) + heatershaker.open_labware_latch() + + if DRYRUN is False: + protocol.delay(minutes=2) + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM heatershaker TO MAGPLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, MAG_PLATE_SLOT + ) + protocol.comment("--> Transfer Elution") + TransferSup = 21 + for loop, X in enumerate(column_3_list): + p50.pick_up_tip() + p50.move_to(sample_plate_2[X].bottom(z=0.5)) + p50.aspirate(TransferSup + 1, rate=0.25) + p50.dispense( + TransferSup + 1, sample_plate_1[column_4_list[loop]].bottom(z=1) + ) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("--> Adding ET2") + ET2Vol = 4 + ET2MixRep = 10 if DRYRUN is False else 1 + ET2MixVol = 20 + for loop, X in enumerate(column_4_list): + p50.pick_up_tip() + p50.aspirate(ET2Vol, ET2.bottom(z=dot_bottom)) # original = () + p50.dispense( + ET2Vol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.move_to(sample_plate_1[X].bottom(z=dot_bottom)) # original = () + p50.mix(ET2MixRep, ET2MixVol) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + if STEP_PCR == 1: + protocol.comment("==============================================") + protocol.comment("--> AMPLIFICATION") + protocol.comment("==============================================") + + protocol.comment("--> Adding PPC") + PPCVol = 5 + for loop, X in enumerate(column_4_list): + p50.pick_up_tip() + p50.aspirate(PPCVol, PPC.bottom(z=dot_bottom)) # original = () + p50.dispense( + PPCVol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("--> Adding EPM") + EPMVol = 20 + EPMMixRep = 10 if DRYRUN is False else 1 + EPMMixVol = 45 + for loop, X in enumerate(column_4_list): + p50.pick_up_tip() + p50.aspirate(EPMVol, EPM.bottom(z=dot_bottom)) # original = () + p50.dispense( + EPMVol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.move_to(sample_plate_1[X].bottom(z=dot_bottom)) # original = () + p50.mix(EPMMixRep, EPMMixVol) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + if DRYRUN is False: + heatershaker.deactivate_heater() + + if STEP_PCRDECK == 1: + if DRYRUN is False: + if DRYRUN is False: + if disposable_lid: + ( + lid_on_plate, + unused_lids, + used_lids, + ) = helpers.use_disposable_lid_with_tc( + protocol, + unused_lids, + used_lids, + sample_plate_1, + thermocycler, + ) + else: + thermocycler.close_lid() + profile_PCR_1: List[ThermocyclerStep] = [ + {"temperature": 98, "hold_time_seconds": 45} + ] + thermocycler.execute_profile( + steps=profile_PCR_1, repetitions=1, block_max_volume=50 + ) + profile_PCR_2: List[ThermocyclerStep] = [ + {"temperature": 98, "hold_time_seconds": 30}, + {"temperature": 60, "hold_time_seconds": 30}, + {"temperature": 72, "hold_time_seconds": 30}, + ] + thermocycler.execute_profile( + steps=profile_PCR_2, repetitions=12, block_max_volume=50 + ) + profile_PCR_3: List[ThermocyclerStep] = [ + {"temperature": 72, "hold_time_minutes": 1} + ] + thermocycler.execute_profile( + steps=profile_PCR_3, repetitions=1, block_max_volume=50 + ) + thermocycler.set_block_temperature(10) + + thermocycler.open_lid() + if disposable_lid: + if trash_lid: + protocol.move_labware(lid_on_plate, trash_bin, use_gripper=True) + elif len(used_lids) <= 1: + protocol.move_labware(lid_on_plate, "B4", use_gripper=True) + else: + protocol.move_labware( + lid_on_plate, used_lids[-2], use_gripper=True + ) + + if STEP_CLEANUP == 1: + protocol.comment("==============================================") + protocol.comment("--> Cleanup") + protocol.comment("==============================================") + + # GRIPPER MOVE sample_plate_2 FROM MAGPLATE TO heatershaker + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + + protocol.comment("--> Transfer Elution") + TransferSup = 45 + for loop, X in enumerate(column_4_list): + p50.pick_up_tip() + p50.move_to(sample_plate_1[X].bottom(z=0.5)) + p50.aspirate(TransferSup + 1, rate=0.25) + p50.dispense( + TransferSup + 1, sample_plate_2[column_5_list[loop]].bottom(z=1) + ) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("--> ADDING AMPure (0.8x)") + AMPureVol = 40.5 + AMPureMixRep = 5.0 if DRYRUN is False else 0.1 + AMPurePremix = 3 if DRYRUN is False else 1 + # ========NEW SINGLE TIP DISPENSE=========== + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.mix(AMPurePremix, AMPureVol + 10, AMPure.bottom(z=1)) + p1000.aspirate(AMPureVol, AMPure.bottom(z=1), rate=0.25) + p1000.dispense(AMPureVol, sample_plate_2[X].bottom(z=1), rate=0.25) + p1000.default_speed = 5 + p1000.move_to(sample_plate_2[X].bottom(z=5)) + for Mix in range(2): + p1000.aspirate(60, rate=0.5) + p1000.move_to(sample_plate_2[X].bottom(z=1)) + p1000.aspirate(60, rate=0.5) + p1000.dispense(60, rate=0.5) + p1000.move_to(sample_plate_2[X].bottom(z=5)) + p1000.dispense(30, rate=0.5) + Mix += 1 + p1000.blow_out(sample_plate_2[X].top(z=2)) + p1000.default_speed = 400 + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.move_to(sample_plate_2[X].top(z=0)) + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + # ========NEW HS MIX========================= + helpers.set_hs_speed( + protocol, + heatershaker, + int(heater_shaker_speed * 0.9), + AMPureMixRep, + True, + ) + + # GRIPPER MOVE PLATE FROM HEATER SHAKER TO MAG PLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, MAG_PLATE_SLOT + ) + + if DRYRUN is False: + protocol.delay(minutes=4) + + protocol.comment("--> Removing Supernatant") + RemoveSup = 200 + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=3.5)) + p1000.aspirate(RemoveSup - 100, rate=0.25) + protocol.delay(minutes=0.1) + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(100, rate=0.25) + p1000.default_speed = 5 + p1000.move_to(sample_plate_2[X].top(z=2)) + p1000.default_speed = 200 + trash_liquid(protocol, p1000, 200, liquid_trash_list) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + for X_times in range(2): + protocol.comment("--> ETOH Wash") + ETOHMaxVol = 150 + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.aspirate(ETOHMaxVol, EtOH.bottom(z=1)) + p1000.move_to(EtOH.top(z=0)) + p1000.move_to(EtOH.top(z=-5)) + p1000.move_to(EtOH.top(z=0)) + p1000.move_to(sample_plate_2[X].top(z=-2)) + p1000.dispense(ETOHMaxVol, rate=1) + protocol.delay(minutes=0.1) + p1000.blow_out() + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.move_to(sample_plate_2[X].top(z=0)) + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + if DRYRUN is False: + protocol.delay(minutes=0.5) + + protocol.comment("--> Remove ETOH Wash") + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=3.5)) + p1000.aspirate(RemoveSup - 100, rate=0.25) + protocol.delay(minutes=0.1) + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(100, rate=0.25) + p1000.default_speed = 5 + p1000.move_to(sample_plate_2[X].top(z=2)) + p1000.default_speed = 200 + trash_liquid(protocol, p1000, RemoveSup, liquid_trash_list) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + if DRYRUN is False: + protocol.delay(minutes=2) + + protocol.comment("--> Removing Residual ETOH") + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.move_to( + sample_plate_2[X].bottom(z=dot_bottom) + ) # original = (z=0) + p1000.aspirate(50, rate=0.25) + p1000.default_speed = 200 + trash_liquid(protocol, p1000, 50, liquid_trash_list) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + if DRYRUN is False: + protocol.delay(minutes=1) + + # GRIPPER MOVE PLATE FROM MAG PLATE TO HEATER SHAKER + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + + protocol.comment("--> Adding RSB") + RSBVol = 32 + RSBMixRep = 1.0 if DRYRUN is False else 0.1 # minutes + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.aspirate(RSBVol, RSB.bottom(z=1)) + + p1000.move_to( + ( + sample_plate_2.wells_by_name()[X] + .center() + .move(types.Point(x=1.3 * 0.8, y=0, z=-4)) + ) + ) + p1000.dispense(RSBVol, rate=1) + p1000.move_to(sample_plate_2.wells_by_name()[X].bottom(z=1)) + p1000.aspirate(RSBVol, rate=1) + p1000.move_to( + ( + sample_plate_2.wells_by_name()[X] + .center() + .move(types.Point(x=0, y=1.3 * 0.8, z=-4)) + ) + ) + p1000.dispense(RSBVol, rate=1) + p1000.move_to(sample_plate_2.wells_by_name()[X].bottom(z=1)) + p1000.aspirate(RSBVol, rate=1) + p1000.move_to( + ( + sample_plate_2.wells_by_name()[X] + .center() + .move(types.Point(x=1.3 * -0.8, y=0, z=-4)) + ) + ) + p1000.dispense(RSBVol, rate=1) + p1000.move_to(sample_plate_2.wells_by_name()[X].bottom(z=1)) + p1000.aspirate(RSBVol, rate=1) + p1000.move_to( + ( + sample_plate_2.wells_by_name()[X] + .center() + .move(types.Point(x=0, y=1.3 * -0.8, z=-4)) + ) + ) + p1000.dispense(RSBVol, rate=1) + p1000.move_to(sample_plate_2.wells_by_name()[X].bottom(z=1)) + p1000.aspirate(RSBVol, rate=1) + p1000.dispense(RSBVol, rate=1) + + p1000.blow_out(sample_plate_2.wells_by_name()[X].center()) + p1000.move_to(sample_plate_2.wells_by_name()[X].top(z=5)) + p1000.move_to(sample_plate_2.wells_by_name()[X].top(z=0)) + p1000.move_to(sample_plate_2.wells_by_name()[X].top(z=5)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + if DRYRUN is False: + helpers.set_hs_speed( + protocol, + heatershaker, + int(heater_shaker_speed * 0.8), + RSBMixRep, + True, + ) + + # GRIPPER MOVE PLATE FROM HEATER SHAKER TO MAG PLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, MAG_PLATE_SLOT + ) + + if DRYRUN is False: + protocol.delay(minutes=3) + + protocol.comment("--> Transferring Supernatant") + TransferSup = 30 + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(TransferSup + 1, rate=0.25) + p1000.dispense( + TransferSup + 1, sample_plate_1[column_6_list[loop]].bottom(z=1) + ) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + liquids_to_probe_at_end = [ + Liquid_trash_well_1, + Liquid_trash_well_2, + Liquid_trash_well_3, + Liquid_trash_well_4, + ] + helpers.find_liquid_height_of_all_wells(protocol, p50, liquids_to_probe_at_end) + if deactivate_modules_bool: + helpers.deactivate_modules(protocol) diff --git a/abr-testing/abr_testing/protocols/active_protocols/5_96ch complex protocol with single tip Pick Up.py b/abr-testing/abr_testing/protocols/active_protocols/5_96ch complex protocol with single tip Pick Up.py index dc40db7f177..ca7506cf6f0 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/5_96ch complex protocol with single tip Pick Up.py +++ b/abr-testing/abr_testing/protocols/active_protocols/5_96ch complex protocol with single tip Pick Up.py @@ -1,14 +1,14 @@ """96 ch Test Single Tip and Gripper Moves.""" from opentrons.protocol_api import ( - ALL, + COLUMN, SINGLE, + ALL, ParameterContext, ProtocolContext, Labware, ) from opentrons.protocol_api.module_contexts import ( HeaterShakerContext, - MagneticBlockContext, ThermocyclerContext, TemperatureModuleContext, ) @@ -21,7 +21,7 @@ } requirements = { - "robotType": "OT-3", + "robotType": "Flex", "apiLevel": "2.21", } @@ -45,25 +45,31 @@ def add_parameters(parameters: ParameterContext) -> None: helpers.create_dot_bottom_parameter(parameters) helpers.create_disposable_lid_parameter(parameters) helpers.create_tc_lid_deck_riser_parameter(parameters) + helpers.create_deactivate_modules_parameter(parameters) -def run(ctx: ProtocolContext) -> None: +def run(protocol: ProtocolContext) -> None: """Protocol.""" - b = ctx.params.dot_bottom # type: ignore[attr-defined] - TIPRACK_96_NAME = ctx.params.tip_size # type: ignore[attr-defined] - disposable_lid = ctx.params.disposable_lid # type: ignore[attr-defined] - deck_riser = ctx.params.deck_riser # type: ignore[attr-defined] + b = protocol.params.dot_bottom # type: ignore[attr-defined] + TIPRACK_96_NAME = protocol.params.tip_size # type: ignore[attr-defined] + disposable_lid = protocol.params.disposable_lid # type: ignore[attr-defined] + deck_riser = protocol.params.deck_riser # type: ignore[attr-defined] + deactivate_modules_bool = protocol.params.deactivate_modules # type: ignore[attr-defined] - waste_chute = ctx.load_waste_chute() + waste_chute = protocol.load_waste_chute() + helpers.comment_protocol_version(protocol, "01") - thermocycler: ThermocyclerContext = ctx.load_module(helpers.tc_str) # type: ignore[assignment] - mag: MagneticBlockContext = ctx.load_module(helpers.mag_str, "A3") # type: ignore[assignment] - h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] - temperature_module: TemperatureModuleContext = ctx.load_module( + thermocycler: ThermocyclerContext = protocol.load_module( + helpers.tc_str + ) # type: ignore[assignment] + h_s: HeaterShakerContext = protocol.load_module( + helpers.hs_str, "D1" + ) # type: ignore[assignment] + temperature_module: TemperatureModuleContext = protocol.load_module( helpers.temp_str, "C1" ) # type: ignore[assignment] if disposable_lid: - unused_lids = helpers.load_disposable_lids(ctx, 3, ["A4"], deck_riser) + unused_lids = helpers.load_disposable_lids(protocol, 3, ["A2"], deck_riser) used_lids: List[Labware] = [] thermocycler.open_lid() h_s.open_labware_latch() @@ -75,16 +81,15 @@ def run(ctx: ProtocolContext) -> None: adapters = [temperature_module_adapter, h_s_adapter] - source_reservoir = ctx.load_labware(RESERVOIR_NAME, "D2") - dest_pcr_plate = ctx.load_labware(PCR_PLATE_96_NAME, "C2") + source_reservoir = protocol.load_labware(RESERVOIR_NAME, "D2") + dest_pcr_plate = protocol.load_labware(PCR_PLATE_96_NAME, "C2") + liquid_waste = protocol.load_labware("nest_1_reservoir_195ml", "B2", "Liquid Waste") - tip_rack_1 = ctx.load_labware( - TIPRACK_96_NAME, "A2", adapter=TIPRACK_96_ADAPTER_NAME + tip_rack_1 = protocol.load_labware( + TIPRACK_96_NAME, "A3", adapter="opentrons_flex_96_tiprack_adapter" ) - tip_rack_adapter = tip_rack_1.parent - - tip_rack_2 = ctx.load_labware(TIPRACK_96_NAME, "C3") - tip_rack_3 = ctx.load_labware(TIPRACK_96_NAME, "C4") + tip_rack_2 = protocol.load_labware(TIPRACK_96_NAME, "C3") + tip_rack_3 = protocol.load_labware(TIPRACK_96_NAME, "C4") tip_racks = [ tip_rack_1, @@ -92,14 +97,16 @@ def run(ctx: ProtocolContext) -> None: tip_rack_3, ] - pipette_96_channel = ctx.load_instrument( + pipette_96_channel = protocol.load_instrument( PIPETTE_96_CHANNEL_NAME, mount="left", tip_racks=tip_racks, liquid_presence_detection=True, ) - water = ctx.define_liquid(name="water", description="H₂O", display_color="#42AB2D") + water = protocol.define_liquid( + name="water", description="H₂O", display_color="#42AB2D" + ) source_reservoir.wells_by_name()["A1"].load_liquid(liquid=water, volume=29000) def run_moves( @@ -123,7 +130,7 @@ def move_to_locations( def reset_labware() -> None: """Reset the labware to the reset location.""" - ctx.move_labware( + protocol.move_labware( labware_to_move, reset_location, use_gripper=use_gripper ) @@ -131,7 +138,9 @@ def reset_labware() -> None: return for location in move_locations: - ctx.move_labware(labware_to_move, location, use_gripper=use_gripper) + protocol.move_labware( + labware_to_move, location, use_gripper=use_gripper + ) if reset_after_each_move: reset_labware() @@ -161,14 +170,13 @@ def test_gripper_moves() -> None: def deck_moves(labware: Labware, reset_location: str) -> None: """Function to perform the movement of labware.""" deck_move_sequence = [ - ["B2"], # Deck Moves + ["B3"], # Deck Moves ["C3"], # Staging Area Slot 3 Moves ["C4", "D4"], # Staging Area Slot 4 Moves [ thermocycler, temperature_module_adapter, h_s_adapter, - mag, ], # Module Moves ] @@ -177,14 +185,13 @@ def deck_moves(labware: Labware, reset_location: str) -> None: def staging_area_slot_3_moves(labware: Labware, reset_location: str) -> None: """Function to perform the movement of labware, starting w/ staging area slot 3.""" staging_area_slot_3_move_sequence = [ - ["B2", "C2"], # Deck Moves + ["B3", "C2"], # Deck Moves [], # Don't have Staging Area Slot 3 open ["C4", "D4"], # Staging Area Slot 4 Moves [ thermocycler, temperature_module_adapter, h_s_adapter, - mag, ], # Module Moves ] @@ -198,14 +205,13 @@ def staging_area_slot_3_moves(labware: Labware, reset_location: str) -> None: def staging_area_slot_4_moves(labware: Labware, reset_location: str) -> None: """Function to perform the movement of labware, starting with staging area slot 4.""" staging_area_slot_4_move_sequence = [ - ["C2", "B2"], # Deck Moves + ["C2", "B3"], # Deck Moves ["C3"], # Staging Area Slot 3 Moves ["C4"], # Staging Area Slot 4 Moves [ thermocycler, temperature_module_adapter, h_s_adapter, - mag, ], # Module Moves ] @@ -219,7 +225,7 @@ def staging_area_slot_4_moves(labware: Labware, reset_location: str) -> None: def module_moves(labware: Labware, module_locations: List) -> None: """Function to perform the movement of labware, starting on a module.""" module_move_sequence = [ - ["C2", "B2"], # Deck Moves + ["C2", "B3"], # Deck Moves ["C3"], # Staging Area Slot 3 Moves ["C4", "D4"], # Staging Area Slot 4 Moves ] @@ -229,7 +235,7 @@ def module_moves(labware: Labware, module_locations: List) -> None: labware_move_to_locations.remove(module_starting_location) all_sequences = module_move_sequence.copy() all_sequences.append(labware_move_to_locations) - ctx.move_labware( + protocol.move_labware( labware, module_starting_location, use_gripper=USING_GRIPPER ) run_moves( @@ -242,27 +248,27 @@ def module_moves(labware: Labware, module_locations: List) -> None: deck_moves(dest_pcr_plate, DECK_MOVE_RESET_LOCATION) - ctx.move_labware( + protocol.move_labware( dest_pcr_plate, STAGING_AREA_SLOT_3_RESET_LOCATION, use_gripper=USING_GRIPPER, ) staging_area_slot_3_moves(dest_pcr_plate, STAGING_AREA_SLOT_3_RESET_LOCATION) - ctx.move_labware( + protocol.move_labware( dest_pcr_plate, STAGING_AREA_SLOT_4_RESET_LOCATION, use_gripper=USING_GRIPPER, ) staging_area_slot_4_moves(dest_pcr_plate, STAGING_AREA_SLOT_4_RESET_LOCATION) - module_locations = [thermocycler, mag] + adapters + module_locations = [thermocycler] + adapters module_moves(dest_pcr_plate, module_locations) - ctx.move_labware(dest_pcr_plate, thermocycler, use_gripper=USING_GRIPPER) + protocol.move_labware(dest_pcr_plate, thermocycler, use_gripper=USING_GRIPPER) def test_manual_moves() -> None: """Test manual moves.""" - ctx.move_labware(source_reservoir, "D4", use_gripper=USING_GRIPPER) + protocol.move_labware(source_reservoir, "D4", use_gripper=USING_GRIPPER) def test_pipetting() -> None: """Test pipetting.""" @@ -279,64 +285,59 @@ def test_single_tip_pickup_usage() -> None: well_position = f"{row}{col}" pipette_96_channel.pick_up_tip(tip_rack_2) - pipette_96_channel.aspirate(5, source_reservoir[well_position]) - pipette_96_channel.touch_tip() + pipette_96_channel.aspirate(45, source_reservoir[well_position]) + pipette_96_channel.air_gap(5) pipette_96_channel.dispense( - 5, dest_pcr_plate[well_position].bottom(b) + 25, dest_pcr_plate[well_position].bottom(b) ) + pipette_96_channel.blow_out(location=liquid_waste["A1"]) pipette_96_channel.drop_tip() tip_count += 1 # leave this dropping in waste chute, do not use get_disposal_preference # want to test partial drop - ctx.move_labware(tip_rack_2, waste_chute, use_gripper=USING_GRIPPER) + protocol.move_labware(tip_rack_2, waste_chute, use_gripper=USING_GRIPPER) + + def test_column_tip_rack_usage() -> None: + """Column Tip Pick Up.""" + list_of_columns = list(range(1, 13)) + pipette_96_channel.configure_nozzle_layout( + style=COLUMN, start="A12", tip_racks=[tip_rack_3] + ) + protocol.comment("------------------------------") + protocol.comment(f"channels {pipette_96_channel.active_channels}") + protocol.move_labware(tip_rack_3, "C3", use_gripper=USING_GRIPPER) + for well in list_of_columns: + tiprack_well = "A" + str(well) + well_name = "A" + str(well) + pipette_96_channel.liquid_presence_detection = True + pipette_96_channel.pick_up_tip(tip_rack_3[tiprack_well]) + pipette_96_channel.aspirate(45, source_reservoir[well_name]) + pipette_96_channel.liquid_presence_detection = False + pipette_96_channel.air_gap(5) + pipette_96_channel.dispense(25, dest_pcr_plate[tiprack_well].bottom(b)) + pipette_96_channel.blow_out(location=liquid_waste["A1"]) + pipette_96_channel.drop_tip() + protocol.move_labware(tip_rack_3, waste_chute, use_gripper=USING_GRIPPER) def test_full_tip_rack_usage() -> None: """Full Tip Pick Up.""" - pipette_96_channel.configure_nozzle_layout(style=ALL, start="A1") + pipette_96_channel.configure_nozzle_layout( + style=ALL, tip_racks=[tip_rack_1] + ) + protocol.comment(f"channels {pipette_96_channel.active_channels}") pipette_96_channel.liquid_presence_detection = True - pipette_96_channel.pick_up_tip(tip_rack_1["A1"]) - - pipette_96_channel.aspirate(5, source_reservoir["A1"]) - pipette_96_channel.touch_tip() - + pipette_96_channel.pick_up_tip() + pipette_96_channel.aspirate(45, source_reservoir["A1"]) pipette_96_channel.liquid_presence_detection = False - pipette_96_channel.air_gap(height=30) - pipette_96_channel.blow_out(waste_chute) - - pipette_96_channel.aspirate(5, source_reservoir["A1"]) - pipette_96_channel.touch_tip() - - pipette_96_channel.air_gap(height=30) - pipette_96_channel.blow_out() - - pipette_96_channel.aspirate(10, source_reservoir["A1"]) - pipette_96_channel.touch_tip() - - pipette_96_channel.dispense(10, dest_pcr_plate["A1"].bottom(b)) - pipette_96_channel.mix(repetitions=5, volume=15) + pipette_96_channel.air_gap(5) + pipette_96_channel.dispense(25, dest_pcr_plate["A1"].bottom(b)) + pipette_96_channel.blow_out(location=liquid_waste["A1"]) pipette_96_channel.return_tip() - - ctx.move_labware(tip_rack_1, waste_chute, use_gripper=USING_GRIPPER) - ctx.move_labware(tip_rack_3, tip_rack_adapter, use_gripper=USING_GRIPPER) - - pipette_96_channel.pick_up_tip(tip_rack_3["A1"]) - pipette_96_channel.transfer( - volume=10, - source=source_reservoir["A1"], - dest=dest_pcr_plate["A1"], - new_tip="never", - touch_tip=True, - blow_out=True, - blowout_location="trash", - mix_before=(3, 5), - mix_after=(1, 5), - ) - pipette_96_channel.return_tip() - - ctx.move_labware(tip_rack_3, waste_chute, use_gripper=USING_GRIPPER) + pipette_96_channel.reset_tipracks() test_single_tip_pickup_usage() + test_column_tip_rack_usage() test_full_tip_rack_usage() def test_module_usage(unused_lids: List[Labware], used_lids: List[Labware]) -> None: @@ -351,14 +352,14 @@ def test_thermocycler( unused_lids, used_lids, ) = helpers.use_disposable_lid_with_tc( - ctx, unused_lids, used_lids, dest_pcr_plate, thermocycler + protocol, unused_lids, used_lids, dest_pcr_plate, thermocycler ) thermocycler.set_block_temperature(4) thermocycler.set_lid_temperature(105) # Close lid thermocycler.close_lid() helpers.perform_pcr( - ctx, + protocol, thermocycler, initial_denature_time_sec=45, denaturation_time_sec=30, @@ -374,9 +375,9 @@ def test_thermocycler( thermocycler.open_lid() if disposable_lid: if len(used_lids) <= 1: - ctx.move_labware(lid_on_plate, "B3", use_gripper=True) + protocol.move_labware(lid_on_plate, waste_chute, use_gripper=True) else: - ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + protocol.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) thermocycler.deactivate() def test_h_s() -> None: @@ -397,16 +398,21 @@ def test_temperature_module() -> None: temperature_module.set_temperature(10) temperature_module.deactivate() - def test_mag() -> None: - """Tests magnetic block.""" - pass - test_thermocycler(unused_lids, used_lids) test_h_s() test_temperature_module() - test_mag() test_pipetting() test_gripper_moves() test_module_usage(unused_lids, used_lids) test_manual_moves() + protocol.move_labware(source_reservoir, "C2", use_gripper=True) + helpers.clean_up_plates( + pipette_96_channel, [dest_pcr_plate, source_reservoir], liquid_waste["A1"], 50 + ) + pipette_96_channel.reset_tipracks() + helpers.find_liquid_height_of_all_wells( + protocol, pipette_96_channel, [liquid_waste["A1"]] + ) + if deactivate_modules_bool: + helpers.deactivate_modules(protocol) diff --git a/abr-testing/abr_testing/protocols/active_protocols/6_Omega_HDQ_DNA_Cells-Flex_96_channel.py b/abr-testing/abr_testing/protocols/active_protocols/6_Omega_HDQ_DNA_Cells-Flex_96_channel.py index 89f643729fb..cc2103d2555 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/6_Omega_HDQ_DNA_Cells-Flex_96_channel.py +++ b/abr-testing/abr_testing/protocols/active_protocols/6_Omega_HDQ_DNA_Cells-Flex_96_channel.py @@ -29,19 +29,28 @@ def add_parameters(parameters: ParameterContext) -> None: """Parameters.""" helpers.create_dot_bottom_parameter(parameters) + helpers.create_deactivate_modules_parameter(parameters) + parameters.add_int( + variable_name="number_of_runs", + display_name="Number of Runs", + default=2, + minimum=1, + maximum=10, + ) # Start protocol def run(ctx: ProtocolContext) -> None: """Protocol.""" dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] - + deactivate_modules = ctx.params.deactivate_modules # type: ignore[attr-defined] + number_of_runs = ctx.params.number_of_runs # type: ignore[attr-defined] dry_run = False tip_mixing = False wash_vol = 600.0 AL_vol = 230.0 - bind_vol = 320.0 + bind_vol = 300.0 sample_vol = 180.0 elution_vol = 100.0 @@ -211,74 +220,43 @@ def bead_mix(vol: float, plate: Well, reps: int = 5) -> None: pip.flow_rate.aspirate = 150 pip.flow_rate.dispense = 200 - # Start Protocol - temp.set_temperature(inc_temp) - # Transfer and mix lysis - pip.pick_up_tip(tips) - pip.aspirate(AL_total_vol, lysis_res) - pip.dispense(AL_total_vol, samples_m) - resuspend_pellet(400, samples_m, reps=4 if not dry_run else 1) - if not tip_mixing: - pip.return_tip() - - # Mix, then heat - ctx.comment("Lysis Mixing") - helpers.set_hs_speed(ctx, h_s, 1800, 10, False) - if not dry_run: - h_s.set_and_wait_for_temperature(55) - ctx.delay( - minutes=10 if not dry_run else 0.25, - msg="Please allow another 10 minutes of 55C incubation to complete lysis.", - ) - h_s.deactivate_shaker() - - # Transfer and mix bind&beads - pip.pick_up_tip(tips) - bead_mix(binding_buffer_vol, bind_res, reps=4 if not dry_run else 1) - pip.aspirate(binding_buffer_vol, bind_res) - pip.dispense(binding_buffer_vol, samples_m) - bead_mix(binding_buffer_vol + starting_vol, samples_m, reps=4 if not dry_run else 1) - if not tip_mixing: - pip.return_tip() - pip.home() - - # Shake for binding incubation - ctx.comment("Binding incubation") - helpers.set_hs_speed(ctx, h_s, 1800, 10, True) - - # Transfer plate to magnet - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) - - ctx.delay( - minutes=settling_time, - msg="Please wait " + str(settling_time) + " minute(s) for beads to pellet.", - ) + def protocol() -> None: + # Start Protocol + temp.set_temperature(inc_temp) + # Transfer and mix lysis + pip.pick_up_tip(tips) + pip.aspirate(AL_total_vol, lysis_res) + pip.dispense(AL_total_vol, samples_m) + resuspend_pellet(200, samples_m, reps=4 if not dry_run else 1) + if not tip_mixing: + pip.return_tip() - # Remove Supernatant and move off magnet - pip.pick_up_tip(tips) - pip.aspirate(1000, samples_m.bottom(dot_bottom)) - pip.dispense(1000, waste) - if starting_vol + binding_buffer_vol > 1000: - pip.aspirate(1000, samples_m.bottom(dot_bottom)) - pip.dispense(1000, waste) - pip.return_tip() - - # Transfer plate from magnet to H/S - helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) - - # Washes - for i in range(num_washes if not dry_run else 1): - if i == 0 or i == 1: - wash_res = wash1_res - else: - wash_res = wash2_res + # Mix, then heat + ctx.comment("Lysis Mixing") + helpers.set_hs_speed(ctx, h_s, 1800, 10, False) + if not dry_run: + h_s.set_and_wait_for_temperature(55) + ctx.delay( + minutes=10 if not dry_run else 0.25, + msg="Please allow another 10 minutes of 55C incubation to complete lysis.", + ) + h_s.deactivate_shaker() + # Transfer and mix bind&beads pip.pick_up_tip(tips) - pip.aspirate(wash_vol, wash_res) - pip.dispense(wash_vol, samples_m) + bead_mix(binding_buffer_vol, bind_res, reps=4 if not dry_run else 1) + pip.aspirate(binding_buffer_vol, bind_res) + pip.dispense(binding_buffer_vol, samples_m) + bead_mix( + binding_buffer_vol + starting_vol, samples_m, reps=4 if not dry_run else 1 + ) if not tip_mixing: pip.return_tip() - helpers.set_hs_speed(ctx, h_s, 1800, 5, True) + pip.home() + + # Shake for binding incubation + ctx.comment("Binding incubation") + helpers.set_hs_speed(ctx, h_s, 1800, 10, True) # Transfer plate to magnet helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) @@ -290,62 +268,161 @@ def bead_mix(vol: float, plate: Well, reps: int = 5) -> None: # Remove Supernatant and move off magnet pip.pick_up_tip(tips) - pip.aspirate(1000, samples_m.bottom(dot_bottom)) - pip.dispense(1000, bind_res.top()) - if wash_vol > 1000: - pip.aspirate(1000, samples_m.bottom(dot_bottom)) - pip.dispense(1000, bind_res.top()) + pip.aspirate(550, samples_m.bottom(dot_bottom)) + pip.dispense(550, waste) + if starting_vol + binding_buffer_vol > 1000: + pip.aspirate(550, samples_m.bottom(dot_bottom)) + pip.dispense(550, waste) pip.return_tip() # Transfer plate from magnet to H/S helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) - # Dry beads - if dry_run: - drybeads = 0.5 - else: - drybeads = 10 - # Number of minutes you want to dry for - for beaddry in np.arange(drybeads, 0, -0.5): + # Washes + for i in range(num_washes if not dry_run else 1): + if i == 0 or i == 1: + wash_res = wash1_res + else: + wash_res = wash2_res + + pip.pick_up_tip(tips) + pip.aspirate(wash_vol, wash_res) + pip.dispense(wash_vol, samples_m) + if not tip_mixing: + pip.return_tip() + helpers.set_hs_speed(ctx, h_s, 1800, 5, True) + + # Transfer plate to magnet + helpers.move_labware_from_hs_to_destination( + ctx, sample_plate, h_s, magblock + ) + + ctx.delay( + minutes=settling_time, + msg="Please wait " + + str(settling_time) + + " minute(s) for beads to pellet.", + ) + + # Remove Supernatant and move off magnet + pip.pick_up_tip(tips) + pip.aspirate(473, samples_m.bottom(dot_bottom)) + pip.dispense(473, bind_res.top()) + if wash_vol > 1000: + pip.aspirate(473, samples_m.bottom(dot_bottom)) + pip.dispense(473, bind_res.top()) + pip.return_tip() + + # Transfer plate from magnet to H/S + helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + + # Dry beads + if dry_run: + drybeads = 0.5 + else: + drybeads = 10 + # Number of minutes you want to dry for + for beaddry in np.arange(drybeads, 0, -0.5): + ctx.delay( + minutes=0.5, + msg="There are " + str(beaddry) + " minutes left in the drying step.", + ) + + # Elution + pip.pick_up_tip(tips1) + pip.aspirate(elution_vol, elution_res) + pip.dispense(elution_vol, samples_m) + resuspend_pellet(elution_vol, samples_m, reps=3 if not dry_run else 1) + if not tip_mixing: + pip.return_tip() + pip.home() + + helpers.set_hs_speed(ctx, h_s, 2000, 5, True) + + # Transfer plate to magnet + helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + ctx.delay( - minutes=0.5, - msg="There are " + str(beaddry) + " minutes left in the drying step.", + minutes=settling_time, + msg="Please wait " + str(settling_time) + " minute(s) for beads to pellet.", ) - # Elution - pip.pick_up_tip(tips1) - pip.aspirate(elution_vol, elution_res) - pip.dispense(elution_vol, samples_m) - resuspend_pellet(elution_vol, samples_m, reps=3 if not dry_run else 1) - if not tip_mixing: + pip.pick_up_tip(tips1) + pip.aspirate(elution_vol, samples_m) + pip.dispense(elution_vol, elutionplate.wells()[0]) pip.return_tip() - pip.home() - - helpers.set_hs_speed(ctx, h_s, 2000, 5, True) - # Transfer plate to magnet - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + pip.home() + pip.reset_tipracks() + + # Empty Plates + pip.pick_up_tip() + pip.aspirate(500, samples_m) + pip.dispense(500, liquid_waste["A1"].top()) + pip.aspirate(500, wash1_res) + pip.dispense(500, liquid_waste["A1"].top()) + pip.aspirate(500, wash2_res) + pip.dispense(500, liquid_waste["A1"].top()) + pip.return_tip() + helpers.find_liquid_height_of_all_wells(ctx, pip, [liquid_waste["A1"]]) + helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) - ctx.delay( - minutes=settling_time, - msg="Please wait " + str(settling_time) + " minute(s) for beads to pellet.", - ) + def setup() -> None: + pip.pick_up_tip() + pip.transfer( + volume=250, + source=liquid_waste["A1"].bottom(z=2), + dest=lysis_reservoir["A1"], + blow_out=True, + blowout_location="source well", + new_tip="never", + trash=False, + ) + pip.transfer( + 1700, + liquid_waste["A1"].bottom(z=2), + wash1_reservoir["A1"], + blow_out=True, + blowout_location="source well", + new_tip="never", + trash=False, + ) + pip.transfer( + 1100, + bind_reservoir["A1"].bottom(z=2), + wash2_reservoir["A1"], + blow_out=True, + blowout_location="source well", + new_tip="never", + trash=False, + ) + pip.transfer( + 100, + liquid_waste["A1"].bottom(z=2), + sample_plate["A1"], + blow_out=True, + blowout_location="source well", + new_tip="never", + trash=False, + ) + pip.return_tip() - pip.pick_up_tip(tips1) - pip.aspirate(elution_vol, samples_m) - pip.dispense(elution_vol, elutionplate.wells()[0]) - pip.return_tip() - - pip.home() - pip.reset_tipracks() - - # Empty Plates - pip.pick_up_tip() - pip.aspirate(1000, samples_m) - pip.dispense(1000, liquid_waste["A1"].top()) - pip.aspirate(1000, wash1_res) - pip.dispense(1000, liquid_waste["A1"].top()) - pip.aspirate(1000, wash2_res) - pip.dispense(1000, liquid_waste["A1"].top()) - pip.return_tip() - helpers.find_liquid_height_of_all_wells(ctx, pip, [liquid_waste["A1"]]) + def clean() -> None: + plates_to_clean = [ + sample_plate, + elutionplate, + wash2_reservoir, + wash1_reservoir, + liquid_waste, + ] + helpers.clean_up_plates(pip, plates_to_clean, liquid_waste["A1"], 1000) + + for i in range(number_of_runs): + protocol() + pip.reset_tipracks() + if i < number_of_runs - 1: + setup() + pip.reset_tipracks() + clean() + if deactivate_modules: + helpers.deactivate_modules(ctx) diff --git a/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py b/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py index aa33079f553..4350888b0d6 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py +++ b/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py @@ -22,7 +22,7 @@ } requirements = { - "robotType": "OT-3", + "robotType": "Flex", "apiLevel": "2.21", } """ @@ -57,18 +57,22 @@ def add_parameters(parameters: ParameterContext) -> None: helpers.create_single_pipette_mount_parameter(parameters) helpers.create_hs_speed_parameter(parameters) helpers.create_dot_bottom_parameter(parameters) + helpers.create_deactivate_modules_parameter(parameters) -def run(ctx: ProtocolContext) -> None: +def run(protocol: ProtocolContext) -> None: """Protocol.""" - heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] - mount = ctx.params.pipette_mount # type: ignore[attr-defined] - dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] + heater_shaker_speed = protocol.params.heater_shaker_speed # type: ignore[attr-defined] + mount = protocol.params.pipette_mount # type: ignore[attr-defined] + dot_bottom = protocol.params.dot_bottom # type: ignore[attr-defined] + deactivate_modules_bool = protocol.params.deactivate_modules # type: ignore[attr-defined] + helpers.comment_protocol_version(protocol, "01") + dry_run = False TIP_TRASH = False res_type = "nest_12_reservoir_22ml" - num_samples = 8 + num_samples = 96 wash1_vol = 600.0 wash2_vol = 600.0 wash3_vol = 600.0 @@ -95,37 +99,48 @@ def run(ctx: ProtocolContext) -> None: starting_vol = AL_vol + sample_vol binding_buffer_vol = bind_vol + bead_vol - ctx.load_trash_bin("A3") - h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] + protocol.load_trash_bin("A3") + h_s: HeaterShakerContext = protocol.load_module( + helpers.hs_str, "D1" + ) # type: ignore[assignment] sample_plate, h_s_adapter = helpers.load_hs_adapter_and_labware( deepwell_type, h_s, "Sample Plate" ) h_s.close_labware_latch() - temp: TemperatureModuleContext = ctx.load_module( + temp: TemperatureModuleContext = protocol.load_module( helpers.temp_str, "D3" ) # type: ignore[assignment] elutionplate, temp_adapter = helpers.load_temp_adapter_and_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", temp, "Elution Plate" ) - magnetic_block: MagneticBlockContext = ctx.load_module( + magnetic_block: MagneticBlockContext = protocol.load_module( helpers.mag_str, "C1" ) # type: ignore[assignment] - waste_reservoir = ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + waste_reservoir = protocol.load_labware( + "nest_1_reservoir_195ml", "B3", "Liquid Waste" + ) waste = waste_reservoir.wells()[0].top() - res1 = ctx.load_labware(res_type, "D2", "Reagent Reservoir 1") + res1 = protocol.load_labware(res_type, "D2", "Reagent Reservoir 1") num_cols = math.ceil(num_samples / 8) - # Load tips and combine all similar boxes - tips1000 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "A1", "Tips 1") - tips1001 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "A2", "Tips 2") - tips1002 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "B1", "Tips 3") - tips = [*tips1000.wells()[num_samples:96], *tips1001.wells(), *tips1002.wells()] + tips1000 = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "A1", "Tips 1") + tips1001 = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "A2", "Tips 2") + tips1002 = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "B1", "Tips 3") + tips1003 = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "B2", "Tips 4") + tips1004 = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "C2", "Tips 5") + + tips = [ + *tips1000.wells()[num_samples:96], + *tips1001.wells(), + *tips1002.wells(), + *tips1003.wells(), + ] tips_sn = tips1000.wells()[:num_samples] # load instruments - m1000 = ctx.load_instrument( - "flex_8channel_1000", mount, tip_racks=[tips1000, tips1001, tips1002] + m1000 = protocol.load_instrument( + "flex_8channel_1000", mount, tip_racks=[tips1000, tips1001, tips1002, tips1003] ) """ @@ -158,7 +173,7 @@ def run(ctx: ProtocolContext) -> None: m1000.flow_rate.aspirate = 300 m1000.flow_rate.dispense = 300 m1000.flow_rate.blow_out = 300 - helpers.find_liquid_height_of_loaded_liquids(ctx, liquid_vols_and_wells, m1000) + helpers.find_liquid_height_of_loaded_liquids(protocol, liquid_vols_and_wells, m1000) def tiptrack(tipbox: List[Well]) -> None: """Track Tips.""" @@ -167,14 +182,15 @@ def tiptrack(tipbox: List[Well]) -> None: if tipbox == tips: m1000.pick_up_tip(tipbox[int(tip1k)]) tip1k = tip1k + 8 + if tip1k >= len(tipbox): + tip1k = 0 drop_count = drop_count + 8 if drop_count >= 150: drop_count = 0 - ctx.pause("Empty Waste Bin.") def remove_supernatant(vol: float) -> None: """Remove supernatants.""" - ctx.comment("-----Removing Supernatant-----") + protocol.comment("-----Removing Supernatant-----") m1000.flow_rate.aspirate = 150 num_trans = math.ceil(vol / 980) vol_per_trans = vol / num_trans @@ -192,7 +208,7 @@ def remove_supernatant(vol: float) -> None: m1000.air_gap(20) m1000.drop_tip(tips_sn[8 * i]) if TIP_TRASH else m1000.return_tip() m1000.flow_rate.aspirate = 300 - helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + helpers.move_labware_to_hs(protocol, sample_plate, h_s, h_s_adapter) def bead_mixing( well: Well, pip: InstrumentContext, mvol: float, reps: int = 8 @@ -284,7 +300,7 @@ def mixing(well: Well, pip: InstrumentContext, mvol: float, reps: int = 8) -> No def A_lysis(vol: float, source: Well) -> None: """A Lysis.""" - ctx.comment("-----Mixing then transferring AL buffer-----") + protocol.comment("-----Mixing then transferring AL buffer-----") num_transfers = math.ceil(vol / 980) tiptrack(tips) for i in range(num_cols): @@ -303,7 +319,6 @@ def A_lysis(vol: float, source: Well) -> None: m1000.require_liquid_presence(src) m1000.aspirate(tvol, src.bottom(1)) m1000.dispense(tvol, src.bottom(4)) - m1000.require_liquid_presence(src) m1000.aspirate(tvol, src.bottom(height)) m1000.air_gap(10) m1000.dispense(m1000.current_volume, samples_m[i].top()) @@ -318,12 +333,12 @@ def A_lysis(vol: float, source: Well) -> None: m1000.air_gap(20) m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - ctx.comment("-----Mixing then Heating AL and Sample-----") + protocol.comment("-----Mixing then Heating AL and Sample-----") - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, A_lysis_time_1, False) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, A_lysis_time_1, False) if not dry_run: h_s.set_and_wait_for_temperature(55) - ctx.delay( + protocol.delay( minutes=A_lysis_time_2, msg="Incubating at 55C " + str(heater_shaker_speed) @@ -347,17 +362,17 @@ def bind(vol: float) -> None: supernatant to the final clean elutions PCR plate. """ - ctx.comment("-----Beginning Bind Steps-----") + protocol.comment("-----Beginning Bind Steps-----") tiptrack(tips) for i, well in enumerate(samples_m): num_trans = math.ceil(vol / 980) vol_per_trans = vol / num_trans - source = binding_buffer[i // 3] + source = binding_buffer[i // 7] if i == 0: reps = 6 if not dry_run else 1 else: reps = 1 - ctx.comment("-----Mixing Beads in Reservoir-----") + protocol.comment("-----Mixing Beads in Reservoir-----") bead_mixing(source, m1000, vol_per_trans, reps=reps if not dry_run else 1) # Transfer beads and binding from source to H-S plate for t in range(num_trans): @@ -370,7 +385,7 @@ def bind(vol: float) -> None: if t < num_trans - 1: m1000.air_gap(20) - ctx.comment("-----Mixing Beads in Plate-----") + protocol.comment("-----Mixing Beads in Plate-----") for i in range(num_cols): if i != 0: tiptrack(tips) @@ -379,19 +394,19 @@ def bind(vol: float) -> None: ) m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - ctx.comment("-----Incubating Beads and Bind on H-S-----") + protocol.comment("-----Incubating Beads and Bind on H-S-----") speed_val = heater_shaker_speed * 0.9 - helpers.set_hs_speed(ctx, h_s, speed_val, bind_time, True) + helpers.set_hs_speed(protocol, h_s, speed_val, bind_time, True) # Transfer from H-S plate to Magdeck plate helpers.move_labware_from_hs_to_destination( - ctx, sample_plate, h_s, magnetic_block + protocol, sample_plate, h_s, magnetic_block ) for bindi in np.arange( settling_time + 1, 0, -0.5 ): # Settling time delay with countdown timer - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(bindi) + " minutes left in the incubation.", ) @@ -410,29 +425,29 @@ def wash(vol: float, source: List[Well]) -> None: if source == wash3: whichwash = 3 - ctx.comment("-----Beginning Wash #" + str(whichwash) + "-----") + protocol.comment("-----Beginning Wash #" + str(whichwash) + "-----") num_trans = math.ceil(vol / 980) vol_per_trans = vol / num_trans tiptrack(tips) for i, m in enumerate(samples_m): - src = source[i // 2] + src = source[i // 4] for n in range(num_trans): if m1000.current_volume > 0: m1000.dispense(m1000.current_volume, src.top()) m1000.transfer(vol_per_trans, src, m.top(), air_gap=20, new_tip="never") m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, elute_wash_time, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, elute_wash_time, True) helpers.move_labware_from_hs_to_destination( - ctx, sample_plate, h_s, magnetic_block + protocol, sample_plate, h_s, magnetic_block ) for washi in np.arange( settling_time, 0, -0.5 ): # settling time timer for washes - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(washi) @@ -445,7 +460,7 @@ def wash(vol: float, source: List[Well]) -> None: def elute(vol: float) -> None: """Elution Function.""" - ctx.comment("-----Beginning Elution Steps-----") + protocol.comment("-----Beginning Elution Steps-----") tiptrack(tips) for i, (m, e) in enumerate(zip(samples_m, elution_samples_m)): m1000.flow_rate.aspirate = 25 @@ -457,15 +472,15 @@ def elute(vol: float) -> None: h_s.set_and_wait_for_shake_speed(heater_shaker_speed * 1.1) speed_val = heater_shaker_speed * 1.1 - helpers.set_hs_speed(ctx, h_s, speed_val, elute_wash_time, True) + helpers.set_hs_speed(protocol, h_s, speed_val, elute_wash_time, True) # Transfer back to magnet helpers.move_labware_from_hs_to_destination( - ctx, sample_plate, h_s, magnetic_block + protocol, sample_plate, h_s, magnetic_block ) for elutei in np.arange(settling_time, 0, -0.5): - ctx.delay( + protocol.delay( minutes=0.5, msg="Incubating on MagDeck for " + str(elutei) + " more minutes.", ) @@ -495,7 +510,7 @@ def elute(vol: float) -> None: else: drybeads = 0.5 for beaddry in np.arange(drybeads, 0, -0.5): - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(beaddry) + " minutes left in the drying step.", ) @@ -504,7 +519,9 @@ def elute(vol: float) -> None: # Probe wells end_wells_with_liquid = [ waste_reservoir.wells()[0], - res1.wells()[0], - elutionplate.wells()[0], ] - helpers.find_liquid_height_of_all_wells(ctx, m1000, end_wells_with_liquid) + m1000.tip_racks = [tips1004] + helpers.clean_up_plates(m1000, [res1, elutionplate], waste_reservoir["A1"], 1000) + helpers.find_liquid_height_of_all_wells(protocol, m1000, end_wells_with_liquid) + if deactivate_modules_bool: + helpers.deactivate_modules(protocol) diff --git a/abr-testing/abr_testing/protocols/active_protocols/8_Illumina and Plate Reader.py b/abr-testing/abr_testing/protocols/active_protocols/8_Illumina and Plate Reader.py index 4894cae41d4..3d8c664956c 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/8_Illumina and Plate Reader.py +++ b/abr-testing/abr_testing/protocols/active_protocols/8_Illumina and Plate Reader.py @@ -1,5 +1,11 @@ """Illumina DNA Prep and Plate Reader Test.""" -from opentrons.protocol_api import ParameterContext, ProtocolContext, Labware +from opentrons.protocol_api import ( + ParameterContext, + ProtocolContext, + Labware, + Well, + InstrumentContext, +) from abr_testing.protocols import helpers from opentrons.protocol_api.module_contexts import ( AbsorbanceReaderContext, @@ -10,9 +16,10 @@ ) from datetime import datetime from opentrons.hardware_control.modules.types import ThermocyclerStep -from typing import List +from typing import List, Dict from opentrons import types + metadata = { "protocolName": "Illumina DNA Prep and Plate Reader Test", "author": "Platform Expansion", @@ -31,7 +38,7 @@ HYBRID_PAUSE = True # True = sets a pause on the Hybridization # PROTOCOL SETTINGS -COLUMNS = 3 # 1-3 +COLUMNS = 4 # 1-4 HYBRIDDECK = True HYBRIDTIME = 1.6 # Hours @@ -55,6 +62,8 @@ def add_parameters(parameters: ParameterContext) -> None: """Add Parameters.""" helpers.create_hs_speed_parameter(parameters) helpers.create_dot_bottom_parameter(parameters) + helpers.create_deactivate_modules_parameter(parameters) + helpers.create_plate_reader_compatible_labware_parameter(parameters) parameters.add_bool( variable_name="plate_orientation", display_name="Hellma Plate Orientation", @@ -103,6 +112,10 @@ def run(protocol: ProtocolContext) -> None: heater_shaker_speed = protocol.params.heater_shaker_speed # type: ignore[attr-defined] dot_bottom = protocol.params.dot_bottom # type: ignore[attr-defined] plate_orientation = protocol.params.plate_orientation # type: ignore[attr-defined] + deactivate_modules_bool = protocol.params.deactivate_modules # type: ignore[attr-defined] + plate_type = protocol.params.labware_plate_reader_compatible # type: ignore [attr-defined] + helpers.comment_protocol_version(protocol, "01") + plate_name_str = "hellma_plate_" + str(plate_orientation) global p200_tips global p50_tips @@ -115,7 +128,9 @@ def run(protocol: ProtocolContext) -> None: tiprack_50_2 = protocol.load_labware("opentrons_flex_96_tiprack_50ul", "A3") # MODULES + LABWARE # Reservoir - reservoir = protocol.load_labware("nest_96_wellplate_2ml_deep", "D2") + reservoir = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "D2", "Liquid Waste" + ) # Heatershaker heatershaker: HeaterShakerContext = protocol.load_module( helpers.hs_str, "D1" @@ -123,6 +138,7 @@ def run(protocol: ProtocolContext) -> None: sample_plate_2 = heatershaker.load_labware( "thermoscientificnunc_96_wellplate_1300ul" ) + heatershaker.close_labware_latch() # Magnetic Block mag_block: MagneticBlockContext = protocol.load_module( helpers.mag_str, "C1" @@ -133,6 +149,7 @@ def run(protocol: ProtocolContext) -> None: sample_plate_1 = thermocycler.load_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt" ) + thermocycler.open_lid() # Temperature Module temp_block: TemperatureModuleContext = protocol.load_module( helpers.temp_str, "B3" @@ -144,7 +161,7 @@ def run(protocol: ProtocolContext) -> None: plate_reader: AbsorbanceReaderContext = protocol.load_module( helpers.abs_mod_str, PLATE_READER_SLOT ) # type: ignore[assignment] - hellma_plate = protocol.load_labware("hellma_reference_plate", HELLMA_PLATE_SLOT) + hellma_plate = protocol.load_labware(plate_type, HELLMA_PLATE_SLOT) # PIPETTES p1000 = protocol.load_instrument( "flex_8channel_1000", @@ -154,6 +171,28 @@ def run(protocol: ProtocolContext) -> None: p50 = protocol.load_instrument( "flex_8channel_50", "right", tip_racks=[tiprack_50_1, tiprack_50_2] ) + + # Load liquids and probe + liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { + "Reagents": [ + {"well": reagent_plate.columns()[3], "volume": 75.0}, + {"well": reagent_plate.columns()[4], "volume": 15.0}, + {"well": reagent_plate.columns()[5], "volume": 20.0}, + {"well": reagent_plate.columns()[6], "volume": 65.0}, + ], + "AMPure": [{"well": reservoir.columns()[0], "volume": 120.0}], + "SMB": [{"well": reservoir.columns()[1], "volume": 750.0}], + "EtOH": [{"well": reservoir.columns()[3], "volume": 900.0}], + "RSB": [{"well": reservoir.columns()[4], "volume": 96.0}], + "Wash": [ + {"well": sample_plate_2.columns()[9], "volume": 1000.0}, + {"well": sample_plate_2.columns()[10], "volume": 1000.0}, + {"well": sample_plate_2.columns()[11], "volume": 1000.0}, + ], + "Samples": [{"well": sample_plate_1.wells(), "volume": 150.0}], + } + helpers.find_liquid_height_of_loaded_liquids(protocol, liquid_vols_and_wells, p50) + # reagent AMPure = reservoir["A1"] SMB = reservoir["A2"] @@ -165,11 +204,42 @@ def run(protocol: ProtocolContext) -> None: Liquid_trash_well_2 = reservoir["A10"] Liquid_trash_well_3 = reservoir["A11"] Liquid_trash_well_4 = reservoir["A12"] + liquid_trash_list = { + Liquid_trash_well_1: 0.0, + Liquid_trash_well_2: 0.0, + Liquid_trash_well_3: 0.0, + Liquid_trash_well_4: 0.0, + } + + def trash_liquid( + protocol: ProtocolContext, + pipette: InstrumentContext, + vol_to_trash: float, + liquid_trash_list: Dict[Well, float], + ) -> None: + """Determine which wells to use as liquid waste.""" + remaining_volume = vol_to_trash + max_capacity = 1500.0 + # Determine liquid waste location depending on current total volume + # Distribute the liquid volume sequentially + for well, current_volume in liquid_trash_list.items(): + if remaining_volume <= 0.0: + break + available_capacity = max_capacity - current_volume + if available_capacity < remaining_volume: + continue + pipette.dispense(remaining_volume, well.top()) + protocol.delay(minutes=0.1) + pipette.blow_out(well.top()) + liquid_trash_list[well] += remaining_volume + if pipette.current_volume <= 0.0: + break # Will Be distributed during the protocol - EEW_1 = sample_plate_2.wells_by_name()["A10"] - EEW_2 = sample_plate_2.wells_by_name()["A11"] - EEW_3 = sample_plate_2.wells_by_name()["A12"] + EEW_1 = sample_plate_2.wells_by_name()["A9"] + EEW_2 = sample_plate_2.wells_by_name()["A10"] + EEW_3 = sample_plate_2.wells_by_name()["A11"] + EEW_4 = sample_plate_2.wells_by_name()["A12"] NHB2 = reagent_plate.wells_by_name()["A1"] Panel = reagent_plate.wells_by_name()["A2"] @@ -206,6 +276,14 @@ def run(protocol: ProtocolContext) -> None: column_5_list = ["A7", "A8", "A9"] # Plate 2 column_6_list = ["A7", "A8", "A9"] # Plate 1 WASHES = [EEW_1, EEW_2, EEW_3] + if COLUMNS == 4: + column_1_list = ["A1", "A2", "A3", "A4"] # Plate 1 + column_2_list = ["A1", "A2", "A3", "A4"] # Plate 2 + column_3_list = ["A5", "A6", "A7", "A8"] # Plate 2 + column_4_list = ["A5", "A6", "A7", "A8"] # Plate 1 + column_5_list = ["A9", "A10", "A11", "A12"] # Plate 2 + column_6_list = ["A9", "A10", "A11", "A12"] # Plate 1 + WASHES = [EEW_1, EEW_2, EEW_3, EEW_4] def tipcheck() -> None: """Check tips.""" @@ -231,9 +309,7 @@ def tipcheck() -> None: thermocycler.set_block_temperature(58) thermocycler.set_lid_temperature(58) heatershaker.set_and_wait_for_temperature(58) - protocol.pause("Ready") heatershaker.close_labware_latch() - Liquid_trash = Liquid_trash_well_1 # Sample Plate contains 30ul of DNA @@ -409,20 +485,14 @@ def tipcheck() -> None: p1000.pick_up_tip() p1000.move_to(sample_plate_2[X].bottom(4)) p1000.aspirate(200, rate=0.25) - p1000.dispense(200, Liquid_trash.top(z=-7)) + trash_liquid(protocol, p1000, 200, liquid_trash_list) p1000.move_to(sample_plate_2[X].bottom(0.5)) p1000.aspirate(200, rate=0.25) - p1000.dispense(200, Liquid_trash.top(z=-7)) - p1000.move_to(Liquid_trash.top(z=-7)) - protocol.delay(minutes=0.1) - p1000.blow_out(Liquid_trash.top(z=-7)) - p1000.aspirate(20) + trash_liquid(protocol, p1000, 200, liquid_trash_list) p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() p200_tips += 1 tipcheck() - Liquid_trash = Liquid_trash_well_2 - # ============================================================================================ # GRIPPER MOVE sample_plate_2 FROM MAGPLATE TO heatershaker helpers.move_labware_to_hs( @@ -469,9 +539,6 @@ def tipcheck() -> None: if DRYRUN is False: protocol.delay(seconds=1 * 60) - if washcount > 2: - Liquid_trash = Liquid_trash_well_3 - protocol.comment("--> Removing Supernatant") RemoveSup = 200 for loop, X in enumerate(column_2_list): @@ -482,10 +549,7 @@ def tipcheck() -> None: p1000.move_to(sample_plate_2[X].bottom(z=0.5)) p1000.aspirate(100, rate=0.25) p1000.move_to(sample_plate_2[X].top(z=0.5)) - p1000.dispense(200, Liquid_trash.top(z=-7)) - protocol.delay(minutes=0.1) - p1000.blow_out(Liquid_trash.top(z=-7)) - p1000.aspirate(20) + trash_liquid(protocol, p1000, 200, liquid_trash_list) p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() p200_tips += 1 tipcheck() @@ -554,10 +618,7 @@ def tipcheck() -> None: p1000.move_to(sample_plate_2[X].bottom(z=0.5)) p1000.aspirate(100, rate=0.25) p1000.move_to(sample_plate_2[X].top(z=0.5)) - p1000.dispense(200, Liquid_trash.top(z=-7)) - protocol.delay(minutes=0.1) - p1000.blow_out(Liquid_trash.top(z=-7)) - p1000.aspirate(20) + trash_liquid(protocol, p1000, 200, liquid_trash_list) p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() p200_tips += 1 tipcheck() @@ -568,12 +629,7 @@ def tipcheck() -> None: p50.move_to(sample_plate_2[X].bottom(z=dot_bottom)) # original = z=0 p50.aspirate(50, rate=0.25) p50.default_speed = 200 - p50.dispense(50, Liquid_trash.top(z=-7)) - protocol.delay(minutes=0.1) - p50.blow_out() - p50.default_speed = 400 - p50.move_to(Liquid_trash.top(z=-7)) - p50.move_to(Liquid_trash.top(z=0)) + trash_liquid(protocol, p50, 50, liquid_trash_list) p50.return_tip() if TIP_TRASH is False else p50.drop_tip() p50_tips += 1 tipcheck() @@ -722,8 +778,6 @@ def tipcheck() -> None: p50_tips += 1 tipcheck() - Liquid_trash = Liquid_trash_well_4 - protocol.comment("--> ADDING AMPure (0.8x)") AMPureVol = 40.5 AMPureMixRep = 5 * 60 if DRYRUN is False else 0.1 * 60 @@ -777,12 +831,7 @@ def tipcheck() -> None: p1000.default_speed = 5 p1000.move_to(sample_plate_2[X].top(z=2)) p1000.default_speed = 200 - p1000.dispense(200, Liquid_trash.top(z=-7)) - protocol.delay(minutes=0.1) - p1000.blow_out() - p1000.default_speed = 400 - p1000.move_to(Liquid_trash.top(z=-7)) - p1000.move_to(Liquid_trash.top(z=0)) + trash_liquid(protocol, p1000, 200, liquid_trash_list) p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() p200_tips += 1 tipcheck() @@ -821,12 +870,7 @@ def tipcheck() -> None: p1000.default_speed = 5 p1000.move_to(sample_plate_2[X].top(z=2)) p1000.default_speed = 200 - p1000.dispense(200, Liquid_trash.top(z=-7)) - protocol.delay(minutes=0.1) - p1000.blow_out() - p1000.default_speed = 400 - p1000.move_to(Liquid_trash.top(z=-7)) - p1000.move_to(Liquid_trash.top(z=0)) + trash_liquid(protocol, p1000, 200, liquid_trash_list) p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() p200_tips += 1 tipcheck() @@ -842,12 +886,7 @@ def tipcheck() -> None: ) # original = (z=0) p1000.aspirate(50, rate=0.25) p1000.default_speed = 200 - p1000.dispense(50, Liquid_trash.top(z=-7)) - protocol.delay(minutes=0.1) - p1000.blow_out() - p1000.default_speed = 400 - p1000.move_to(Liquid_trash.top(z=-7)) - p1000.move_to(Liquid_trash.top(z=0)) + trash_liquid(protocol, p1000, 50, liquid_trash_list) p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() p200_tips += 1 tipcheck() @@ -945,4 +984,13 @@ def tipcheck() -> None: p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() p200_tips += 1 tipcheck() + liquids_to_probe_at_end = [ + Liquid_trash_well_1, + Liquid_trash_well_2, + Liquid_trash_well_3, + Liquid_trash_well_4, + ] + helpers.find_liquid_height_of_all_wells(protocol, p50, liquids_to_probe_at_end) plate_reader_actions(protocol, plate_reader, hellma_plate, plate_name_str) + if deactivate_modules_bool: + helpers.deactivate_modules(protocol) diff --git a/abr-testing/abr_testing/protocols/active_protocols/9_Magmax_RNA_Cells_Flex.py b/abr-testing/abr_testing/protocols/active_protocols/9_Magmax_RNA_Cells_Flex.py index 09201e58314..c44e8111490 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/9_Magmax_RNA_Cells_Flex.py +++ b/abr-testing/abr_testing/protocols/active_protocols/9_Magmax_RNA_Cells_Flex.py @@ -24,7 +24,7 @@ } requirements = { - "robotType": "OT-3", + "robotType": "Flex", "apiLevel": "2.21", } """ @@ -44,15 +44,17 @@ Reservoir 1: Well 1 - 8120 ul -Well 2 - 6400 ul -Well 3-7 - 8550 ul +Well 2 - 8120 ul +Well 3 - 12800 ul +Well 4-12 - 9500 ul + """ -whichwash = 1 -sample_max = 48 -tip = 0 +whichwash = 0 +tip_pick_up = 0 drop_count = 0 waste_vol = 0 +wash_volume_tracker = 0.0 # Start protocol @@ -61,22 +63,25 @@ def add_parameters(parameters: ParameterContext) -> None: helpers.create_dot_bottom_parameter(parameters) helpers.create_single_pipette_mount_parameter(parameters) helpers.create_hs_speed_parameter(parameters) + helpers.create_deactivate_modules_parameter(parameters) -def run(ctx: ProtocolContext) -> None: +def run(protocol: ProtocolContext) -> None: """Protocol.""" dry_run = False inc_lysis = True res_type = "nest_12_reservoir_15ml" TIP_TRASH = False - num_samples = 48 + num_samples = 96 wash_vol = 150.0 lysis_vol = 140.0 stop_vol = 100.0 - elution_vol = dnase_vol = 50.0 - heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] - dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] - pipette_mount = ctx.params.pipette_mount # type: ignore[attr-defined] + elution_vol = dnase_vol = 55.0 + heater_shaker_speed = protocol.params.heater_shaker_speed # type: ignore[attr-defined] + dot_bottom = protocol.params.dot_bottom # type: ignore[attr-defined] + pipette_mount = protocol.params.pipette_mount # type: ignore[attr-defined] + deactivate_modules_bool = protocol.params.deactivate_modules # type: ignore[attr-defined] + helpers.comment_protocol_version(protocol, "01") # Protocol Parameters deepwell_type = "nest_96_wellplate_2ml_deep" @@ -93,63 +98,67 @@ def run(ctx: ProtocolContext) -> None: drybeads = elute_time = 0.25 bind_time = wash_time = dnase_time = stop_time = 0.25 bead_vol = 20.0 - ctx.load_trash_bin("A3") - h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] + protocol.load_trash_bin("A3") + h_s: HeaterShakerContext = protocol.load_module( + helpers.hs_str, "D1" + ) # type: ignore[assignment] sample_plate, h_s_adapter = helpers.load_hs_adapter_and_labware( deepwell_type, h_s, "Sample Plate" ) h_s.close_labware_latch() - temp: TemperatureModuleContext = ctx.load_module( + temp: TemperatureModuleContext = protocol.load_module( helpers.temp_str, "D3" ) # type: ignore[assignment] elutionplate, temp_adapter = helpers.load_temp_adapter_and_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", temp, "Elution Plate" ) temp.set_temperature(4) - magblock: MagneticBlockContext = ctx.load_module( + magblock: MagneticBlockContext = protocol.load_module( helpers.mag_str, "C1" ) # type: ignore[assignment] - waste_reservoir = ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + waste_reservoir = protocol.load_labware( + "nest_1_reservoir_195ml", "B3", "Liquid Waste" + ) waste = waste_reservoir.wells()[0].top() - res1 = ctx.load_labware(res_type, "D2", "reagent reservoir 1") + res1 = protocol.load_labware(res_type, "D2", "reagent reservoir 1") num_cols = math.ceil(num_samples / 8) # Load tips and combine all similar boxes - tips200 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "A1", "Tips 1") - tips201 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "A2", "Tips 2") - tips202 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "B1", "Tips 3") - tips203 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "B2", "Tips 4") - tips = [ - *tips200.wells()[num_samples:96], - *tips201.wells(), - *tips202.wells(), - *tips203.wells(), - ] + tips200 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "A1", "Tips 1") + tips201 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "A2", "Tips 2") + tips202 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "B1", "Tips 3") + tips203 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "B2", "Tips 4") + tips204 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "C2", "Tips 5") + tips_sn = tips200.wells()[:num_samples] # load P1000M pipette - m1000 = ctx.load_instrument( + m1000 = protocol.load_instrument( "flex_8channel_1000", pipette_mount, - tip_racks=[tips200, tips201, tips202, tips203], + tip_racks=[tips200, tips201, tips202, tips203, tips204], ) # Load Liquid Locations in Reservoir elution_solution = elutionplate.rows()[0][:num_cols] - dnase1 = elutionplate.rows()[0][num_cols : 2 * num_cols] - lysis_ = res1.wells()[0] - stopreaction = res1.wells()[1] - wash1 = res1.wells()[2] - wash2 = res1.wells()[3] - wash3 = res1.wells()[4] - wash4 = res1.wells()[5] - wash5 = res1.wells()[6] - + dnase1 = elutionplate.rows()[0][:num_cols] + lysis_ = res1.wells()[0:2] + stopreaction = res1.wells()[2] + wash1 = res1.wells()[3] + wash2 = res1.wells()[4] + wash3 = res1.wells()[5] + wash4 = res1.wells()[6] + wash5 = res1.wells()[7] + wash6 = res1.wells()[8] + wash7 = res1.wells()[9] + wash8 = res1.wells()[10] + wash9 = res1.wells()[11] + all_washes = res1.wells()[3:12] """ Here is where you can define the locations of your reagents. """ samples_m = sample_plate.rows()[0][:num_cols] # 20ul beads each well - cells_m = sample_plate.rows()[0][num_cols : 2 * num_cols] + cells_m = sample_plate.rows()[0][:num_cols] elution_samples_m = elutionplate.rows()[0][:num_cols] # Do the same for color mapping beads_ = sample_plate.wells()[: (8 * num_cols)] @@ -163,36 +172,42 @@ def run(ctx: ProtocolContext) -> None: "Sample": [{"well": cells_, "volume": 0.0}], "DNAse": [{"well": dnase1_, "volume": dnase_vol}], "Elution Buffer": [{"well": elution_samps, "volume": elution_vol}], - "Lysis": [{"well": lysis_, "volume": lysis_vol}], - "Wash 1": [{"well": wash1, "volume": wash_vol}], - "Wash 2": [{"well": wash2, "volume": wash_vol}], - "Wash 3": [{"well": wash3, "volume": wash_vol}], - "Wash 4": [{"well": wash4, "volume": wash_vol}], - "Wash 5": [{"well": wash5, "volume": wash_vol}], - "Stop": [{"well": stopreaction, "volume": stop_vol}], + "Lysis": [{"well": lysis_, "volume": 8120.0}], + "Stop": [{"well": stopreaction, "volume": 6400.0}], + "Wash 1": [{"well": wash1, "volume": 9500.0}], + "Wash 2": [{"well": wash2, "volume": 9500.0}], + "Wash 3": [{"well": wash3, "volume": 9500.0}], + "Wash 4": [{"well": wash4, "volume": 9500.0}], + "Wash 5": [{"well": wash5, "volume": 9500.0}], + "Wash 6": [{"well": wash6, "volume": 9500.0}], + "Wash 7": [{"well": wash7, "volume": 9500.0}], + "Wash 8": [{"well": wash8, "volume": 9500.0}], + "Wash 9": [{"well": wash9, "volume": 9500.0}], } - helpers.find_liquid_height_of_loaded_liquids(ctx, liquid_vols_and_wells, m1000) + helpers.find_liquid_height_of_loaded_liquids(protocol, liquid_vols_and_wells, m1000) m1000.flow_rate.aspirate = 50 m1000.flow_rate.dispense = 150 m1000.flow_rate.blow_out = 300 - def tiptrack(pip: InstrumentContext, tipbox: List[Well]) -> None: + def tiptrack(pip: InstrumentContext) -> None: """Tip Track.""" - global tip + global tip_pick_up global drop_count - pip.pick_up_tip(tipbox[int(tip)]) - tip = tip + 8 + pip.pick_up_tip() + tip_pick_up += 1 drop_count = drop_count + 8 if drop_count >= 250: drop_count = 0 if TIP_TRASH: - ctx.pause("Empty Trash bin.") + protocol.pause("Empty Trash bin.") + if tip_pick_up >= 59: + pip.reset_tipracks() def remove_supernatant(vol: float) -> None: """Remove Supernatant.""" - ctx.comment("-----Removing Supernatant-----") + protocol.comment("-----Removing Supernatant-----") m1000.flow_rate.aspirate = 30 num_trans = math.ceil(vol / 180) vol_per_trans = vol / num_trans @@ -211,7 +226,7 @@ def remove_supernatant(vol: float) -> None: m1000.drop_tip(tips_sn[8 * i]) if TIP_TRASH else m1000.return_tip() m1000.flow_rate.aspirate = 300 # Move Plate From Magnet to H-S - helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + helpers.move_labware_to_hs(protocol, sample_plate, h_s, h_s_adapter) def bead_mixing( well: Well, pip: InstrumentContext, mvol: float, reps: int = 8 @@ -301,32 +316,39 @@ def mixing(well: Well, pip: InstrumentContext, mvol: float, reps: int = 8) -> No pip.flow_rate.aspirate = 300 pip.flow_rate.dispense = 300 - def lysis(vol: float, source: Well) -> None: + def lysis(vol: float, source: List[Well]) -> None: """Lysis Steps.""" - ctx.comment("-----Beginning lysis steps-----") + tvol_total = 0.0 + protocol.comment("-----Beginning lysis steps-----") num_transfers = math.ceil(vol / 180) - tiptrack(m1000, tips) + tiptrack(m1000) + src = source[0] for i in range(num_cols): - src = source tvol = vol / num_transfers for t in range(num_transfers): m1000.require_liquid_presence(src) m1000.aspirate(tvol, src.bottom(1)) m1000.dispense(m1000.current_volume, cells_m[i].top(-3)) + tvol_total += tvol * 8 + if tvol_total > 8000.0: + protocol.comment("-----Changing to second lysis well.------") + src = source[1] + protocol.comment(f"new source {src}") + tvol_total = 0.0 # mix after adding all reagent to wells with cells for i in range(num_cols): if i != 0: - tiptrack(m1000, tips) + tiptrack(m1000) for x in range(8 if not dry_run else 1): m1000.aspirate(tvol * 0.75, cells_m[i].bottom(dot_bottom)) m1000.dispense(tvol * 0.75, cells_m[i].bottom(8)) if x == 3: - ctx.delay(minutes=0.0167) + protocol.delay(minutes=0.0167) m1000.blow_out(cells_m[i].bottom(1)) m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, lysis_time, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, lysis_time, True) def bind() -> None: """Bind. @@ -344,10 +366,10 @@ def bind() -> None: supernatant to the final clean elutions PCR plate. """ - ctx.comment("-----Beginning bind steps-----") + protocol.comment("-----Beginning bind steps-----") for i, well in enumerate(samples_m): # Transfer cells+lysis/bind to wells with beads - tiptrack(m1000, tips) + tiptrack(m1000) m1000.aspirate(185, cells_m[i].bottom(dot_bottom)) m1000.air_gap(10) m1000.dispense(m1000.current_volume, well.bottom(8)) @@ -355,15 +377,17 @@ def bind() -> None: bead_mixing(well, m1000, 130, reps=5 if not dry_run else 1) m1000.air_gap(10) m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, bind_time, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, bind_time, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) for bindi in np.arange( settling_time, 0, -0.5 ): # Settling time delay with countdown timer - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(bindi) + " minutes left in the incubation.", ) @@ -371,45 +395,43 @@ def bind() -> None: # remove initial supernatant remove_supernatant(180) - def wash(vol: float, source: Well) -> None: + def wash(vol: float, source: List[Well]) -> None: """Wash Function.""" global whichwash # Defines which wash the protocol is on to log on the app - - if source == wash1: - whichwash = 1 - if source == wash2: - whichwash = 2 - if source == wash3: - whichwash = 3 - if source == wash4: - whichwash = 4 - - ctx.comment("-----Now starting Wash #" + str(whichwash) + "-----") - - tiptrack(m1000, tips) + protocol.comment("-----Now starting Wash #" + str(whichwash) + "-----") + global wash_volume_tracker + tiptrack(m1000) num_trans = math.ceil(vol / 180) vol_per_trans = vol / num_trans for i, m in enumerate(samples_m): - src = source + src = source[whichwash] for n in range(num_trans): m1000.aspirate(vol_per_trans, src) m1000.air_gap(10) m1000.dispense(m1000.current_volume, m.top(-2)) - ctx.delay(seconds=2) + protocol.delay(seconds=2) m1000.blow_out(m.top(-2)) + wash_volume_tracker += vol_per_trans * 8 + if wash_volume_tracker > 9600: + whichwash += 1 + src = source[whichwash] + protocol.comment(f"new wash source {whichwash}") + wash_volume_tracker = 0.0 m1000.air_gap(10) m1000.drop_tip() if TIP_TRASH else m1000.return_tip() # Shake for 5 minutes to mix wash with beads - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, wash_time, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, wash_time, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) for washi in np.arange( settling_time, 0, -0.5 ): # settling time timer for washes - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(washi) @@ -419,13 +441,14 @@ def wash(vol: float, source: Well) -> None: ) remove_supernatant(vol) + protocol.comment(f"final wash source {whichwash}") def dnase(vol: float, source: List[Well]) -> None: """Steps for DNAseI.""" - ctx.comment("-----DNAseI Steps Beginning-----") + protocol.comment("-----DNAseI Steps Beginning-----") num_trans = math.ceil(vol / 180) vol_per_trans = vol / num_trans - tiptrack(m1000, tips) + tiptrack(m1000) for i, m in enumerate(samples_m): src = source[i] m1000.flow_rate.aspirate = 10 @@ -442,17 +465,17 @@ def dnase(vol: float, source: List[Well]) -> None: # Is this mixing needed? \/\/\/ for i in range(num_cols): if i != 0: - tiptrack(m1000, tips) + tiptrack(m1000) mixing(samples_m[i], m1000, 45, reps=5 if not dry_run else 1) m1000.drop_tip() if TIP_TRASH else m1000.return_tip() # Shake for 10 minutes to mix DNAseI - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, dnase_time, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, dnase_time, True) def stop_reaction(vol: float, source: Well) -> None: """Adding stop solution.""" - ctx.comment("-----Adding Stop Solution-----") - tiptrack(m1000, tips) + protocol.comment("-----Adding Stop Solution-----") + tiptrack(m1000) num_trans = math.ceil(vol / 180) vol_per_trans = vol / num_trans for i, m in enumerate(samples_m): @@ -467,13 +490,15 @@ def stop_reaction(vol: float, source: Well) -> None: m1000.drop_tip() if TIP_TRASH else m1000.return_tip() # Shake for 3 minutes to mix wash with beads - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, stop_time, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, stop_time, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) for stop in np.arange(settling_time, 0, -0.5): - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(stop) + " minutes left in this incubation.", ) @@ -482,8 +507,8 @@ def stop_reaction(vol: float, source: Well) -> None: def elute(vol: float) -> None: """Elution.""" - ctx.comment("-----Elution Beginning-----") - tiptrack(m1000, tips) + protocol.comment("-----Elution Beginning-----") + tiptrack(m1000) m1000.flow_rate.aspirate = 10 for i, m in enumerate(samples_m): loc = m.top(-2) @@ -498,7 +523,7 @@ def elute(vol: float) -> None: # Is this mixing needed? \/\/\/ for i in range(num_cols): if i != 0: - tiptrack(m1000, tips) + tiptrack(m1000) for mixes in range(10): m1000.aspirate(elution_vol - 10, samples_m[i]) m1000.dispense(elution_vol - 10, samples_m[i].bottom(10)) @@ -510,20 +535,22 @@ def elute(vol: float) -> None: m1000.drop_tip() if TIP_TRASH else m1000.return_tip() # Shake for 3 minutes to mix wash with beads - helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, elute_time, True) + helpers.set_hs_speed(protocol, h_s, heater_shaker_speed, elute_time, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) for elutei in np.arange(settling_time, 0, -0.5): - ctx.delay( + protocol.delay( minutes=0.5, msg="Incubating on MagDeck for " + str(elutei) + " more minutes.", ) - ctx.comment("-----Trasnferring Sample to Elution Plate-----") + protocol.comment("-----Trasnferring Sample to Elution Plate-----") for i, (m, e) in enumerate(zip(samples_m, elution_samples_m)): - tiptrack(m1000, tips) + tiptrack(m1000) loc = m.bottom(dot_bottom) m1000.transfer(vol, loc, e.bottom(5), air_gap=20, new_tip="never") m1000.blow_out(e.top(-2)) @@ -537,23 +564,27 @@ def elute(vol: float) -> None: if inc_lysis: lysis(lysis_vol, lysis_) bind() - wash(wash_vol, wash1) - wash(wash_vol, wash2) + wash(wash_vol, all_washes) + wash(wash_vol, all_washes) + wash(wash_vol, all_washes) # dnase1 treatment dnase(dnase_vol, dnase1) stop_reaction(stop_vol, stopreaction) # Resume washes - wash(wash_vol, wash3) - wash(wash_vol, wash4) - wash(wash_vol, wash5) + wash(wash_vol, all_washes) + wash(wash_vol, all_washes) + wash(wash_vol, all_washes) for beaddry in np.arange(drybeads, 0, -0.5): - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(beaddry) + " minutes left in the drying step.", ) elute(elution_vol) - - end_list_of_wells_to_probe = [waste_reservoir["A1"], res1["A1"]] - end_list_of_wells_to_probe.extend(elution_samples_m) - helpers.find_liquid_height_of_all_wells(ctx, m1000, end_list_of_wells_to_probe) + end_list_of_wells_to_probe = [waste_reservoir["A1"]] + helpers.clean_up_plates( + m1000, [elutionplate, sample_plate], waste_reservoir["A1"], 200 + ) + helpers.find_liquid_height_of_all_wells(protocol, m1000, end_list_of_wells_to_probe) + if deactivate_modules_bool: + helpers.deactivate_modules(protocol) diff --git a/abr-testing/abr_testing/protocols/csv_parameters/1_samplevols.csv b/abr-testing/abr_testing/protocols/csv_parameters/1_samplevols.csv new file mode 100644 index 00000000000..132b4dc70fb --- /dev/null +++ b/abr-testing/abr_testing/protocols/csv_parameters/1_samplevols.csv @@ -0,0 +1,97 @@ +Well,Dye,Diluent +A1,0,100 +B1,5,95 +C1,10,90 +D1,20,80 +E1,40,60 +F1,15,40 +G1,40,20 +H1,40,0 +A2,35,65 +B2,38,42 +C2,42,58 +D2,32,8 +E2,38,12 +F2,26,74 +G2,31,69 +H2,46,4 +A3,47,13 +B3,42,18 +C3,46,64 +D3,48,22 +E3,26,74 +F3,34,66 +G3,43,37 +H3,20,80 +A4,44,16 +B4,49,41 +C4,48,42 +D4,44,16 +E4,47,53 +F4,47,33 +G4,42,48 +H4,39,21 +A5,30,20 +B5,36,14 +C5,31,59 +D5,38,52 +E5,36,4 +F5,32,28 +G5,35,55 +H5,39,1 +A6,31,59 +B6,20,80 +C6,38,2 +D6,34,46 +E6,30,70 +F6,32,58 +G6,21,79 +H6,38,52 +A7,33,27 +B7,34,16 +C7,40,60 +D7,34,26 +E7,30,20 +F7,44,56 +G7,26,74 +H7,45,55 +A8,39,1 +B8,38,2 +C8,34,66 +D8,39,11 +E8,46,54 +F8,37,63 +G8,38,42 +H8,34,66 +A9,44,56 +B9,39,11 +C9,30,70 +D9,37,33 +E9,46,54 +F9,39,21 +G9,29,41 +H9,23,77 +A10,26,74 +B10,39,1 +C10,31,49 +D10,38,62 +E10,29,1 +F10,21,79 +G10,29,41 +H10,28,42 +A11,15,55 +B11,28,72 +C11,11,49 +D11,34,66 +E11,27,73 +F11,30,40 +G11,33,67 +H11,31,39 +A12,39,31 +B12,47,53 +C12,46,54 +D12,13,7 +E12,34,46 +F12,45,35 +G12,28,42 +H12,37,63 \ No newline at end of file diff --git a/abr-testing/abr_testing/protocols/csv_parameters/2_samplevols.csv b/abr-testing/abr_testing/protocols/csv_parameters/2_samplevols.csv index fa50562e68b..424aae072c3 100644 --- a/abr-testing/abr_testing/protocols/csv_parameters/2_samplevols.csv +++ b/abr-testing/abr_testing/protocols/csv_parameters/2_samplevols.csv @@ -6,20 +6,92 @@ D1,3,7,40,A1 E1,2,8,40,A2 F1,1,9,40,A2 G1,5,5,40,A2 -H1,3,7,40,A3 +H1,3,7,40,A2 A2,3,7,40,A3 B2,3,7,40,A3 C2,3,7,40,A3 D2,3,7,40,A3 -E2,3,7,40,A3 -F2,3,7,40,A3 -G2,3,7,40,A3 -H2,3,7,40,A3 -A3,3,7,40,A3 -B3,3,7,40,A3 -C3,3,7,45,A3 -D3,3,7,45,A3 -E3,3,5,45,A3 -F3,3,5,45,A3 +E2,3,7,40,A4 +F2,3,7,40,A4 +G2,3,7,40,A4 +H2,3,7,40,A4 +A3,3,7,40,A5 +B3,3,7,40,A5 +C3,3,7,45,A5 +D3,3,7,45,A5 +E3,3,5,45,A6 +F3,3,5,45,A6 G3,3,5,45,A6 -H3,3,4,45,A5 \ No newline at end of file +H3,3,4,45,A6 +A4,3,7,40,A1 +B4,0,10,40,A1 +C4,10,0,40,A1 +D4,3,7,40,A1 +E4,2,8,40,A2 +F4,1,9,40,A2 +G4,5,5,40,A2 +H4,3,7,40,A2 +A5,3,7,40,A3 +B5,3,7,40,A3 +C5,3,7,40,A3 +D5,3,7,40,A3 +E5,3,7,40,A4 +F5,3,7,40,A4 +G5,3,7,40,A4 +H5,3,7,40,A4 +A6,3,7,40,A5 +B6,3,7,40,A5 +C6,3,7,45,A5 +D6,3,7,45,A5 +E6,3,5,45,A6 +F6,3,5,45,A6 +G6,3,5,45,A6 +H6,3,4,45,A6 +A7,3,7,40,A1 +B7,0,10,40,A1 +C7,10,0,40,A1 +D7,3,7,40,A1 +E7,2,8,40,A2 +F7,1,9,40,A2 +G7,5,5,40,A2 +H7,3,7,40,A2 +A8,3,7,40,A3 +B8,3,7,40,A3 +C8,3,7,40,A3 +D8,3,7,40,A3 +E8,3,7,40,A4 +F8,3,7,40,A4 +G8,3,7,40,A4 +H8,3,7,40,A4 +A9,3,7,40,A5 +B9,3,7,40,A5 +C9,3,7,45,A5 +D9,3,7,45,A5 +E9,3,5,45,A6 +F9,3,5,45,A6 +G9,3,5,45,A6 +H9,3,4,45,A6 +A10,3,7,40,A1 +B10,0,10,40,A1 +C10,10,0,40,A1 +D10,3,7,40,A1 +E10,2,8,40,A2 +F10,1,9,40,A2 +G10,5,5,40,A2 +H10,3,7,40,A2 +A11,3,7,40,A3 +B11,3,7,40,A3 +C11,3,7,40,A3 +D11,3,7,40,A3 +E11,3,7,40,A4 +F11,3,7,40,A4 +G11,3,7,40,A4 +H11,3,7,40,A4 +A12,3,7,40,A5 +B12,3,7,40,A5 +C12,3,7,45,A5 +D12,3,7,45,A5 +E12,3,5,45,A6 +F12,3,5,45,A6 +G12,3,5,45,A6 +H12,3,4,45,A6 diff --git a/abr-testing/abr_testing/protocols/helpers.py b/abr-testing/abr_testing/protocols/helpers.py index 12abbfa9b3f..31a1d1a9244 100644 --- a/abr-testing/abr_testing/protocols/helpers.py +++ b/abr-testing/abr_testing/protocols/helpers.py @@ -7,14 +7,15 @@ ParameterContext, Well, ) -from typing import Tuple from opentrons.protocol_api.module_contexts import ( HeaterShakerContext, MagneticBlockContext, ThermocyclerContext, TemperatureModuleContext, + MagneticModuleContext, + AbsorbanceReaderContext, ) -from typing import List, Union, Dict +from typing import List, Union, Dict, Tuple from opentrons.hardware_control.modules.types import ThermocyclerStep from opentrons_shared_data.errors.exceptions import PipetteLiquidNotFoundError @@ -106,7 +107,62 @@ def load_temp_adapter_and_labware( return labware_on_temp_mod, temp_adapter +# FUNCTIONS FOR COMMON COMMENTS + + +def comment_protocol_version(protocol: ProtocolContext, version: str) -> None: + """Comment version number of protocol.""" + protocol.comment(f"Protocol Version: {version}") + + # FUNCTIONS FOR LOADING COMMON PARAMETERS +def create_channel_parameter(parameters: ParameterContext) -> None: + """Create pipette channel parameter.""" + parameters.add_str( + variable_name="channels", + display_name="Number of Pipette Channels", + choices=[ + {"display_name": "1 Channel", "value": "1channel"}, + {"display_name": "8 Channel", "value": "8channel"}, + ], + default="8channel", + ) + + +def create_pipette_parameters(parameters: ParameterContext) -> None: + """Create parameter for pipettes.""" + # NOTE: Place function inside def add_parameters(parameters) in protocol. + # NOTE: Copy ctx.params.left mount, ctx.params.right_mount # type: ignore[attr-defined] + # to get result + # Left Mount + parameters.add_str( + variable_name="left_mount", + display_name="Left Mount", + description="Pipette Type on Left Mount.", + choices=[ + {"display_name": "8ch 50ul", "value": "flex_8channel_50"}, + {"display_name": "8ch 1000ul", "value": "flex_8channel_1000"}, + {"display_name": "1ch 50ul", "value": "flex_1channel_50"}, + {"display_name": "1ch 1000ul", "value": "flex_1channel_1000"}, + {"display_name": "96ch 1000ul", "value": "flex_96channel_1000"}, + {"display_name": "None", "value": "none"}, + ], + default="flex_8channel_1000", + ) + # Right Mount + parameters.add_str( + variable_name="right_mount", + display_name="Right Mount", + description="Pipette Type on Right Mount.", + choices=[ + {"display_name": "8ch 50ul", "value": "flex_8channel_50"}, + {"display_name": "8ch 1000ul", "value": "flex_8channel_1000"}, + {"display_name": "1ch 50ul", "value": "flex_1channel_50"}, + {"display_name": "1ch 1000ul", "value": "flex_1channel_1000"}, + {"display_name": "None", "value": "none"}, + ], + default="none", + ) def create_single_pipette_mount_parameter(parameters: ParameterContext) -> None: @@ -163,6 +219,16 @@ def create_disposable_lid_parameter(parameters: ParameterContext) -> None: ) +def create_disposable_lid_trash_location(parameters: ParameterContext) -> None: + """Create a parameter for lid placement after use.""" + parameters.add_bool( + variable_name="trash_lid", + display_name="Trash Disposable Lid", + description="True means trash lid, false means keep on deck.", + default=True, + ) + + def create_tc_lid_deck_riser_parameter(parameters: ParameterContext) -> None: """Create parameter for tc lid deck riser.""" parameters.add_bool( @@ -184,7 +250,7 @@ def create_tip_size_parameter(parameters: ParameterContext) -> None: {"display_name": "200 µL", "value": "opentrons_flex_96_tiprack_200ul"}, {"display_name": "1000 µL", "value": "opentrons_flex_96_tiprack_1000ul"}, ], - default="opentrons_flex_96_tiprack_1000ul", + default="opentrons_flex_96_tiprack_50ul", ) @@ -224,6 +290,25 @@ def create_hs_speed_parameter(parameters: ParameterContext) -> None: ) +def create_plate_reader_compatible_labware_parameter( + parameters: ParameterContext, +) -> None: + """Create parameter for flat bottom plates compatible with plate reader.""" + parameters.add_str( + variable_name="labware_plate_reader_compatible", + display_name="Plate Reader Labware", + default="nest_96_wellplate_200ul_flat", + choices=[ + { + "display_name": "Corning_96well", + "value": "corning_96_wellplate_360ul_flat", + }, + {"display_name": "Hellma Plate", "value": "hellma_reference_plate"}, + {"display_name": "Nest_96well", "value": "nest_96_wellplate_200ul_flat"}, + ], + ) + + def create_tc_compatible_labware_parameter(parameters: ParameterContext) -> None: """Create parameter for labware type compatible with thermocycler.""" parameters.add_str( @@ -249,7 +334,33 @@ def create_tc_compatible_labware_parameter(parameters: ParameterContext) -> None ) +def create_deactivate_modules_parameter(parameters: ParameterContext) -> None: + """Create parameter for deactivating modules at the end fof run.""" + parameters.add_bool( + variable_name="deactivate_modules", + display_name="Deactivate Modules", + description="deactivate all modules at end of run", + default=True, + ) + + # FUNCTIONS FOR COMMON MODULE SEQUENCES +def deactivate_modules(protocol: ProtocolContext) -> None: + """Deactivate all loaded modules.""" + print("Deactivating Modules") + modules = protocol.loaded_modules + + if modules: + for module in modules.values(): + if isinstance(module, HeaterShakerContext): + module.deactivate_shaker() + module.deactivate_heater() + elif isinstance(module, TemperatureModuleContext): + module.deactivate() + elif isinstance(module, MagneticModuleContext): + module.disengage() + elif isinstance(module, ThermocyclerContext): + module.deactivate() def move_labware_from_hs_to_destination( @@ -314,6 +425,39 @@ def use_disposable_lid_with_tc( # FUNCTIONS FOR COMMON PIPETTE COMMAND SEQUENCES +def clean_up_plates( + pipette: InstrumentContext, + list_of_labware: List[Labware], + liquid_waste: Well, + tip_size: int, +) -> None: + """Aspirate liquid from labware and dispense into liquid waste.""" + pipette.pick_up_tip() + pipette.liquid_presence_detection = False + num_of_active_channels = pipette.active_channels + for labware in list_of_labware: + if num_of_active_channels == 8: + list_of_wells = labware.rows()[0] + elif num_of_active_channels == 1: + list_of_wells = labware.wells() + elif num_of_active_channels == 96: + list_of_wells = [labware.wells()[0]] + for well in list_of_wells: + vol_removed = 0.0 + while well.max_volume > vol_removed: + pipette.aspirate(tip_size, well) + pipette.dispense( + tip_size, + liquid_waste.top(), + ) + pipette.blow_out(liquid_waste.top()) + vol_removed += pipette.max_volume + if pipette.channels != num_of_active_channels: + pipette.drop_tip() + else: + pipette.return_tip() + + def find_liquid_height(pipette: InstrumentContext, well_to_probe: Well) -> float: """Find liquid height of well.""" try: @@ -372,6 +516,18 @@ def load_wells_with_custom_liquids( well.load_liquid(liquid, volume) +def comment_height_of_specific_labware( + protocol: ProtocolContext, labware_name: str, dict_of_labware_heights: Dict +) -> None: + """Comment height found of specific labware.""" + total_height = 0.0 + for key in dict_of_labware_heights.keys(): + if key[0] == labware_name: + height = dict_of_labware_heights[key] + total_height += height + protocol.comment(f"Liquid Waste Total Height: {total_height}") + + def find_liquid_height_of_all_wells( protocol: ProtocolContext, pipette: InstrumentContext, @@ -382,7 +538,7 @@ def find_liquid_height_of_all_wells( pipette.pick_up_tip() pip_channels = pipette.active_channels for well in wells: - labware_name = well.parent.load_name + labware_name = well.parent.name total_number_of_wells_in_plate = len(well.parent.wells()) # if pip_channels is > 1 and total_wells > 12 - only probe 1st row. if ( @@ -402,6 +558,9 @@ def find_liquid_height_of_all_wells( pipette.reset_tipracks() msg = f"result: {dict_of_labware_heights}" protocol.comment(msg=msg) + comment_height_of_specific_labware( + protocol, "Liquid Waste", dict_of_labware_heights + ) return dict_of_labware_heights @@ -423,6 +582,8 @@ def find_liquid_height_of_loaded_liquids( entry["well"] if isinstance(entry["well"], list) else [entry["well"]] ) ] + if pipette.active_channels == 96: + wells = [well for well in wells if well.display_name.split(" ")[0] == "A1"] find_liquid_height_of_all_wells(ctx, pipette, wells) return wells @@ -463,6 +624,14 @@ def load_wells_with_water( "#C0C0C0", ] +# Modules with deactivate +ModuleTypes = Union[ + TemperatureModuleContext, + ThermocyclerContext, + HeaterShakerContext, + MagneticModuleContext, + AbsorbanceReaderContext, +] # THERMOCYCLER PROFILES @@ -501,6 +670,3 @@ def perform_pcr( thermocycler.execute_profile( steps=final_extension_profile, repetitions=1, block_max_volume=50 ) - - -# TODO: Create dictionary of labware, module, and adapter. diff --git a/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py index 422102e4321..76b72b97164 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py @@ -13,7 +13,7 @@ requirements = { "robotType": "Flex", - "apiLevel": "2.20", + "apiLevel": "2.21", } @@ -26,14 +26,16 @@ def run(protocol: protocol_api.ProtocolContext) -> None: p1000, ) = load_common_liquid_setup_labware_and_instruments(protocol) - res1 = protocol.load_labware("nest_12_reservoir_15ml", "C3", "R1") - res2 = protocol.load_labware("nest_12_reservoir_15ml", "B3", "R2") + res1 = protocol.load_labware("nest_12_reservoir_15ml", "D3", "Reagent Reservoir 1") + res2 = protocol.load_labware("nest_12_reservoir_15ml", "C3", "Reagent Reservoir 2") + res3 = protocol.load_labware("nest_12_reservoir_15ml", "B3", "Reagent Reservoir 3") lysis_and_pk = 12320 / 8 beads_and_binding = 11875 / 8 binding2 = 13500 / 8 - wash2 = 9000 / 8 + wash2 = 9800 / 8 wash2_list = [wash2] * 12 + final_elution = 1200 / 8 # Fill up Plates # Res1 p1000.transfer( @@ -42,7 +44,10 @@ def run(protocol: protocol_api.ProtocolContext) -> None: beads_and_binding, beads_and_binding, beads_and_binding, - binding2, + beads_and_binding, + beads_and_binding, + beads_and_binding, + beads_and_binding, binding2, binding2, binding2, @@ -58,6 +63,9 @@ def run(protocol: protocol_api.ProtocolContext) -> None: res1["A6"].top(), res1["A7"].top(), res1["A8"].top(), + res1["A9"].top(), + res1["A10"].top(), + res1["A11"].top(), res1["A12"].top(), ], blow_out=True, @@ -66,10 +74,19 @@ def run(protocol: protocol_api.ProtocolContext) -> None: ) # Res2 p1000.transfer( - volume=wash2_list, - source=source_reservoir["A1"], + volume=[final_elution] + wash2_list[:11], + source=[source_reservoir["A1"]] * 12, dest=res2.wells(), blow_out=True, blowout_location="source well", trash=False, ) + # Res 3 + p1000.transfer( + volume=[wash2, wash2], + source=[source_reservoir["A1"], source_reservoir["A1"]], + dest=[res3["A1"], res3["A2"]], + blow_out=True, + blowout_location="source well", + trash=False, + ) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py index 112aec315b5..2d722d410e5 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py @@ -13,7 +13,7 @@ requirements = { "robotType": "Flex", - "apiLevel": "2.20", + "apiLevel": "2.21", } @@ -27,8 +27,11 @@ def run(protocol: protocol_api.ProtocolContext) -> None: ) = load_common_liquid_setup_labware_and_instruments(protocol) reservoir_wash = protocol.load_labware("nest_12_reservoir_15ml", "D2", "Reservoir") - sample_plate = protocol.load_labware( - "nest_96_wellplate_2ml_deep", "C3", "Sample Plate" + sample_plate1 = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "C3", "Sample Plate 1" + ) + sample_plate2 = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "B3", "Sample Plate 2" ) columns = [ @@ -52,10 +55,24 @@ def run(protocol: protocol_api.ProtocolContext) -> None: p1000.dispense(750, reservoir_wash[i].top()) p1000.blow_out(location=source_reservoir["A1"].top()) p1000.return_tip() + # 1 column 6000 uL + p1000.pick_up_tip() + for i in columns: + p1000.aspirate(750, source_reservoir["A1"].bottom(z=0.5)) + p1000.dispense(750, reservoir_wash[i].top()) + p1000.blow_out(location=source_reservoir["A1"].top()) + p1000.return_tip() + # Nest 96 Deep Well Plate 2 mL: 250 uL per well + p1000.pick_up_tip() + for n in columns: + p1000.aspirate(250, source_reservoir["A1"].bottom(z=0.5)) + p1000.dispense(250, sample_plate1[n].bottom(z=1)) + p1000.blow_out(location=source_reservoir["A1"].top()) + p1000.return_tip() # Nest 96 Deep Well Plate 2 mL: 250 uL per well p1000.pick_up_tip() for n in columns: p1000.aspirate(250, source_reservoir["A1"].bottom(z=0.5)) - p1000.dispense(250, sample_plate[n].bottom(z=1)) + p1000.dispense(250, sample_plate2[n].bottom(z=1)) p1000.blow_out(location=source_reservoir["A1"].top()) p1000.return_tip() diff --git a/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py index 2575caecf6e..688533ffd55 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py @@ -13,7 +13,7 @@ requirements = { "robotType": "Flex", - "apiLevel": "2.20", + "apiLevel": "2.21", } diff --git a/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py index 2d995fede39..a99bb0568cf 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py @@ -12,7 +12,7 @@ requirements = { "robotType": "Flex", - "apiLevel": "2.20", + "apiLevel": "2.21", } @@ -26,14 +26,22 @@ def run(protocol: protocol_api.ProtocolContext) -> None: ) = load_common_liquid_setup_labware_and_instruments(protocol) reservoir = protocol.load_labware("nest_12_reservoir_15ml", "D2", "Reservoir") # Transfer Liquid - vol = 5400 / 8 + vol = 6175 / 8 columns = ["A1", "A2", "A3", "A4", "A5"] for i in columns: p1000.transfer( vol, - source=source_reservoir["A1"].bottom(z=0.5), + source=source_reservoir["A1"].bottom(z=2), dest=reservoir[i].top(), blowout=True, blowout_location="source well", trash=False, ) + p1000.transfer( + 8500 / 8, + source=source_reservoir["A1"].bottom(z=2), + dest=reservoir["A6"], + blowout=True, + blowout_location="source well", + trash=False, + ) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py index a6c71b563d4..1ffefc48f19 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py @@ -7,13 +7,13 @@ metadata = { "protocolName": "DVT1ABR2 Liquids: BMS PCR Protocol", - "author": "Rhyann clarke ", + "author": "Rhyann Clarke ", "source": "Protocol Library", } requirements = { "robotType": "Flex", - "apiLevel": "2.20", + "apiLevel": "2.21", } @@ -33,9 +33,9 @@ def run(protocol: protocol_api.ProtocolContext) -> None: ) # Steps # Dispense into plate 1 - p1000.transfer(50, source_reservoir["A1"], pcr_plate_1.wells(), trash=False) + p1000.transfer(100, source_reservoir["A1"], pcr_plate_1.wells(), trash=False) # Dispense p1000.configure_nozzle_layout(protocol_api.SINGLE, start="H1", tip_racks=[tip_rack]) - p1000.transfer(1500, source_reservoir["A1"], snap_caps["B1"]) - p1000.transfer(1500, source_reservoir["A1"], snap_caps.rows()[0]) + p1000.transfer(1000, source_reservoir["A1"], snap_caps["B1"]) + p1000.transfer(1000, source_reservoir["A1"], snap_caps.rows()[0]) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/3_Tartrazine Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/3_Tartrazine Liquid Setup.py index 9e0b29a03ed..f0941bb398b 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/3_Tartrazine Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/3_Tartrazine Liquid Setup.py @@ -1,8 +1,6 @@ """Plate Filler Protocol for Tartrazine Protocol.""" from opentrons import protocol_api -from abr_testing.protocols.helpers import ( - load_common_liquid_setup_labware_and_instruments, -) +from abr_testing.protocols import helpers metadata = { "protocolName": "DVT1ABR3 Liquids: Tartrazine Protocol", @@ -12,36 +10,77 @@ requirements = { "robotType": "Flex", - "apiLevel": "2.20", + "apiLevel": "2.21", } +def add_parameters(parameters: protocol_api.ParameterContext) -> None: + """Add parameters.""" + parameters.add_int( + variable_name="number_of_plates", + display_name="Number of Plates", + default=4, + minimum=1, + maximum=4, + ) + helpers.create_channel_parameter(parameters) + + def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" + number_of_plates = protocol.params.number_of_plates # type: ignore [attr-defined] + channels = protocol.params.channels # type: ignore [attr-defined] # Initiate Labware ( source_reservoir, tip_rack, p1000, - ) = load_common_liquid_setup_labware_and_instruments(protocol) - reagent_tube = protocol.load_labware( - "opentrons_10_tuberack_falcon_4x50ml_6x15ml_conical", "D3", "Reagent Tube" - ) - p1000.configure_nozzle_layout( - style=protocol_api.SINGLE, start="H1", tip_racks=[tip_rack] - ) - # Transfer Liquid - p1000.transfer( - 45000, - source_reservoir["A1"], - reagent_tube["B3"].top(), - blowout=True, - blowout_location="source well", - ) - p1000.transfer( - 45000, - source_reservoir["A1"], - reagent_tube["A4"].top(), - blowout=True, - blowout_location="source well", - ) + ) = helpers.load_common_liquid_setup_labware_and_instruments(protocol) + if channels == "1channel": + reagent_tube = protocol.load_labware( + "opentrons_10_tuberack_falcon_4x50ml_6x15ml_conical", "D3", "Reagent Tube" + ) + p1000.configure_nozzle_layout( + style=protocol_api.SINGLE, start="H1", tip_racks=[tip_rack] + ) + # Transfer Liquid + p1000.transfer( + 45000, + source_reservoir["A1"], + reagent_tube["B3"].top(), + blowout=True, + blowout_location="source well", + ) + p1000.transfer( + 45000, + source_reservoir["A1"], + reagent_tube["A4"].top(), + blowout=True, + blowout_location="source well", + ) + elif channels == "8channel": + reservoir = protocol.load_labware("nest_12_reservoir_15ml", "D3", "Reservoir") + water_max_vol = reservoir["A1"].max_volume - 500 + reservoir_wells = reservoir.wells()[ + 1: + ] # Skip A1 as it's reserved for tartrazine + # NEEDED WATER + needed_water: float = ( + float(number_of_plates) * 96.0 * 250.0 + ) # loading extra as a safety factor + # CALCULATING NEEDED # OF WATER WELLS + needed_wells = round(needed_water / water_max_vol) + water_wells = [] + for i in range(needed_wells + 1): + water_wells.append(reservoir_wells[i]) + # Create lists of volumes and source that matches wells to fill + water_max_vol_list = [water_max_vol] * len(water_wells) + source_list = [source_reservoir["A1"]] * len(water_wells) + p1000.transfer( + water_max_vol_list, + source_list, + water_wells, + blowout=True, + blowout_locaiton="source", + trash=False, + ) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py index 18aee383ace..937c9f4dafd 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py @@ -12,7 +12,7 @@ requirements = { "robotType": "Flex", - "apiLevel": "2.20", + "apiLevel": "2.21", } @@ -27,7 +27,7 @@ def run(protocol: protocol_api.ProtocolContext) -> None: reservoir_1 = protocol.load_labware( "nest_96_wellplate_2ml_deep", "D2", "Reservoir 1" ) # Reservoir - reservoir_2 = protocol.load_labware( + sample_plate_2 = protocol.load_labware( "thermoscientificnunc_96_wellplate_1300ul", "D3", "Sample Plate 2" ) # Reservoir sample_plate_1 = protocol.load_labware( @@ -57,10 +57,10 @@ def run(protocol: protocol_api.ProtocolContext) -> None: volume=[120, 750, 900, 96], source=source_reservoir["A1"], dest=[ - reservoir_1["A1"].top(), - reservoir_1["A2"].top(), - reservoir_1["A4"].top(), - reservoir_1["A5"].top(), + reservoir_1["A1"].top(), # AMPure + reservoir_1["A2"].top(), # SMB + reservoir_1["A4"].top(), # EtOH + reservoir_1["A5"].top(), # RSB ], blow_out=True, blowout_location="source well", @@ -68,10 +68,10 @@ def run(protocol: protocol_api.ProtocolContext) -> None: ) # Reservoir 2 Plate Prep: dispense liquid into columns 1-9 total 3690 ul - reservoir_2_wells = reservoir_2.wells() + reservoir_2_wells = sample_plate_1.wells() list_of_locations = [well_location.top() for well_location in reservoir_2_wells] p1000.transfer( - volume=[50, 50, 50, 50, 50, 50, 330, 330, 330, 800, 800, 800], + volume=[150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150], source=source_reservoir["A1"], dest=list_of_locations, blow_out=True, @@ -80,9 +80,14 @@ def run(protocol: protocol_api.ProtocolContext) -> None: ) # Sample Plate Prep: total 303 - dest_list = [sample_plate_1["A1"], sample_plate_1["A2"], sample_plate_1["A3"]] + dest_list = [ + sample_plate_2["A9"], + sample_plate_2["A10"], + sample_plate_2["A11"], + sample_plate_2["A12"], + ] p1000.transfer( - volume=[101, 101, 101], + volume=[1000, 1000, 1000, 1000], source=source_reservoir["A1"], dest=dest_list, blow_out=True, diff --git a/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py index cd263318442..e7a726b6b46 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py @@ -5,14 +5,14 @@ ) metadata = { - "protocolName": "DVT2ABR5 and 6 Liquids: 96ch Complex Protocol", + "protocolName": "DVT2ABR5 Liquids: 96ch Complex Protocol", "author": "Rhyann clarke ", "source": "Protocol Library", } requirements = { "robotType": "Flex", - "apiLevel": "2.16", + "apiLevel": "2.21", } @@ -29,7 +29,7 @@ def run(protocol: protocol_api.ProtocolContext) -> None: "nest_96_wellplate_2ml_deep", "D2", "Reservoir" ) # Reservoir - vol = 500 + vol = 1000 column_list = [ "A1", @@ -45,9 +45,9 @@ def run(protocol: protocol_api.ProtocolContext) -> None: "A11", "A12", ] + p1000.pick_up_tip() for i in column_list: - p1000.pick_up_tip() p1000.aspirate(vol, source_reservoir["A1"].bottom(z=0.5)) p1000.dispense(vol, reservoir[i].top()) p1000.blow_out(location=source_reservoir["A1"].top()) - p1000.return_tip() + p1000.return_tip() diff --git a/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py index 4addbd5c7e8..309f9916d03 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py @@ -13,7 +13,7 @@ requirements = { "robotType": "Flex", - "apiLevel": "2.16", + "apiLevel": "2.21", } @@ -55,9 +55,22 @@ def run(protocol: protocol_api.ProtocolContext) -> None: # Sample Plate p1000.transfer( - volume=180, + volume=200, source=source_reservoir["A1"].bottom(z=0.5), - dest=sample_plate["A1"].top(), + dest=[ + sample_plate["A1"].top(), + sample_plate["A2"].top(), + sample_plate["A3"].top(), + sample_plate["A4"].top(), + sample_plate["A5"].top(), + sample_plate["A6"].top(), + sample_plate["A7"].top(), + sample_plate["A8"].top(), + sample_plate["A9"].top(), + sample_plate["A10"].top(), + sample_plate["A11"].top(), + sample_plate["A12"].top(), + ], blowout=True, blowout_location="source well", trash=False, @@ -66,7 +79,20 @@ def run(protocol: protocol_api.ProtocolContext) -> None: p1000.transfer( volume=100, source=source_reservoir["A1"].bottom(z=0.5), - dest=elution_plate["A1"].top(), + dest=[ + elution_plate["A1"].top(), + elution_plate["A2"].top(), + elution_plate["A3"].top(), + elution_plate["A4"].top(), + elution_plate["A5"].top(), + elution_plate["A6"].top(), + elution_plate["A7"].top(), + elution_plate["A8"].top(), + elution_plate["A9"].top(), + elution_plate["A10"].top(), + elution_plate["A11"].top(), + elution_plate["A12"].top(), + ], blowout=True, blowout_location="source well", trash=False, diff --git a/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py index c6ded28719d..e935063ed16 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py @@ -13,7 +13,7 @@ requirements = { "robotType": "Flex", - "apiLevel": "2.16", + "apiLevel": "2.21", } @@ -34,15 +34,28 @@ def run(protocol: protocol_api.ProtocolContext) -> None: ) # Volumes + lysis = 8120 / 8 + stop_reaction_vol = 6400 / 8 elution_vol = 55 - well1 = 8120 / 8 - well2 = 6400 / 8 - well3_7 = 8550 / 8 + well4_12 = 9500 / 8 sample_vol = 100 # Reservoir p1000.transfer( - volume=[well1, well2, well3_7, well3_7, well3_7, well3_7, well3_7], + volume=[ + lysis, + lysis, + stop_reaction_vol, + well4_12, + well4_12, + well4_12, + well4_12, + well4_12, + well4_12, + well4_12, + well4_12, + well4_12, + ], source=source_reservoir["A1"].bottom(z=0.2), dest=[ res1["A1"].top(), @@ -52,6 +65,11 @@ def run(protocol: protocol_api.ProtocolContext) -> None: res1["A5"].top(), res1["A6"].top(), res1["A7"].top(), + res1["A8"].top(), + res1["A9"].top(), + res1["A10"].top(), + res1["A11"].top(), + res1["A12"].top(), ], blow_out=True, blowout_location="source well", @@ -94,7 +112,20 @@ def run(protocol: protocol_api.ProtocolContext) -> None: ) # Sample Plate p1000.transfer( - volume=[sample_vol, sample_vol, sample_vol, sample_vol, sample_vol, sample_vol], + volume=[ + sample_vol, + sample_vol, + sample_vol, + sample_vol, + sample_vol, + sample_vol, + sample_vol, + sample_vol, + sample_vol, + sample_vol, + sample_vol, + sample_vol, + ], source=source_reservoir["A1"].bottom(z=0.2), dest=[ sample_plate["A1"].top(), @@ -103,6 +134,12 @@ def run(protocol: protocol_api.ProtocolContext) -> None: sample_plate["A4"].top(), sample_plate["A5"].top(), sample_plate["A6"].top(), + sample_plate["A7"].top(), + sample_plate["A8"].top(), + sample_plate["A9"].top(), + sample_plate["A10"].top(), + sample_plate["A11"].top(), + sample_plate["A12"].top(), ], blow_out=True, blowout_location="source well", diff --git a/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py index df85453ff28..254a1b05514 100644 --- a/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py +++ b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py @@ -23,8 +23,8 @@ def add_parameters(parameters: ParameterContext) -> None: default=5, ) parameters.add_float( - variable_name="x_offset", - display_name="X Offset", + variable_name="offset", + display_name="Z Offset", choices=[ {"display_name": "0.0", "value": 0.0}, {"display_name": "0.1", "value": 0.1}, @@ -62,10 +62,10 @@ def run(protocol: ProtocolContext) -> None: """Runs protocol that moves lids and stacks them.""" # Load Parameters lids_in_stack = protocol.params.lids_in_a_stack # type: ignore[attr-defined] - x_offset = protocol.params.x_offset # type: ignore[attr-defined] + offset = protocol.params.offset # type: ignore[attr-defined] negative = protocol.params.negative # type: ignore[attr-defined] if negative: - x_offset = x_offset * -1 + offset = offset * -1 # Thermocycler thermocycler: ThermocyclerContext = protocol.load_module( "thermocyclerModuleV2" @@ -81,16 +81,16 @@ def run(protocol: ProtocolContext) -> None: lid_stack_4 = helpers.load_disposable_lids(protocol, lids_in_stack, ["C3"]) lid_stack_5 = helpers.load_disposable_lids(protocol, lids_in_stack, ["B3"]) - drop_offset = {"x": x_offset, "y": 0, "z": 0} + pickup_offset = {"x": 0, "y": 0, "z": offset} slot = 0 lids = [lid_stack_1, lid_stack_2, lid_stack_3, lid_stack_4, lid_stack_5] for lid_list in lids: lid_to_move = lid_list[0] lid_to_move_back_to = lid_list[1] - protocol.comment(f"Offset {x_offset}, Lid # {slot+1}") + protocol.comment(f"Offset {offset}, Lid # {slot+1}") # move lid to plate in thermocycler protocol.move_labware( - lid_to_move, plate_in_cycler, use_gripper=True, drop_offset=drop_offset + lid_to_move, plate_in_cycler, use_gripper=True, pick_up_offset=pickup_offset ) protocol.move_labware(lid_to_move, lid_to_move_back_to, use_gripper=True) diff --git a/abr-testing/abr_testing/tools/abr_scale.py b/abr-testing/abr_testing/tools/abr_scale.py index a35fee93fbf..e91abf114b2 100644 --- a/abr-testing/abr_testing/tools/abr_scale.py +++ b/abr-testing/abr_testing/tools/abr_scale.py @@ -149,14 +149,11 @@ def get_most_recent_run_and_record( headers, runs_and_lpc, headers_lpc, - list_of_heights, ) = abr_google_drive.create_data_dictionary( most_recent_run_id, storage_directory, "", - labware, - accuracy, - hellma_plate_standards=hellma_file_values, + hellma_file_values, ) google_sheet_abr_data = google_sheets_tool.google_sheet( credentials_path, "ABR-run-data", tab_number=0 @@ -164,15 +161,6 @@ def get_most_recent_run_and_record( start_row = google_sheet_abr_data.get_index_row() + 1 google_sheet_abr_data.batch_update_cells(runs_and_robots, "A", start_row, "0") print("Wrote run to ABR-run-data") - # Add liquid height detection to abr sheet - google_sheet_ldf = google_sheets_tool.google_sheet( - credentials_path, "ABR-run-data", 4 - ) - start_row_lhd = google_sheet_ldf.get_index_row() + 1 - google_sheet_ldf.batch_update_cells( - list_of_heights, "A", start_row_lhd, "1795535088" - ) - print("Wrote found liquid heights to ABR-run-data") # Add LPC to google sheet google_sheet_lpc = google_sheets_tool.google_sheet( credentials_path, "ABR-LPC", tab_number=0 diff --git a/abr-testing/abr_testing/tools/abr_setup.py b/abr-testing/abr_testing/tools/abr_setup.py index 224ba5bf120..a084c54c4f9 100644 --- a/abr-testing/abr_testing/tools/abr_setup.py +++ b/abr-testing/abr_testing/tools/abr_setup.py @@ -42,7 +42,9 @@ def clean_sheet(sheet_name: str, credentials: str) -> Any: # Check if the date is older than the cutoff if formatted_date < cutoff_date: rem_rows.append(row_id) - if len(rem_rows) > 2000: + + # Limit rem_rows to 1500 at a time + if len(rem_rows) >= 1500: break if len(rem_rows) == 0: # No more rows to remove @@ -53,9 +55,7 @@ def clean_sheet(sheet_name: str, credentials: str) -> Any: sheet.batch_delete_rows(rem_rows) print("deleted rows") except Exception: - print("could not delete rows") - traceback.print_exc() - sys.exit(1) + return clean_sheet(sheet_name, credentials) From 77a6ab529e273233611e81d0c94887f531c7ca9c Mon Sep 17 00:00:00 2001 From: koji Date: Wed, 18 Dec 2024 11:38:49 -0500 Subject: [PATCH 28/42] fix(protocol-designer): unify navigation bar of pd (#17128) * fix(protocol-designer): unify navigation bar of pd --- protocol-designer/src/NavigationBar.tsx | 95 ------------------- protocol-designer/src/ProtocolRoutes.tsx | 22 +++-- protocol-designer/src/atoms/constants.ts | 20 ++++ .../__tests__/LiquidButton.test.tsx | 2 +- .../LiquidButton/index.tsx} | 0 protocol-designer/src/molecules/index.ts | 2 +- .../organisms/AssignLiquidsModal/index.tsx | 4 +- .../__tests__/DesignerNavigation.test.tsx} | 19 ++-- .../index.tsx | 36 ++++--- .../Navigation/__tests__/Navigation.test.tsx} | 24 ++--- .../src/organisms/Navigation/index.tsx | 91 ++++++++++++++++++ .../__tests__/SettingsIcon.test.tsx | 1 + .../SettingsIcon/index.tsx | 52 ++++++++-- protocol-designer/src/organisms/index.ts | 4 +- .../Designer/DeckSetup/DeckSetupTools.tsx | 11 +-- .../StepForm/StepFormToolbox.tsx | 10 +- .../Timeline/TimelineToolbox.tsx | 5 +- .../src/pages/Designer/index.tsx | 4 +- .../pages/Liquids/__tests__/Liquids.test.tsx | 8 +- protocol-designer/src/pages/Liquids/index.tsx | 7 +- protocol-designer/src/pages/index.ts | 6 ++ 21 files changed, 245 insertions(+), 178 deletions(-) delete mode 100644 protocol-designer/src/NavigationBar.tsx rename protocol-designer/src/{organisms/ProtocolNavBar => molecules/LiquidButton}/__tests__/LiquidButton.test.tsx (94%) rename protocol-designer/src/{organisms/ProtocolNavBar/LiquidButton.tsx => molecules/LiquidButton/index.tsx} (100%) rename protocol-designer/src/organisms/{ProtocolNavBar/__tests__/ProtocolNavBar.test.tsx => DesignerNavigation/__tests__/DesignerNavigation.test.tsx} (84%) rename protocol-designer/src/organisms/{ProtocolNavBar => DesignerNavigation}/index.tsx (82%) rename protocol-designer/src/{__tests__/NavigationBar.test.tsx => organisms/Navigation/__tests__/Navigation.test.tsx} (66%) create mode 100644 protocol-designer/src/organisms/Navigation/index.tsx rename protocol-designer/src/{molecules => organisms}/SettingsIcon/__tests__/SettingsIcon.test.tsx (99%) rename protocol-designer/src/{molecules => organisms}/SettingsIcon/index.tsx (54%) create mode 100644 protocol-designer/src/pages/index.ts diff --git a/protocol-designer/src/NavigationBar.tsx b/protocol-designer/src/NavigationBar.tsx deleted file mode 100644 index 7ac392f2b4b..00000000000 --- a/protocol-designer/src/NavigationBar.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import type * as React from 'react' -import { useLocation, useNavigate } from 'react-router-dom' -import styled from 'styled-components' -import { useDispatch, useSelector } from 'react-redux' -import { useTranslation } from 'react-i18next' - -import { - ALIGN_CENTER, - Btn, - COLORS, - CURSOR_POINTER, - DIRECTION_COLUMN, - Flex, - JUSTIFY_SPACE_BETWEEN, - SPACING, - StyledText, -} from '@opentrons/components' -import { toggleNewProtocolModal } from './navigation/actions' -import { actions as loadFileActions } from './load-file' -import { BUTTON_LINK_STYLE } from './atoms' -import { getHasUnsavedChanges } from './load-file/selectors' -import { SettingsIcon } from './molecules' -import type { ThunkDispatch } from './types' - -export function NavigationBar(): JSX.Element | null { - const { t } = useTranslation(['shared', 'alert']) - const location = useLocation() - const navigate = useNavigate() - const dispatch: ThunkDispatch = useDispatch() - const loadFile = ( - fileChangeEvent: React.ChangeEvent - ): void => { - dispatch(loadFileActions.loadProtocolFile(fileChangeEvent)) - dispatch(toggleNewProtocolModal(false)) - } - const hasUnsavedChanges = useSelector(getHasUnsavedChanges) - - const handleCreateNew = (): void => { - if ( - !hasUnsavedChanges || - window.confirm(t('alert:confirm_create_new') as string) - ) { - dispatch(toggleNewProtocolModal(true)) - navigate('/createNew') - } - } - - return location.pathname === '/designer' || - location.pathname === '/liquids' ? null : ( - - - - - {t('opentrons')} - - - {t('protocol_designer')} - - - {t('version', { version: process.env.OT_PD_VERSION })} - - - - {location.pathname === '/createNew' ? null : ( - - - {t('create_new')} - - - )} - - - - {t('import')} - - - - - {location.pathname === '/createNew' ? null : } - - - - ) -} - -const StyledLabel = styled.label` - height: 20px; - cursor: ${CURSOR_POINTER}; - input[type='file'] { - display: none; - } -` diff --git a/protocol-designer/src/ProtocolRoutes.tsx b/protocol-designer/src/ProtocolRoutes.tsx index 7350aa0a8da..4d47caca2c4 100644 --- a/protocol-designer/src/ProtocolRoutes.tsx +++ b/protocol-designer/src/ProtocolRoutes.tsx @@ -1,18 +1,20 @@ import { Route, Navigate, Routes, useNavigate } from 'react-router-dom' import { ErrorBoundary } from 'react-error-boundary' import { Box } from '@opentrons/components' -import { Landing } from './pages/Landing' -import { ProtocolOverview } from './pages/ProtocolOverview' -import { Liquids } from './pages/Liquids' -import { Designer } from './pages/Designer' -import { CreateNewProtocolWizard } from './pages/CreateNewProtocolWizard' -import { NavigationBar } from './NavigationBar' -import { Settings } from './pages/Settings' import { - Kitchen, + CreateNewProtocolWizard, + Designer, + Landing, + Liquids, + ProtocolOverview, + Settings, +} from './pages' +import { FileUploadMessagesModal, - LabwareUploadModal, GateModal, + Kitchen, + LabwareUploadModal, + Navigation, } from './organisms' import { ProtocolDesignerAppFallback } from './resources/ProtocolDesignerAppFallback' @@ -72,7 +74,7 @@ export function ProtocolRoutes(): JSX.Element { FallbackComponent={ProtocolDesignerAppFallback} onReset={handleReset} > - + {showGateModal ? : null} diff --git a/protocol-designer/src/atoms/constants.ts b/protocol-designer/src/atoms/constants.ts index 620a3d10dbc..67393baafd9 100644 --- a/protocol-designer/src/atoms/constants.ts +++ b/protocol-designer/src/atoms/constants.ts @@ -13,6 +13,24 @@ export const BUTTON_LINK_STYLE = css` } ` +export const LINK_BUTTON_STYLE = css` + color: ${COLORS.black90}; + + &:hover { + color: ${COLORS.blue50}; + } + + &:focus-visible { + color: ${COLORS.blue50}; + outline: 2px solid ${COLORS.blue50}; + outline-offset: 0.25rem; + } + + &:disabled { + color: ${COLORS.grey40}; + } +` + export const LINE_CLAMP_TEXT_STYLE = ( lineClamp: number ): FlattenSimpleInterpolation => css` @@ -32,3 +50,5 @@ export const COLUMN_STYLE = css` min-width: calc((${MIN_OVERVIEW_WIDTH} - ${COLUMN_GRID_GAP}) * 0.5); flex: 1; ` + +export const NAV_BAR_HEIGHT_REM = 4 diff --git a/protocol-designer/src/organisms/ProtocolNavBar/__tests__/LiquidButton.test.tsx b/protocol-designer/src/molecules/LiquidButton/__tests__/LiquidButton.test.tsx similarity index 94% rename from protocol-designer/src/organisms/ProtocolNavBar/__tests__/LiquidButton.test.tsx rename to protocol-designer/src/molecules/LiquidButton/__tests__/LiquidButton.test.tsx index 179d512f262..08bd1962583 100644 --- a/protocol-designer/src/organisms/ProtocolNavBar/__tests__/LiquidButton.test.tsx +++ b/protocol-designer/src/molecules/LiquidButton/__tests__/LiquidButton.test.tsx @@ -3,7 +3,7 @@ import { fireEvent, screen } from '@testing-library/react' import { i18n } from '../../../assets/localization' import { renderWithProviders } from '../../../__testing-utils__' -import { LiquidButton } from '../LiquidButton' +import { LiquidButton } from '../../../molecules/LiquidButton' import type { ComponentProps } from 'react' diff --git a/protocol-designer/src/organisms/ProtocolNavBar/LiquidButton.tsx b/protocol-designer/src/molecules/LiquidButton/index.tsx similarity index 100% rename from protocol-designer/src/organisms/ProtocolNavBar/LiquidButton.tsx rename to protocol-designer/src/molecules/LiquidButton/index.tsx diff --git a/protocol-designer/src/molecules/index.ts b/protocol-designer/src/molecules/index.ts index 1c0f2bbb67f..8a65e96180b 100644 --- a/protocol-designer/src/molecules/index.ts +++ b/protocol-designer/src/molecules/index.ts @@ -2,6 +2,6 @@ export * from './CheckboxExpandStepFormField' export * from './CheckboxStepFormField' export * from './DropdownStepFormField' export * from './InputStepFormField' -export * from './SettingsIcon' +export * from './LiquidButton' export * from './ToggleExpandStepFormField' export * from './ToggleStepFormField' diff --git a/protocol-designer/src/organisms/AssignLiquidsModal/index.tsx b/protocol-designer/src/organisms/AssignLiquidsModal/index.tsx index a7c891e7c3c..8372c5886fc 100644 --- a/protocol-designer/src/organisms/AssignLiquidsModal/index.tsx +++ b/protocol-designer/src/organisms/AssignLiquidsModal/index.tsx @@ -21,7 +21,7 @@ import { getSelectedWells } from '../../well-selection/selectors' import { SelectableLabware } from '../Labware/SelectableLabware' import { wellFillFromWellContents } from '../LabwareOnDeck/utils' import { deselectWells, selectWells } from '../../well-selection/actions' -import { PROTOCOL_NAV_BAR_HEIGHT_REM } from '../ProtocolNavBar' +import { NAV_BAR_HEIGHT_REM } from '../../atoms' import { LiquidToolbox } from './LiquidToolbox' import type { WellGroup } from '@opentrons/components' @@ -52,7 +52,7 @@ export function AssignLiquidsModal(): JSX.Element | null { return ( { @@ -21,17 +21,22 @@ vi.mock('react-router-dom', async importOriginal => { return { ...reactRouterDom, useNavigate: () => mockNavigate, + useLocation: () => ({ + location: { + pathname: '/designer', + }, + }), } }) -const render = (props: ComponentProps) => { - return renderWithProviders(, { +const render = (props: ComponentProps) => { + return renderWithProviders(, { i18nInstance: i18n, }) } -describe('ProtocolNavBar', () => { - let props: ComponentProps +describe('DesignerNavigation', () => { + let props: ComponentProps beforeEach(() => { props = { hasZoomInSlot: false, diff --git a/protocol-designer/src/organisms/ProtocolNavBar/index.tsx b/protocol-designer/src/organisms/DesignerNavigation/index.tsx similarity index 82% rename from protocol-designer/src/organisms/ProtocolNavBar/index.tsx rename to protocol-designer/src/organisms/DesignerNavigation/index.tsx index fc9d5bff942..ce0e7a9b3ff 100644 --- a/protocol-designer/src/organisms/ProtocolNavBar/index.tsx +++ b/protocol-designer/src/organisms/DesignerNavigation/index.tsx @@ -1,6 +1,6 @@ import { useDispatch, useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' -import { useNavigate } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import styled from 'styled-components' import { @@ -18,41 +18,39 @@ import { } from '@opentrons/components' import { getFileMetadata } from '../../file-data/selectors' import { selectTerminalItem } from '../../ui/steps/actions/actions' -import { LINE_CLAMP_TEXT_STYLE } from '../../atoms' +import { LINE_CLAMP_TEXT_STYLE, NAV_BAR_HEIGHT_REM } from '../../atoms' import { useKitchen } from '../Kitchen/hooks' -import { LiquidButton } from './LiquidButton' +import { LiquidButton } from '../../molecules/LiquidButton' import type { StyleProps, TabProps } from '@opentrons/components' -export const PROTOCOL_NAV_BAR_HEIGHT_REM = 4 - -interface ProtocolNavBarProps { +interface DesignerNavigationProps { hasZoomInSlot?: boolean tabs?: TabProps[] hasTrashEntity?: boolean showLiquidOverflowMenu?: (liquidOverflowMenu: boolean) => void - liquidPage?: boolean } - -export function ProtocolNavBar({ +// Note: this navigation is used in design page and liquids page +export function DesignerNavigation({ hasZoomInSlot, tabs = [], hasTrashEntity, showLiquidOverflowMenu, - liquidPage = false, -}: ProtocolNavBarProps): JSX.Element { +}: DesignerNavigationProps): JSX.Element { const { t } = useTranslation('starting_deck_state') + const location = useLocation() const metadata = useSelector(getFileMetadata) const { makeSnackbar } = useKitchen() const navigate = useNavigate() const dispatch = useDispatch() + const isLiquidsPage = location.pathname === '/liquids' - const showProtocolEditButtons = !(hasZoomInSlot || liquidPage) + const showProtocolEditButtons = !(hasZoomInSlot === true || isLiquidsPage) let metadataText = t('edit_protocol') - if (liquidPage) { + if (isLiquidsPage) { metadataText = t('add_liquid') - } else if (hasZoomInSlot) { + } else if (hasZoomInSlot === true) { metadataText = t('add_hardware_labware') } return ( @@ -78,10 +76,10 @@ export function ProtocolNavBar({ ) : null} - {liquidPage ? null : ( + {isLiquidsPage ? null : ( { - if (hasTrashEntity) { + if (hasTrashEntity === true) { navigate('/overview') dispatch(selectTerminalItem('__initial_setup__')) } else { @@ -100,12 +98,12 @@ export function ProtocolNavBar({ const NavContainer = styled(Flex)<{ showShadow: boolean }>` z-index: ${props => (props.showShadow === true ? 11 : 0)}; padding: ${SPACING.spacing12}; - height: ${PROTOCOL_NAV_BAR_HEIGHT_REM}rem; + height: ${NAV_BAR_HEIGHT_REM}rem; width: 100%; justify-content: ${JUSTIFY_SPACE_BETWEEN}; align-items: ${ALIGN_CENTER}; box-shadow: ${props => - props.showShadow + props.showShadow === true ? `0px 1px 3px 0px ${COLORS.black90}${COLORS.opacity20HexCode}` : 'none'}; ` @@ -119,7 +117,7 @@ const MetadataContainer = styled.div.withConfig({ display: flex; flex-direction: ${DIRECTION_COLUMN}; text-align: ${props => - props.showProtocolEditButtons === true + props.showProtocolEditButtons ? TYPOGRAPHY.textAlignCenter : TYPOGRAPHY.textAlignLeft}; diff --git a/protocol-designer/src/__tests__/NavigationBar.test.tsx b/protocol-designer/src/organisms/Navigation/__tests__/Navigation.test.tsx similarity index 66% rename from protocol-designer/src/__tests__/NavigationBar.test.tsx rename to protocol-designer/src/organisms/Navigation/__tests__/Navigation.test.tsx index deac271d6d5..90d0fe4b917 100644 --- a/protocol-designer/src/__tests__/NavigationBar.test.tsx +++ b/protocol-designer/src/organisms/Navigation/__tests__/Navigation.test.tsx @@ -2,27 +2,27 @@ import { describe, it, vi, beforeEach, expect } from 'vitest' import { fireEvent, screen } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom' -import { i18n } from '../assets/localization' -import { renderWithProviders } from '../__testing-utils__' -import { NavigationBar } from '../NavigationBar' -import { getHasUnsavedChanges } from '../load-file/selectors' -import { toggleNewProtocolModal } from '../navigation/actions' -import { SettingsIcon } from '../molecules' +import { i18n } from '../../../assets/localization' +import { renderWithProviders } from '../../../__testing-utils__' +import { getHasUnsavedChanges } from '../../../load-file/selectors' +import { toggleNewProtocolModal } from '../../../navigation/actions' +import { SettingsIcon } from '../../SettingsIcon' +import { Navigation } from '..' -vi.mock('../molecules') -vi.mock('../navigation/actions') -vi.mock('../file-data/selectors') -vi.mock('../load-file/selectors') +vi.mock('../../SettingsIcon') +vi.mock('../../../navigation/actions') +vi.mock('../../../file-data/selectors') +vi.mock('../../../load-file/selectors') const render = () => { return renderWithProviders( - + , { i18nInstance: i18n } ) } -describe('NavigationBar', () => { +describe('Navigation', () => { beforeEach(() => { vi.mocked(getHasUnsavedChanges).mockReturnValue(false) vi.mocked(SettingsIcon).mockReturnValue(
mock SettingsIcon
) diff --git a/protocol-designer/src/organisms/Navigation/index.tsx b/protocol-designer/src/organisms/Navigation/index.tsx new file mode 100644 index 00000000000..0f5b423ddc6 --- /dev/null +++ b/protocol-designer/src/organisms/Navigation/index.tsx @@ -0,0 +1,91 @@ +import { useLocation, useNavigate } from 'react-router-dom' +import styled from 'styled-components' +import { useDispatch, useSelector } from 'react-redux' +import { useTranslation } from 'react-i18next' + +import { + ALIGN_CENTER, + Btn, + COLORS, + CURSOR_POINTER, + Flex, + JUSTIFY_SPACE_BETWEEN, + SPACING, + StyledText, +} from '@opentrons/components' +import { toggleNewProtocolModal } from '../../navigation/actions' +import { actions as loadFileActions } from '../../load-file' +import { LINK_BUTTON_STYLE } from '../../atoms' +import { getHasUnsavedChanges } from '../../load-file/selectors' +import { SettingsIcon } from '../SettingsIcon' +import type { ThunkDispatch } from '../../types' + +export function Navigation(): JSX.Element | null { + const { t } = useTranslation(['shared', 'alert']) + const location = useLocation() + const navigate = useNavigate() + const dispatch: ThunkDispatch = useDispatch() + const loadFile = ( + fileChangeEvent: React.ChangeEvent + ): void => { + dispatch(loadFileActions.loadProtocolFile(fileChangeEvent)) + dispatch(toggleNewProtocolModal(false)) + } + const hasUnsavedChanges = useSelector(getHasUnsavedChanges) + + const handleCreateNew = (): void => { + if ( + !hasUnsavedChanges || + window.confirm(t('alert:confirm_create_new') as string) + ) { + dispatch(toggleNewProtocolModal(true)) + navigate('/createNew') + } + } + + return location.pathname === '/designer' || + location.pathname === '/liquids' ? null : ( + + + + {t('opentrons')} + + + {t('protocol_designer')} + + + {t('version', { version: process.env.OT_PD_VERSION })} + + + + {location.pathname === '/createNew' ? null : ( + + + {t('create_new')} + + + )} + + + + {t('import')} + + + + + {location.pathname === '/createNew' ? null : } + + + ) +} + +const StyledLabel = styled.label` + height: 1.25rem; + cursor: ${CURSOR_POINTER}; + input[type='file'] { + display: none; + } +` diff --git a/protocol-designer/src/molecules/SettingsIcon/__tests__/SettingsIcon.test.tsx b/protocol-designer/src/organisms/SettingsIcon/__tests__/SettingsIcon.test.tsx similarity index 99% rename from protocol-designer/src/molecules/SettingsIcon/__tests__/SettingsIcon.test.tsx rename to protocol-designer/src/organisms/SettingsIcon/__tests__/SettingsIcon.test.tsx index ee2258b0a7c..8c4a9e1ec2b 100644 --- a/protocol-designer/src/molecules/SettingsIcon/__tests__/SettingsIcon.test.tsx +++ b/protocol-designer/src/organisms/SettingsIcon/__tests__/SettingsIcon.test.tsx @@ -3,6 +3,7 @@ import { fireEvent, screen } from '@testing-library/react' import { renderWithProviders } from '../../../__testing-utils__' import { getFileMetadata } from '../../../file-data/selectors' import { SettingsIcon } from '..' + import type { NavigateFunction } from 'react-router-dom' const mockNavigate = vi.fn() diff --git a/protocol-designer/src/molecules/SettingsIcon/index.tsx b/protocol-designer/src/organisms/SettingsIcon/index.tsx similarity index 54% rename from protocol-designer/src/molecules/SettingsIcon/index.tsx rename to protocol-designer/src/organisms/SettingsIcon/index.tsx index 0953ce992cb..934d6371b2c 100644 --- a/protocol-designer/src/molecules/SettingsIcon/index.tsx +++ b/protocol-designer/src/organisms/SettingsIcon/index.tsx @@ -1,17 +1,18 @@ import { useSelector } from 'react-redux' import { useLocation, useNavigate } from 'react-router-dom' +import { css } from 'styled-components' + import { BORDERS, Btn, COLORS, + CURSOR_POINTER, Flex, Icon, JUSTIFY_CENTER, } from '@opentrons/components' import { getFileMetadata } from '../../file-data/selectors' -import { BUTTON_LINK_STYLE } from '../../atoms/constants' -// TODO(ja): this icon needs to be updated to match css states and correct svg export const SettingsIcon = (): JSX.Element => { const location = useLocation() const navigate = useNavigate() @@ -32,22 +33,57 @@ export const SettingsIcon = (): JSX.Element => { data-testid="SettingsIcon" borderRadius={BORDERS.borderRadiusFull} backgroundColor={ - location.pathname === '/settings' ? COLORS.grey30 : COLORS.transparent + location.pathname === '/settings' ? COLORS.grey35 : COLORS.transparent } - cursor="pointer" - width="2rem" - height="2rem" + cursor={CURSOR_POINTER} justifyContent={JUSTIFY_CENTER} > - +
) } + +const GEAR_ICON_STYLE = css` + width: 2rem; + height: 2rem; + border-radius: 50%; + color: ${COLORS.grey60}; + + &:hover { + background-color: ${COLORS.grey30}; + } + + &:active { + color: ${COLORS.grey60}; + background-color: ${COLORS.grey35}; + } + + &:focus-visible { + position: relative; + outline: none; + + /* blue ring */ + &::after { + content: ''; + position: absolute; + top: -0.5rem; + left: -0.5rem; + right: -0.5rem; + bottom: -0.5rem; + + border: 3px solid ${COLORS.blue50}; + border-radius: 50%; + pointer-events: none; + box-sizing: content-box; + } + background-color: ${COLORS.grey35}; + } +` diff --git a/protocol-designer/src/organisms/index.ts b/protocol-designer/src/organisms/index.ts index 0bf328fed4e..cbab9d62f8e 100644 --- a/protocol-designer/src/organisms/index.ts +++ b/protocol-designer/src/organisms/index.ts @@ -6,6 +6,7 @@ export * from './BlockingHintModal' export * from './ConfirmDeleteModal' export * from './ConfirmDeleteStagingAreaModal' export * from './DefineLiquidsModal' +export * from './DesignerNavigation' export * from './DisabledScreen' export * from './EditInstrumentsModal' export * from './EditNickNameModal' @@ -17,10 +18,11 @@ export * from './Kitchen' export * from './KnowledgeLink' export * from './LabwareOnDeck' export * from './LabwareUploadModal' +export * from './Navigation' export * from './PipetteInfoItem' export * from './Portal' -export * from './ProtocolNavBar' export * from './SelectWellsModal' +export * from './SettingsIcon' export * from './SlotDetailsContainer' export * from './SlotInformation' export * from './TipPositionModal' diff --git a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx index ac0f56b377e..e93ec99d887 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx @@ -52,11 +52,8 @@ import { selectors } from '../../../labware-ingred/selectors' import { useKitchen } from '../../../organisms/Kitchen/hooks' import { getDismissedHints } from '../../../tutorial/selectors' import { createContainerAboveModule } from '../../../step-forms/actions/thunks' -import { - ConfirmDeleteStagingAreaModal, - PROTOCOL_NAV_BAR_HEIGHT_REM, -} from '../../../organisms' -import { BUTTON_LINK_STYLE } from '../../../atoms' +import { BUTTON_LINK_STYLE, NAV_BAR_HEIGHT_REM } from '../../../atoms' +import { ConfirmDeleteStagingAreaModal } from '../../../organisms' import { getSlotInformation } from '../utils' import { ALL_ORDERED_CATEGORIES, FIXTURES, MOAM_MODELS } from './constants' import { LabwareTools } from './LabwareTools' @@ -371,7 +368,7 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null { position === POSITION_FIXED ? { right: SPACING.spacing12, - top: `calc(${PROTOCOL_NAV_BAR_HEIGHT_REM}rem + ${SPACING.spacing12})`, + top: `calc(${NAV_BAR_HEIGHT_REM}rem + ${SPACING.spacing12})`, } : {} return ( @@ -398,7 +395,7 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null { ) : null} {changeModuleWarning} { diff --git a/protocol-designer/src/pages/Designer/index.tsx b/protocol-designer/src/pages/Designer/index.tsx index f9f343735d4..410faa44739 100644 --- a/protocol-designer/src/pages/Designer/index.tsx +++ b/protocol-designer/src/pages/Designer/index.tsx @@ -17,7 +17,7 @@ import { selectTerminalItem } from '../../ui/steps/actions/actions' import { useKitchen } from '../../organisms/Kitchen/hooks' import { getDeckSetupForActiveItem } from '../../top-selectors/labware-locations' import { generateNewProtocol } from '../../labware-ingred/actions' -import { DefineLiquidsModal, ProtocolNavBar } from '../../organisms' +import { DefineLiquidsModal, DesignerNavigation } from '../../organisms' import { selectDesignerTab } from '../../file-data/actions' import { getDesignerTab, getFileMetadata } from '../../file-data/selectors' import { DeckSetupContainer } from './DeckSetup' @@ -151,7 +151,7 @@ export function Designer(): JSX.Element { /> ) : null} - { vi.mocked(AssignLiquidsModal).mockReturnValue(
mock AssignLiquidsModal
) - vi.mocked(ProtocolNavBar).mockReturnValue(
mock ProtocolNavBar
) + vi.mocked(DesignerNavigation).mockReturnValue( +
mock DesignerNavigation
+ ) vi.mocked(LiquidsOverflowMenu).mockReturnValue(
mock LiquidsOverflowMenu
) @@ -55,7 +57,7 @@ describe('Liquids', () => { it('renders nav and assign liquids modal', () => { render() - screen.getByText('mock ProtocolNavBar') + screen.getByText('mock DesignerNavigation') screen.getByText('mock AssignLiquidsModal') }) }) diff --git a/protocol-designer/src/pages/Liquids/index.tsx b/protocol-designer/src/pages/Liquids/index.tsx index c8382498863..3604f9e3d24 100644 --- a/protocol-designer/src/pages/Liquids/index.tsx +++ b/protocol-designer/src/pages/Liquids/index.tsx @@ -9,7 +9,7 @@ import { import { AssignLiquidsModal, DefineLiquidsModal, - ProtocolNavBar, + DesignerNavigation, } from '../../organisms' import { selectors as labwareIngredSelectors } from '../../labware-ingred/selectors' import { LiquidsOverflowMenu } from '../Designer/LiquidsOverflowMenu' @@ -59,10 +59,7 @@ export function Liquids(): JSX.Element { ) : null} - + diff --git a/protocol-designer/src/pages/index.ts b/protocol-designer/src/pages/index.ts new file mode 100644 index 00000000000..c80a9b799ce --- /dev/null +++ b/protocol-designer/src/pages/index.ts @@ -0,0 +1,6 @@ +export * from './CreateNewProtocolWizard' +export * from './Designer' +export * from './Landing' +export * from './Liquids' +export * from './ProtocolOverview/' +export * from './Settings' From 9f0bc7d3efd5cc6ac03807a3ef9b637213a0a16d Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Wed, 18 Dec 2024 12:17:11 -0500 Subject: [PATCH 29/42] fix(protocol-designer): remove console log (#17139) remove console log --- .../src/pages/ProtocolOverview/LiquidDefinitions.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/protocol-designer/src/pages/ProtocolOverview/LiquidDefinitions.tsx b/protocol-designer/src/pages/ProtocolOverview/LiquidDefinitions.tsx index e9da36c4bae..b55b615eb11 100644 --- a/protocol-designer/src/pages/ProtocolOverview/LiquidDefinitions.tsx +++ b/protocol-designer/src/pages/ProtocolOverview/LiquidDefinitions.tsx @@ -65,7 +65,6 @@ export function LiquidDefinitions({ {Object.keys(allIngredientGroupFields).length > 0 ? ( Object.values(allIngredientGroupFields).map((liquid, index) => { - console.log(getLiquidDescription(liquid, enableLiquidClasses)) return ( Date: Wed, 18 Dec 2024 13:13:34 -0500 Subject: [PATCH 30/42] Abr lengthen protocols (#17140) # Overview This pr adds back in the changes made in the 'ABR10/ABR6 fixes' commit. For some reason after pushing the fix to the abr-setup script, those updates were disregarded. --------- Co-authored-by: rclarke0 Co-authored-by: Rhyann Clarke <146747548+rclarke0@users.noreply.github.com> --- .../data_collection/read_robot_logs.py | 5 +- .../10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py | 5 +- .../6_Omega_HDQ_DNA_Cells-Flex_96_channel.py | 88 +++++++++-------- .../10_ZymoBIOMICS Magbead Liquid Setup.py | 3 +- .../test_protocols/tc_lid_x_offset_test.py | 97 ++++++++++++------- abr-testing/abr_testing/tools/abr_setup.py | 6 +- 6 files changed, 121 insertions(+), 83 deletions(-) diff --git a/abr-testing/abr_testing/data_collection/read_robot_logs.py b/abr-testing/abr_testing/data_collection/read_robot_logs.py index 0a098835cf7..d4570d20110 100644 --- a/abr-testing/abr_testing/data_collection/read_robot_logs.py +++ b/abr-testing/abr_testing/data_collection/read_robot_logs.py @@ -239,7 +239,10 @@ def get_liquid_waste_height(file_results: Dict[str, Any]) -> float: result_str = get_comment_result_by_string( file_results, "Liquid Waste Total Height: " ) - height = float(result_str) + try: + height = float(result_str) + except ValueError: + height = 0.0 return height diff --git a/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py b/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py index 9e93e597bbd..fbc77c9ed46 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py +++ b/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py @@ -165,7 +165,7 @@ def tipcheck(m1000: InstrumentContext) -> None: "Lysis and PK": [{"well": lysis_, "volume": 12320.0}], "Beads and Binding": [{"well": binding_buffer, "volume": 11875.0}], "Binding 2": [{"well": bind2_res, "volume": 13500.0}], - "Final Elution": [{"well": elution_solution, "volume": 1200.0}], + "Final Elution": [{"well": elution_solution, "volume": 7500.0}], "Samples": [{"well": samps, "volume": 0.0}], "Reagents": [{"well": all_washes, "volume": 9800.0}], } @@ -489,9 +489,8 @@ def elute(vol: float) -> None: m1000.aspirate(vol, elution_solution) m1000.air_gap(20) m1000.dispense(m1000.current_volume, m.top(-3)) - total_elution_vol += vol + total_elution_vol += vol * 8 m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - helpers.set_hs_speed(protocol, h_s, heater_shaker_speed * 0.9, wash_time, True) # Transfer back to magnet diff --git a/abr-testing/abr_testing/protocols/active_protocols/6_Omega_HDQ_DNA_Cells-Flex_96_channel.py b/abr-testing/abr_testing/protocols/active_protocols/6_Omega_HDQ_DNA_Cells-Flex_96_channel.py index cc2103d2555..894f80dcdea 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/6_Omega_HDQ_DNA_Cells-Flex_96_channel.py +++ b/abr-testing/abr_testing/protocols/active_protocols/6_Omega_HDQ_DNA_Cells-Flex_96_channel.py @@ -35,16 +35,16 @@ def add_parameters(parameters: ParameterContext) -> None: display_name="Number of Runs", default=2, minimum=1, - maximum=10, + maximum=4, ) # Start protocol -def run(ctx: ProtocolContext) -> None: +def run(protocol: ProtocolContext) -> None: """Protocol.""" - dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] - deactivate_modules = ctx.params.deactivate_modules # type: ignore[attr-defined] - number_of_runs = ctx.params.number_of_runs # type: ignore[attr-defined] + dot_bottom = protocol.params.dot_bottom # type: ignore[attr-defined] + deactivate_modules = protocol.params.deactivate_modules # type: ignore[attr-defined] + number_of_runs = protocol.params.number_of_runs # type: ignore[attr-defined] dry_run = False tip_mixing = False @@ -53,7 +53,7 @@ def run(ctx: ProtocolContext) -> None: bind_vol = 300.0 sample_vol = 180.0 elution_vol = 100.0 - + helpers.comment_protocol_version(protocol, "01") # Same for all HDQ Extractions deepwell_type = "nest_96_wellplate_2ml_deep" if not dry_run: @@ -68,56 +68,56 @@ def run(ctx: ProtocolContext) -> None: binding_buffer_vol = bead_vol + bind_vol starting_vol = AL_total_vol + sample_vol - h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] + h_s: HeaterShakerContext = protocol.load_module( + helpers.hs_str, "D1" + ) # type: ignore[assignment] sample_plate, h_s_adapter = helpers.load_hs_adapter_and_labware( deepwell_type, h_s, "Sample Plate" ) h_s.close_labware_latch() samples_m = sample_plate.wells()[0] - # NOTE: MAG BLOCK will be on slot 6 - - temp: TemperatureModuleContext = ctx.load_module( + temp: TemperatureModuleContext = protocol.load_module( helpers.temp_str, "A3" ) # type: ignore[assignment] elutionplate, tempblock = helpers.load_temp_adapter_and_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", temp, "Elution Plate/Reservoir" ) - magblock: MagneticBlockContext = ctx.load_module( + magblock: MagneticBlockContext = protocol.load_module( "magneticBlockV1", "C1" ) # type: ignore[assignment] - liquid_waste = ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + liquid_waste = protocol.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") waste = liquid_waste.wells()[0].top() - lysis_reservoir = ctx.load_labware(deepwell_type, "D2", "Lysis reservoir") + lysis_reservoir = protocol.load_labware(deepwell_type, "D2", "Lysis reservoir") lysis_res = lysis_reservoir.wells()[0] - bind_reservoir = ctx.load_labware( + bind_reservoir = protocol.load_labware( deepwell_type, "C2", "Beads and binding reservoir" ) bind_res = bind_reservoir.wells()[0] - wash1_reservoir = ctx.load_labware(deepwell_type, "C3", "Wash 1 reservoir") + wash1_reservoir = protocol.load_labware(deepwell_type, "C3", "Wash 1 reservoir") wash1_res = wash1_reservoir.wells()[0] - wash2_reservoir = ctx.load_labware(deepwell_type, "B1", "Wash 2 reservoir") + wash2_reservoir = protocol.load_labware(deepwell_type, "B1", "Wash 2 reservoir") wash2_res = wash2_reservoir.wells()[0] elution_res = elutionplate.wells()[0] # Load Pipette and tip racks # Load tips - tiprack_1 = ctx.load_labware( + tiprack_1 = protocol.load_labware( "opentrons_flex_96_tiprack_1000ul", "A1", adapter="opentrons_flex_96_tiprack_adapter", ) tips = tiprack_1.wells()[0] - tiprack_2 = ctx.load_labware( + tiprack_2 = protocol.load_labware( "opentrons_flex_96_tiprack_1000ul", "A2", adapter="opentrons_flex_96_tiprack_adapter", ) tips1 = tiprack_2.wells()[0] # load 96 channel pipette - pip: InstrumentContext = ctx.load_instrument( + pip: InstrumentContext = protocol.load_instrument( "flex_96channel_1000", mount="left", tip_racks=[tiprack_1, tiprack_2] ) # Load Liquids and probe @@ -136,7 +136,7 @@ def run(ctx: ProtocolContext) -> None: "Samples": [{"well": sample_plate.wells(), "volume": sample_vol}], } - helpers.find_liquid_height_of_loaded_liquids(ctx, liquid_vols_and_wells, pip) + helpers.find_liquid_height_of_loaded_liquids(protocol, liquid_vols_and_wells, pip) pip.flow_rate.aspirate = 50 pip.flow_rate.dispense = 150 @@ -220,7 +220,7 @@ def bead_mix(vol: float, plate: Well, reps: int = 5) -> None: pip.flow_rate.aspirate = 150 pip.flow_rate.dispense = 200 - def protocol() -> None: + def protocol_function() -> None: # Start Protocol temp.set_temperature(inc_temp) # Transfer and mix lysis @@ -232,11 +232,11 @@ def protocol() -> None: pip.return_tip() # Mix, then heat - ctx.comment("Lysis Mixing") - helpers.set_hs_speed(ctx, h_s, 1800, 10, False) + protocol.comment("Lysis Mixing") + helpers.set_hs_speed(protocol, h_s, 1800, 10, False) if not dry_run: h_s.set_and_wait_for_temperature(55) - ctx.delay( + protocol.delay( minutes=10 if not dry_run else 0.25, msg="Please allow another 10 minutes of 55C incubation to complete lysis.", ) @@ -255,13 +255,15 @@ def protocol() -> None: pip.home() # Shake for binding incubation - ctx.comment("Binding incubation") - helpers.set_hs_speed(ctx, h_s, 1800, 10, True) + protocol.comment("Binding incubation") + helpers.set_hs_speed(protocol, h_s, 1800, 10, True) # Transfer plate to magnet - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) - ctx.delay( + protocol.delay( minutes=settling_time, msg="Please wait " + str(settling_time) + " minute(s) for beads to pellet.", ) @@ -276,7 +278,7 @@ def protocol() -> None: pip.return_tip() # Transfer plate from magnet to H/S - helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + helpers.move_labware_to_hs(protocol, sample_plate, h_s, h_s_adapter) # Washes for i in range(num_washes if not dry_run else 1): @@ -290,14 +292,14 @@ def protocol() -> None: pip.dispense(wash_vol, samples_m) if not tip_mixing: pip.return_tip() - helpers.set_hs_speed(ctx, h_s, 1800, 5, True) + helpers.set_hs_speed(protocol, h_s, 1800, 5, True) # Transfer plate to magnet helpers.move_labware_from_hs_to_destination( - ctx, sample_plate, h_s, magblock + protocol, sample_plate, h_s, magblock ) - ctx.delay( + protocol.delay( minutes=settling_time, msg="Please wait " + str(settling_time) @@ -314,7 +316,7 @@ def protocol() -> None: pip.return_tip() # Transfer plate from magnet to H/S - helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + helpers.move_labware_to_hs(protocol, sample_plate, h_s, h_s_adapter) # Dry beads if dry_run: @@ -323,7 +325,7 @@ def protocol() -> None: drybeads = 10 # Number of minutes you want to dry for for beaddry in np.arange(drybeads, 0, -0.5): - ctx.delay( + protocol.delay( minutes=0.5, msg="There are " + str(beaddry) + " minutes left in the drying step.", ) @@ -337,12 +339,14 @@ def protocol() -> None: pip.return_tip() pip.home() - helpers.set_hs_speed(ctx, h_s, 2000, 5, True) + helpers.set_hs_speed(protocol, h_s, 2000, 5, True) # Transfer plate to magnet - helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate, h_s, magblock + ) - ctx.delay( + protocol.delay( minutes=settling_time, msg="Please wait " + str(settling_time) + " minute(s) for beads to pellet.", ) @@ -364,8 +368,8 @@ def protocol() -> None: pip.aspirate(500, wash2_res) pip.dispense(500, liquid_waste["A1"].top()) pip.return_tip() - helpers.find_liquid_height_of_all_wells(ctx, pip, [liquid_waste["A1"]]) - helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + helpers.find_liquid_height_of_all_wells(protocol, pip, [liquid_waste["A1"]]) + helpers.move_labware_to_hs(protocol, sample_plate, h_s, h_s_adapter) def setup() -> None: pip.pick_up_tip() @@ -418,11 +422,13 @@ def clean() -> None: helpers.clean_up_plates(pip, plates_to_clean, liquid_waste["A1"], 1000) for i in range(number_of_runs): - protocol() + protocol_function() + pip.reset_tipracks() if i < number_of_runs - 1: setup() pip.reset_tipracks() clean() if deactivate_modules: - helpers.deactivate_modules(ctx) + helpers.deactivate_modules(protocol) + helpers.find_liquid_height_of_all_wells(protocol, pip, [liquid_waste["A1"]]) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py index 76b72b97164..7fed5d5d052 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py @@ -35,7 +35,8 @@ def run(protocol: protocol_api.ProtocolContext) -> None: binding2 = 13500 / 8 wash2 = 9800 / 8 wash2_list = [wash2] * 12 - final_elution = 1200 / 8 + final_elution = 7500 / 8 + # Fill up Plates # Res1 p1000.transfer( diff --git a/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py index 254a1b05514..9dd4ee7b578 100644 --- a/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py +++ b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py @@ -1,12 +1,9 @@ """Protocol to Test the Stacking and Movement of Tough Auto Seal Lid.""" -from opentrons.protocol_api import ( - ParameterContext, - ProtocolContext, -) +from opentrons.protocol_api import ParameterContext, ProtocolContext, Labware from opentrons.protocol_api.module_contexts import ( ThermocyclerContext, ) -from abr_testing.protocols import helpers +from typing import List metadata = {"protocolName": "5 Stack Test"} @@ -23,8 +20,8 @@ def add_parameters(parameters: ParameterContext) -> None: default=5, ) parameters.add_float( - variable_name="offset", - display_name="Z Offset", + variable_name="num_offset", + display_name="Numerical Offset", choices=[ {"display_name": "0.0", "value": 0.0}, {"display_name": "0.1", "value": 0.1}, @@ -56,41 +53,73 @@ def add_parameters(parameters: ParameterContext) -> None: description="Turn on to make offset negative.", default=False, ) + parameters.add_str( + variable_name="offset", + display_name="Offset", + choices=[ + {"display_name": "Z", "value": "Z"}, + {"display_name": "Y", "value": "Y"}, + {"display_name": "X", "value": "X"}, + ], + default="X", + ) + parameters.add_bool( + variable_name="thermocycler_bool", display_name="thermocycler", default=False + ) def run(protocol: ProtocolContext) -> None: """Runs protocol that moves lids and stacks them.""" # Load Parameters - lids_in_stack = protocol.params.lids_in_a_stack # type: ignore[attr-defined] + lids_in_stack: int = protocol.params.lids_in_a_stack # type: ignore[attr-defined] + num_offset = protocol.params.num_offset # type: ignore[attr-defined] + offset = protocol.params.offset # type: ignore[attr-defined] negative = protocol.params.negative # type: ignore[attr-defined] + thermocycler_bool = protocol.params.thermocycler_bool # type: ignore[attr-defined] if negative: - offset = offset * -1 + num_offset = num_offset * -1 + # Thermocycler - thermocycler: ThermocyclerContext = protocol.load_module( - "thermocyclerModuleV2" - ) # type: ignore[assignment] - plate_in_cycler = thermocycler.load_labware( - "armadillo_96_wellplate_200ul_pcr_full_skirt" - ) - thermocycler.open_lid() + if thermocycler_bool: + thermocycler: ThermocyclerContext = protocol.load_module( + "thermocyclerModuleV2" + ) # type: ignore[assignment] + plate_in_cycler: Labware = thermocycler.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt" + ) + thermocycler.open_lid() + else: + plate_in_cycler = protocol.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "D2" + ) # Load Lids - lid_stack_1 = helpers.load_disposable_lids(protocol, lids_in_stack, ["D2"]) - lid_stack_2 = helpers.load_disposable_lids(protocol, lids_in_stack, ["C2"]) - lid_stack_3 = helpers.load_disposable_lids(protocol, lids_in_stack, ["B2"]) - lid_stack_4 = helpers.load_disposable_lids(protocol, lids_in_stack, ["C3"]) - lid_stack_5 = helpers.load_disposable_lids(protocol, lids_in_stack, ["B3"]) - - pickup_offset = {"x": 0, "y": 0, "z": offset} + deck_riser_adapter = protocol.load_adapter("opentrons_flex_deck_riser", "D3") + unused_lids: List[Labware] = [ + deck_riser_adapter.load_labware("opentrons_tough_pcr_auto_sealing_lid") + ] + if lids_in_stack > 1: + for i in range(lids_in_stack - 1): + unused_lids.append( + unused_lids[-1].load_labware("opentrons_tough_pcr_auto_sealing_lid") + ) + unused_lids.reverse() + pick_up_offset = { + "X": {"x": num_offset, "y": 0, "z": 0}, + "Y": {"x": 0, "y": num_offset, "z": 0}, + "Z": {"x": 0, "y": 0, "z": num_offset}, + } slot = 0 - lids = [lid_stack_1, lid_stack_2, lid_stack_3, lid_stack_4, lid_stack_5] - for lid_list in lids: - lid_to_move = lid_list[0] - - lid_to_move_back_to = lid_list[1] - protocol.comment(f"Offset {offset}, Lid # {slot+1}") - # move lid to plate in thermocycler - protocol.move_labware( - lid_to_move, plate_in_cycler, use_gripper=True, pick_up_offset=pickup_offset - ) - protocol.move_labware(lid_to_move, lid_to_move_back_to, use_gripper=True) + if len(unused_lids) > 1: + lid_to_move_back_to = unused_lids[1] # stack back on top + else: + lid_to_move_back_to = deck_riser_adapter + protocol.comment(f"{offset} Offset {num_offset}, Lid # {slot+1}") + # move lid to plate in thermocycler + protocol.move_labware( + unused_lids[0], + plate_in_cycler, + use_gripper=True, + pick_up_offset=pick_up_offset[offset], + ) + protocol.move_labware(unused_lids[0], lid_to_move_back_to, use_gripper=True) diff --git a/abr-testing/abr_testing/tools/abr_setup.py b/abr-testing/abr_testing/tools/abr_setup.py index a084c54c4f9..d17773965b3 100644 --- a/abr-testing/abr_testing/tools/abr_setup.py +++ b/abr-testing/abr_testing/tools/abr_setup.py @@ -42,9 +42,7 @@ def clean_sheet(sheet_name: str, credentials: str) -> Any: # Check if the date is older than the cutoff if formatted_date < cutoff_date: rem_rows.append(row_id) - - # Limit rem_rows to 1500 at a time - if len(rem_rows) >= 1500: + if len(rem_rows) > 1500: break if len(rem_rows) == 0: # No more rows to remove @@ -55,7 +53,9 @@ def clean_sheet(sheet_name: str, credentials: str) -> Any: sheet.batch_delete_rows(rem_rows) print("deleted rows") except Exception: + print("could not delete rows") return + clean_sheet(sheet_name, credentials) From a2e4bdd2acb29a5e4bd00fd5a4ba5e760c073b64 Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:59:56 -0500 Subject: [PATCH 31/42] feat(protocol-designer, components): add dropdown field deck highlights (#17122) closes AUTH-1124 --- .../BaseDeck/WasteChuteFixture.tsx | 85 +++-- .../BaseDeck/WasteChuteStagingAreaFixture.tsx | 7 + .../src/hardware-sim/Deck/DeckFromLayers.tsx | 2 + .../src/hardware-sim/Deck/FlexTrash.tsx | 19 + .../src/hardware-sim/Deck/OT2Layers.tsx | 13 +- .../DeckLabel/__tests__/DeckLabel.test.tsx | 2 +- components/src/molecules/DeckLabel/index.tsx | 6 +- .../src/molecules/DropdownMenu/index.tsx | 6 + .../__tests__/DeckLabelSet.test.tsx | 2 + .../src/organisms/DeckLabelSet/index.tsx | 29 +- .../assets/localization/en/application.json | 5 + .../molecules/DropdownStepFormField/index.tsx | 49 ++- .../organisms/DesignerNavigation/index.tsx | 11 +- .../Designer/DeckSetup/DeckItemHighlight.tsx | 94 +++++ .../Designer/DeckSetup/DeckSetupDetails.tsx | 28 +- .../Designer/DeckSetup/FixtureRender.tsx | 55 ++- .../Designer/DeckSetup/HighlightItems.tsx | 326 ++++++++++++++++++ .../pages/Designer/DeckSetup/HoveredItems.tsx | 1 + .../pages/Designer/DeckSetup/ModuleLabel.tsx | 37 +- .../DeckSetup/SelectedHoveredItems.tsx | 4 + .../__tests__/DeckSetupContainer.test.tsx | 13 +- .../src/pages/Designer/HighlightLabware.tsx | 5 + .../src/pages/Designer/LabwareLabel.tsx | 26 +- .../Designer/Offdeck/HighlightOffdeckSlot.tsx | 76 ++++ .../pages/Designer/Offdeck/OffDeckDetails.tsx | 41 ++- .../Offdeck/__tests__/OffDeckDetails.test.tsx | 16 +- .../StepForm/PipetteFields/LabwareField.tsx | 12 +- .../StepForm/StepFormToolbox.tsx | 17 +- .../StepTools/HeaterShakerTools/index.tsx | 11 +- .../StepForm/StepTools/MagnetTools/index.tsx | 73 +--- .../MoveLabwareTools/LabwareLocationField.tsx | 15 +- .../MoveLabwareTools/MoveLabwareField.tsx | 12 +- .../StepTools/TemperatureTools/index.tsx | 11 +- .../StepTools/ThermocyclerTools/index.tsx | 4 +- .../StepTools/__tests__/MagnetTools.test.tsx | 3 - .../src/pages/Designer/index.tsx | 11 +- .../test/createPresavedStepForm.test.ts | 1 + .../utils/createPresavedStepForm.ts | 79 ++++- .../steps/actions/__tests__/actions.test.ts | 34 +- .../__tests__/addAndSelectStep.test.ts | 316 +++++++++++++++++ .../src/ui/steps/actions/actions.ts | 127 ++++++- .../src/ui/steps/actions/thunks/index.ts | 121 ++++++- .../src/ui/steps/actions/types.ts | 18 + protocol-designer/src/ui/steps/reducers.ts | 49 +++ protocol-designer/src/ui/steps/selectors.ts | 9 + shared-data/js/fixtures.ts | 4 +- 46 files changed, 1653 insertions(+), 232 deletions(-) create mode 100644 protocol-designer/src/pages/Designer/DeckSetup/DeckItemHighlight.tsx create mode 100644 protocol-designer/src/pages/Designer/DeckSetup/HighlightItems.tsx create mode 100644 protocol-designer/src/pages/Designer/Offdeck/HighlightOffdeckSlot.tsx diff --git a/components/src/hardware-sim/BaseDeck/WasteChuteFixture.tsx b/components/src/hardware-sim/BaseDeck/WasteChuteFixture.tsx index 2253e0f8726..cc977a4e8b6 100644 --- a/components/src/hardware-sim/BaseDeck/WasteChuteFixture.tsx +++ b/components/src/hardware-sim/BaseDeck/WasteChuteFixture.tsx @@ -8,6 +8,7 @@ import { JUSTIFY_CENTER, TEXT_ALIGN_CENTER, } from '../../styles' +import { DeckLabelSet } from '../../organisms' import { SPACING, TYPOGRAPHY } from '../../ui-style-constants' import { COLORS } from '../../helix-design-system' import { RobotCoordsForeignObject } from '../Deck/RobotCoordsForeignObject' @@ -17,7 +18,13 @@ import type { DeckDefinition, ModuleType, } from '@opentrons/shared-data' +import type { DeckLabelProps } from '../../molecules' +const WASTE_CHUTE_WIDTH = 130 +const WASTE_CHUTE_HEIGHT = 138 +const WASTE_CHUTE_X = 322 +const WASTE_CHUTE_Y = -51 +const TAG_HEIGHT = 28 interface WasteChuteFixtureProps extends React.SVGProps { cutoutId: typeof WASTE_CHUTE_CUTOUT deckDefinition: DeckDefinition @@ -25,6 +32,10 @@ interface WasteChuteFixtureProps extends React.SVGProps { fixtureBaseColor?: React.SVGProps['fill'] wasteChuteColor?: string showExtensions?: boolean + /** optional prop to highlight the border of the wasteChute */ + showHighlight?: boolean + /** optional tag info to display a tag below the waste */ + tagInfo?: DeckLabelProps[] } export function WasteChuteFixture( @@ -35,6 +46,8 @@ export function WasteChuteFixture( deckDefinition, fixtureBaseColor = COLORS.grey35, wasteChuteColor = COLORS.grey50, + showHighlight, + tagInfo, ...restProps } = props @@ -64,6 +77,8 @@ export function WasteChuteFixture( ) @@ -72,43 +87,57 @@ export function WasteChuteFixture( interface WasteChuteProps { wasteIconColor: string backgroundColor: string + showHighlight?: boolean + tagInfo?: DeckLabelProps[] } /** * a deck map foreign object representing the physical location of the waste chute connected to the deck */ export function WasteChute(props: WasteChuteProps): JSX.Element { - const { wasteIconColor, backgroundColor } = props + const { wasteIconColor, backgroundColor, showHighlight, tagInfo } = props return ( - - + - - - Waste chute - - - + + + Waste chute + + + + {tagInfo != null && tagInfo.length > 0 ? ( + + ) : null} + ) } diff --git a/components/src/hardware-sim/BaseDeck/WasteChuteStagingAreaFixture.tsx b/components/src/hardware-sim/BaseDeck/WasteChuteStagingAreaFixture.tsx index 0034439ce12..17539777257 100644 --- a/components/src/hardware-sim/BaseDeck/WasteChuteStagingAreaFixture.tsx +++ b/components/src/hardware-sim/BaseDeck/WasteChuteStagingAreaFixture.tsx @@ -8,6 +8,7 @@ import { SlotClip } from './SlotClip' import { WasteChute } from './WasteChuteFixture' import type { DeckDefinition, ModuleType } from '@opentrons/shared-data' +import type { DeckLabelProps } from '../../molecules' interface WasteChuteStagingAreaFixtureProps extends React.SVGProps { @@ -18,6 +19,8 @@ interface WasteChuteStagingAreaFixtureProps slotClipColor?: React.SVGProps['stroke'] wasteChuteColor?: string showExtensions?: boolean + showHighlight?: boolean + tagInfo?: DeckLabelProps[] } export function WasteChuteStagingAreaFixture( @@ -29,6 +32,8 @@ export function WasteChuteStagingAreaFixture( fixtureBaseColor = COLORS.grey35, slotClipColor = COLORS.grey60, wasteChuteColor = COLORS.grey50, + showHighlight, + tagInfo, ...restProps } = props @@ -62,6 +67,8 @@ export function WasteChuteStagingAreaFixture( ) diff --git a/components/src/hardware-sim/Deck/DeckFromLayers.tsx b/components/src/hardware-sim/Deck/DeckFromLayers.tsx index badd7e80ca1..14d5b5337f4 100644 --- a/components/src/hardware-sim/Deck/DeckFromLayers.tsx +++ b/components/src/hardware-sim/Deck/DeckFromLayers.tsx @@ -15,6 +15,8 @@ import { ALL_OT2_DECK_LAYERS } from './constants' import type { RobotType } from '@opentrons/shared-data' +export * from './OT2Layers' + export interface DeckFromLayersProps { robotType: RobotType layerBlocklist: string[] diff --git a/components/src/hardware-sim/Deck/FlexTrash.tsx b/components/src/hardware-sim/Deck/FlexTrash.tsx index 9b3c4c9fef9..00ae3fb2a1b 100644 --- a/components/src/hardware-sim/Deck/FlexTrash.tsx +++ b/components/src/hardware-sim/Deck/FlexTrash.tsx @@ -4,6 +4,7 @@ import { opentrons1Trash3200MlFixedV1 as trashLabwareDef, } from '@opentrons/shared-data' import { Icon } from '../../icons' +import { DeckLabelSet } from '../../organisms' import { Flex, Text } from '../../primitives' import { ALIGN_CENTER, JUSTIFY_CENTER } from '../../styles' import { SPACING, TYPOGRAPHY } from '../../ui-style-constants' @@ -11,6 +12,7 @@ import { COLORS, BORDERS } from '../../helix-design-system' import { RobotCoordsForeignObject } from './RobotCoordsForeignObject' import type { RobotType } from '@opentrons/shared-data' +import type { DeckLabelProps } from '../../molecules' // only allow edge cutout locations (columns 1 and 3) export type TrashCutoutId = @@ -23,11 +25,16 @@ export type TrashCutoutId = | 'cutoutC3' | 'cutoutD3' +const HEIGHT_OF_TAG = 28 interface FlexTrashProps { robotType: RobotType trashIconColor: string backgroundColor: string trashCutoutId?: TrashCutoutId + /** optional prop to highlight the border of the trashBin */ + showHighlight?: boolean + /** optional tag info to display a tag below the trash */ + tagInfo?: DeckLabelProps[] } /** @@ -40,6 +47,8 @@ export const FlexTrash = ({ trashIconColor, backgroundColor, trashCutoutId, + showHighlight, + tagInfo, }: FlexTrashProps): JSX.Element | null => { // be sure we don't try to render for an OT-2 if (robotType !== FLEX_ROBOT_TYPE) return null @@ -96,6 +105,7 @@ export const FlexTrash = ({ justifyContent={JUSTIFY_CENTER} gridGap={SPACING.spacing8} width="100%" + border={showHighlight ? `3px solid ${COLORS.blue50}` : 'none'} > {rotateDegrees === '180' ? ( + {tagInfo != null && tagInfo.length > 0 ? ( + + ) : null} ) : null } diff --git a/components/src/hardware-sim/Deck/OT2Layers.tsx b/components/src/hardware-sim/Deck/OT2Layers.tsx index fe103ded268..cc5b3143aa1 100644 --- a/components/src/hardware-sim/Deck/OT2Layers.tsx +++ b/components/src/hardware-sim/Deck/OT2Layers.tsx @@ -1,3 +1,5 @@ +import { COLORS } from '../../helix-design-system' + export function FixedBase(): JSX.Element { return ( @@ -14,15 +16,20 @@ export function FixedBase(): JSX.Element { ) } -export function FixedTrash(): JSX.Element { +interface FixedTrashProps { + highlight?: boolean +} +export function FixedTrash(props: FixedTrashProps): JSX.Element { + const { highlight = false } = props return ( diff --git a/components/src/molecules/DeckLabel/__tests__/DeckLabel.test.tsx b/components/src/molecules/DeckLabel/__tests__/DeckLabel.test.tsx index 088536e706a..f041585b1cd 100644 --- a/components/src/molecules/DeckLabel/__tests__/DeckLabel.test.tsx +++ b/components/src/molecules/DeckLabel/__tests__/DeckLabel.test.tsx @@ -1,4 +1,3 @@ -import type * as React from 'react' import { screen } from '@testing-library/react' import { describe, it, beforeEach, expect } from 'vitest' @@ -20,6 +19,7 @@ describe('DeckLabel', () => { text: 'mock DeckLabel text', isSelected: false, isLast: true, + isZoomed: true, } }) diff --git a/components/src/molecules/DeckLabel/index.tsx b/components/src/molecules/DeckLabel/index.tsx index d3a8c02b975..67be739c7ab 100644 --- a/components/src/molecules/DeckLabel/index.tsx +++ b/components/src/molecules/DeckLabel/index.tsx @@ -11,6 +11,7 @@ import type { FlattenSimpleInterpolation } from 'styled-components' import type { ModuleModel } from '@opentrons/shared-data' export interface DeckLabelProps { + isZoomed: boolean text: string isSelected: boolean moduleModel?: ModuleModel @@ -26,6 +27,7 @@ export function DeckLabel({ moduleModel, maxWidth = FLEX_MAX_CONTENT, isLast = false, + isZoomed, }: DeckLabelProps): JSX.Element { const DECK_LABEL_BASE_STYLE = ( labelBorderRadius?: string @@ -59,7 +61,7 @@ export function DeckLabel({ return ( - {moduleModel != null ? ( + {moduleModel != null && isZoomed ? ( ) : null} diff --git a/components/src/molecules/DropdownMenu/index.tsx b/components/src/molecules/DropdownMenu/index.tsx index 29dfe03988d..2e2f2d8b8ca 100644 --- a/components/src/molecules/DropdownMenu/index.tsx +++ b/components/src/molecules/DropdownMenu/index.tsx @@ -65,6 +65,8 @@ export interface DropdownMenuProps { disabled?: boolean /** optional placement of the menu */ menuPlacement?: 'auto' | 'top' | 'bottom' + onEnter?: (id: string) => void + onExit?: () => void } // TODO: (smb: 4/15/22) refactor this to use html select for accessibility @@ -84,6 +86,8 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { disabled = false, onFocus, onBlur, + onEnter, + onExit, menuPlacement = 'auto', } = props const [targetProps, tooltipProps] = useHoverTooltip() @@ -290,6 +294,8 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { setShowDropdownMenu(false) }} border="none" + onMouseEnter={() => onEnter?.(option.value)} + onMouseLeave={onExit} > ): JSX.Element => { - const { deckLabels, x, y, width, height } = props + const { deckLabels, x, y, width, height, invert = false } = props return ( - - + + 0 ? deckLabels[0].isZoomed : true} + /> {deckLabels.length > 0 ? deckLabels.map((deckLabel, index) => ( @@ -46,9 +60,14 @@ export const DeckLabelSet = React.forwardRef( DeckLabelSetComponent ) -const StyledBox = styled(Box)` +interface StyledBoxProps { + isZoomed: boolean +} + +const StyledBox = styled(Box)` border-radius: ${BORDERS.borderRadius4}; - border: 1.5px solid ${COLORS.blue50}; + border: ${({ isZoomed }) => + isZoomed ? `1.5px solid ${COLORS.blue50}` : `3px solid ${COLORS.blue50}`}; ` const LabelContainer = styled.div` diff --git a/protocol-designer/src/assets/localization/en/application.json b/protocol-designer/src/assets/localization/en/application.json index 0cbdb9cc6d3..3692c9a1fac 100644 --- a/protocol-designer/src/assets/localization/en/application.json +++ b/protocol-designer/src/assets/localization/en/application.json @@ -5,12 +5,14 @@ "cancel": "cancel", "date_created": "Date Created", "description": "Description", + "dest": "Destination", "edit": "edit", "exit_batch_edit": "exit batch edit", "go_back": "Go back", "information": "Information", "labware": "labware", "last_exported": "Last Exported", + "location": "Location", "magnet_height_caption": "Must be between {{low}} to {{high}}.", "magnet_recommended": "The recommended height is {{default}}", "manually": "Manually", @@ -42,6 +44,9 @@ "temperature": "temperature", "thermocycler": "thermocycler" }, + "select": "Select", + "selected": "Selected", + "source": "Source", "temperature": "Temperature (ËšC)", "time": "Time", "units": { diff --git a/protocol-designer/src/molecules/DropdownStepFormField/index.tsx b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx index 01f82972d60..75334fe830a 100644 --- a/protocol-designer/src/molecules/DropdownStepFormField/index.tsx +++ b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx @@ -1,5 +1,5 @@ import { useTranslation } from 'react-i18next' -import { useEffect } from 'react' +import { useDispatch } from 'react-redux' import { COLORS, DIRECTION_COLUMN, @@ -9,6 +9,7 @@ import { SPACING, StyledText, } from '@opentrons/components' +import { selectDropdownItem } from '../../ui/steps/actions/actions' import type { Options } from '@opentrons/components' import type { FieldProps } from '../../pages/Designer/ProtocolSteps/StepForm/types' @@ -16,8 +17,13 @@ export interface DropdownStepFormFieldProps extends FieldProps { options: Options title: string width?: string + onEnter?: (id: string) => void + onExit?: () => void } +const FIRST_FIELDS = ['aspirate_labware', 'labware', 'moduleId'] +const SECOND_FIELDS = ['dispense_labware', 'newLocation'] + export function DropdownStepFormField( props: DropdownStepFormFieldProps ): JSX.Element { @@ -31,16 +37,44 @@ export function DropdownStepFormField( padding = `0 ${SPACING.spacing16}`, width = '17.5rem', onFieldFocus, + onEnter, + onExit, onFieldBlur, + name: fieldName, } = props - const { t } = useTranslation('tooltip') + const { t } = useTranslation(['tooltip', 'application']) + const dispatch = useDispatch() const availableOptionId = options.find(opt => opt.value === value) + const handleSelection = (value: string): void => { + let text = t('application:selected') + if (fieldName === 'newLocation') { + text = t('application:location') + } else if (fieldName === 'aspirate_labware') { + text = t('application:source') + } else if (fieldName === 'dispense_labware') { + text = t('application:dest') + } - useEffect(() => { - if (options.length === 1) { - updateValue(options[0].value) + const selection = { + id: value, + text, + } + if (FIRST_FIELDS.includes(fieldName)) { + dispatch( + selectDropdownItem({ + selection: { ...selection, field: '1' }, + mode: 'add', + }) + ) + } else if (SECOND_FIELDS.includes(fieldName)) { + dispatch( + selectDropdownItem({ + selection: { ...selection, field: '2' }, + mode: 'add', + }) + ) } - }, []) + } return ( @@ -59,7 +93,10 @@ export function DropdownStepFormField( } onClick={value => { updateValue(value) + handleSelection(value) }} + onEnter={onEnter} + onExit={onExit} /> ) : ( selected.id === itemId && selected.field === '2' + ) + + if ( + tab === 'startingDeck' || + slotPosition === null || + (!isHovered && !isSelected) + ) { + return null + } + + return ( + <> + + + + ) +} diff --git a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupDetails.tsx b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupDetails.tsx index 53a61df3faf..110bf9535a2 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupDetails.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupDetails.tsx @@ -29,6 +29,7 @@ import { HoveredItems } from './HoveredItems' import { SelectedHoveredItems } from './SelectedHoveredItems' import { getAdjacentLabware } from './utils' import { SlotWarning } from './SlotWarning' +import { HighlightItems } from './HighlightItems' import type { ComponentProps, Dispatch, SetStateAction } from 'react' import type { ThermocyclerVizProps } from '@opentrons/components' @@ -258,17 +259,19 @@ export function DeckSetupDetails(props: DeckSetupDetailsProps): JSX.Element { ) : null} {labwareLoadedOnModule == null ? ( - + <> + + ) : null} @@ -431,6 +434,9 @@ export function DeckSetupDetails(props: DeckSetupDetailsProps): JSX.Element { ) })} + {/* highlight items from Protocol steps */} + + {/* selected hardware + labware */} { - const { fixture, cutout, deckDef, robotType } = props + const { fixture, cutout, deckDef, robotType, showHighlight, tagInfo } = props const deckSetup = useSelector(getInitialDeckSetup) const { labware } = deckSetup const adjacentLabware = getAdjacentLabware(fixture, cutout, labware) @@ -61,22 +68,28 @@ export const FixtureRender = (props: FixtureRenderProps): JSX.Element => { ) } case 'trashBin': { - return ( - - - - - ) + if (robotType === OT2_ROBOT_TYPE && showHighlight) { + return + } else { + return ( + + + + + ) + } } case 'wasteChute': { return ( @@ -85,6 +98,8 @@ export const FixtureRender = (props: FixtureRenderProps): JSX.Element => { cutoutId={cutout as typeof WASTE_CHUTE_CUTOUT} deckDefinition={deckDef} fixtureBaseColor={lightFill} + showHighlight={showHighlight} + tagInfo={tagInfo} /> ) } @@ -95,6 +110,8 @@ export const FixtureRender = (props: FixtureRenderProps): JSX.Element => { cutoutId={cutout as typeof WASTE_CHUTE_CUTOUT} deckDefinition={deckDef} fixtureBaseColor={lightFill} + showHighlight={showHighlight} + tagInfo={tagInfo} /> {renderLabwareOnDeck()} diff --git a/protocol-designer/src/pages/Designer/DeckSetup/HighlightItems.tsx b/protocol-designer/src/pages/Designer/DeckSetup/HighlightItems.tsx new file mode 100644 index 00000000000..fd548de360b --- /dev/null +++ b/protocol-designer/src/pages/Designer/DeckSetup/HighlightItems.tsx @@ -0,0 +1,326 @@ +import { useSelector } from 'react-redux' +import { useTranslation } from 'react-i18next' + +import { + STANDARD_FLEX_SLOTS, + STANDARD_OT2_SLOTS, + THERMOCYCLER_MODULE_TYPE, + WASTE_CHUTE_CUTOUT, + getAddressableAreaFromSlotId, + getPositionFromSlotId, + inferModuleOrientationFromXCoordinate, +} from '@opentrons/shared-data' +import { getDeckSetupForActiveItem } from '../../../top-selectors/labware-locations' +import { + getHoveredDropdownItem, + getSelectedDropdownItem, +} from '../../../ui/steps/selectors' +import { getDesignerTab } from '../../../file-data/selectors' +import { LabwareLabel } from '../LabwareLabel' +import { ModuleLabel } from './ModuleLabel' +import { FixtureRender } from './FixtureRender' +import { DeckItemHighlight } from './DeckItemHighlight' +import type { AdditionalEquipmentName } from '@opentrons/step-generation' +import type { + RobotType, + DeckDefinition, + CutoutId, + AddressableAreaName, +} from '@opentrons/shared-data' +import type { LabwareOnDeck, ModuleOnDeck } from '../../../step-forms' +import type { Fixture } from './constants' + +interface HighlightItemsProps { + deckDef: DeckDefinition + robotType: RobotType +} + +const SLOTS = [ + ...STANDARD_FLEX_SLOTS, + ...STANDARD_OT2_SLOTS, + 'A4', + 'B4', + 'C4', + 'D4', + 'cutoutD3', +] + +export function HighlightItems(props: HighlightItemsProps): JSX.Element | null { + const { robotType, deckDef } = props + const { t } = useTranslation('application') + const tab = useSelector(getDesignerTab) + const { labware, modules, additionalEquipmentOnDeck } = useSelector( + getDeckSetupForActiveItem + ) + const hoveredItem = useSelector(getHoveredDropdownItem) + const selectedDropdownItems = useSelector(getSelectedDropdownItem) + + if ( + hoveredItem == null && + (selectedDropdownItems == null || selectedDropdownItems.length === 0) + ) { + return null + } + + const hoveredItemLabware: LabwareOnDeck | null = + hoveredItem?.id != null && labware[hoveredItem.id] != null + ? labware[hoveredItem.id] + : null + const selectedItemLabwares = selectedDropdownItems.filter( + selected => selected.id != null && labware[selected.id] + ) + const hoveredItemModule: ModuleOnDeck | null = + hoveredItem?.id != null && modules[hoveredItem.id] != null + ? modules[hoveredItem.id] + : null + const selectedItemModule = selectedDropdownItems.find( + selected => selected.id != null && modules[selected.id] + ) + const hoveredItemTrash: { + name: AdditionalEquipmentName + id: string + location?: string | undefined + } | null = + hoveredItem?.id != null && additionalEquipmentOnDeck[hoveredItem.id] != null + ? additionalEquipmentOnDeck[hoveredItem.id] + : null + const selectedItemTrash = selectedDropdownItems.find( + selected => selected.id != null && additionalEquipmentOnDeck[selected.id] + ) + + const hoveredDeckItem: string | null = + hoveredItem?.id != null && + SLOTS.includes(hoveredItem.id as AddressableAreaName) + ? hoveredItem.id + : null + const selectedItemSlot = selectedDropdownItems.find( + selected => + selected.id != null && SLOTS.includes(selected.id as AddressableAreaName) + ) + + const getLabwareItems = (): JSX.Element[] => { + const items: JSX.Element[] = [] + + if (hoveredItemLabware != null || selectedItemLabwares.length > 0) { + const selectedLabwaresOnDeck = selectedItemLabwares + .map(item => (item?.id != null ? labware[item.id] : null)) + .filter(Boolean) + + const labwaresToRender = + hoveredItemLabware != null + ? [hoveredItemLabware] + : selectedLabwaresOnDeck + + labwaresToRender.forEach((labwareOnDeck, index) => { + if (!labwareOnDeck) { + console.warn( + `labwareOnDeck was null as ${labwareOnDeck}, expected to find a matching entity` + ) + return + } + + let labwareSlot = labwareOnDeck.slot + const hasTC = Object.values(modules).some( + module => module.type === THERMOCYCLER_MODULE_TYPE + ) + + if (modules[labwareSlot]) { + labwareSlot = modules[labwareSlot].slot + } else if (labware[labwareSlot]) { + const adapter = labware[labwareSlot] + labwareSlot = modules[adapter.slot]?.slot ?? adapter.slot + } + + const position = getPositionFromSlotId(labwareSlot, deckDef) + if (position != null) { + items.push( + selected.id === labwareOnDeck.id + )} + isLast={true} + position={ + hasTC && labwareSlot === 'B1' ? [-20, 282, 0] : position + } + labwareDef={labwareOnDeck.def} + labelText={ + hoveredItemLabware == null + ? selectedItemLabwares.find( + selected => selected.id === labwareOnDeck.id + )?.text ?? '' + : hoveredItem.text ?? '' + } + /> + ) + } + }) + } + + return items + } + + const getModuleItems = (): JSX.Element[] => { + const items: JSX.Element[] = [] + + if (hoveredItemModule != null || selectedItemModule != null) { + const selectedModuleOnDeck = + selectedItemModule?.id != null ? modules[selectedItemModule.id] : null + const moduleOnDeck = hoveredItemModule ?? selectedModuleOnDeck + + if (!moduleOnDeck) { + console.warn( + `moduleOnDeck was null as ${moduleOnDeck}, expected to find a matching entity` + ) + return items + } + + const position = getPositionFromSlotId(moduleOnDeck.slot, deckDef) + if (position != null) { + items.push( + + ) + } + } + + return items + } + + const getTrashItems = (): JSX.Element[] => { + const items: JSX.Element[] = [] + + if (hoveredItemTrash != null || selectedItemTrash != null) { + const selectedTrashOnDeck = + selectedItemTrash?.id != null + ? additionalEquipmentOnDeck[selectedItemTrash.id] + : null + const trashOnDeck = hoveredItemTrash ?? selectedTrashOnDeck + + if (!trashOnDeck) { + console.warn( + `trashOnDeck was null as ${trashOnDeck}, expected to find a matching entity` + ) + return [] + } + + if (hoveredItemTrash != null) { + items.push( + + ) + } + + if (selectedTrashOnDeck != null && selectedItemTrash != null) { + items.push( + + ) + } + } + + return items + } + + const getDeckItems = (): JSX.Element[] => { + const items: JSX.Element[] = [] + + if (hoveredDeckItem != null || selectedItemSlot != null) { + const slot = hoveredDeckItem ?? selectedItemSlot?.id + + if (slot === WASTE_CHUTE_CUTOUT) { + items.push( + + ) + } else { + const addressableArea = + slot != null && slot !== WASTE_CHUTE_CUTOUT + ? getAddressableAreaFromSlotId(slot, deckDef) + : null + + if (!addressableArea) { + console.warn( + `addressableArea was null as ${addressableArea}, expected to find a matching entity` + ) + return [] + } + items.push( + + ) + } + } + + return items + } + + const renderItems = (): JSX.Element[] => { + return [ + ...getLabwareItems(), + ...getModuleItems(), + ...getTrashItems(), + ...getDeckItems(), + ] + } + + return <>{renderItems()} +} diff --git a/protocol-designer/src/pages/Designer/DeckSetup/HoveredItems.tsx b/protocol-designer/src/pages/Designer/DeckSetup/HoveredItems.tsx index 79bba166f88..a96d2418607 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/HoveredItems.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/HoveredItems.tsx @@ -76,6 +76,7 @@ export const HoveredItems = ( text: selectedLabwareDef.metadata.displayName, isLast: false, isSelected: true, + isZoomed: true, }, ] : [] diff --git a/protocol-designer/src/pages/Designer/DeckSetup/ModuleLabel.tsx b/protocol-designer/src/pages/Designer/DeckSetup/ModuleLabel.tsx index 1b8eaa4e73b..12849eba08a 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/ModuleLabel.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/ModuleLabel.tsx @@ -1,11 +1,15 @@ import { useRef, useState, useEffect } from 'react' +import { useSelector } from 'react-redux' import { DeckLabelSet } from '@opentrons/components' import { + FLEX_ROBOT_TYPE, HEATERSHAKER_MODULE_TYPE, MAGNETIC_MODULE_TYPE, TEMPERATURE_MODULE_TYPE, + THERMOCYCLER_MODULE_TYPE, getModuleDef2, } from '@opentrons/shared-data' +import { getRobotType } from '../../../file-data/selectors' import type { DeckLabelProps } from '@opentrons/components' import type { CoordinateTuple, ModuleModel } from '@opentrons/shared-data' @@ -15,7 +19,9 @@ interface ModuleLabelProps { orientation: 'left' | 'right' isSelected: boolean isLast: boolean + isZoomed?: boolean labwareInfos?: DeckLabelProps[] + labelName?: string } export const ModuleLabel = (props: ModuleLabelProps): JSX.Element => { const { @@ -25,7 +31,10 @@ export const ModuleLabel = (props: ModuleLabelProps): JSX.Element => { isSelected, isLast, labwareInfos = [], + isZoomed = true, + labelName, } = props + const robotType = useSelector(getRobotType) const labelContainerRef = useRef(null) const [labelContainerHeight, setLabelContainerHeight] = useState(12) @@ -40,14 +49,25 @@ export const ModuleLabel = (props: ModuleLabelProps): JSX.Element => { def?.dimensions.labwareInterfaceXDimension != null ? def.dimensions.xDimension - def?.dimensions.labwareInterfaceXDimension : 0 - // TODO(ja 9/6/24): definitely need to refine these overhang values let leftOverhang = overhang - if (def?.moduleType === TEMPERATURE_MODULE_TYPE) { - leftOverhang = overhang * 2 - } else if (def?.moduleType === HEATERSHAKER_MODULE_TYPE) { - leftOverhang = overhang + 14 - } else if (def?.moduleType === MAGNETIC_MODULE_TYPE) { - leftOverhang = overhang + 8 + + switch (def?.moduleType) { + case TEMPERATURE_MODULE_TYPE: + leftOverhang = overhang * 2 + break + case HEATERSHAKER_MODULE_TYPE: + leftOverhang = overhang + 14 + break + case MAGNETIC_MODULE_TYPE: + leftOverhang = overhang + 8 + break + case THERMOCYCLER_MODULE_TYPE: + if (!isZoomed && robotType === FLEX_ROBOT_TYPE) { + leftOverhang = overhang + 20 + } + break + default: + break } return ( @@ -55,10 +75,11 @@ export const ModuleLabel = (props: ModuleLabelProps): JSX.Element => { ref={labelContainerRef} deckLabels={[ { - text: def?.displayName, + text: labelName ?? def?.displayName, isSelected, isLast, moduleModel: def?.model, + isZoomed: isZoomed, }, ...labwareInfos, ]} diff --git a/protocol-designer/src/pages/Designer/DeckSetup/SelectedHoveredItems.tsx b/protocol-designer/src/pages/Designer/DeckSetup/SelectedHoveredItems.tsx index 33bb727fa38..2400271ee22 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/SelectedHoveredItems.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/SelectedHoveredItems.tsx @@ -115,6 +115,7 @@ export const SelectedHoveredItems = ( text: def.metadata.displayName, isSelected: true, isLast: hoveredLabware == null && selectedNestedLabwareDefUri == null, + isZoomed: true, } labwareInfos.push(selectedLabwareLabel) } @@ -123,6 +124,7 @@ export const SelectedHoveredItems = ( text: selectedNestedLabwareDef.metadata.displayName, isSelected: true, isLast: hoveredLabware == null, + isZoomed: true, } labwareInfos.push(selectedNestedLabwareLabel) } @@ -136,6 +138,7 @@ export const SelectedHoveredItems = ( text: hoveredLabwareDef.metadata.displayName, isSelected: false, isLast: true, + isZoomed: true, } labwareInfos.push(hoverLabelLabel) } @@ -208,6 +211,7 @@ export const SelectedHoveredItems = ( selectedNestedLabwareDef?.metadata.displayName ?? 'unknown name', isSelected: true, isLast: true, + isZoomed: true, }, ]} /> diff --git a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/DeckSetupContainer.test.tsx b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/DeckSetupContainer.test.tsx index eb77c79190a..a5d0226472d 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/DeckSetupContainer.test.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/DeckSetupContainer.test.tsx @@ -8,14 +8,19 @@ import { renderWithProviders } from '../../../../__testing-utils__' import { selectors } from '../../../../labware-ingred/selectors' import { getDeckSetupForActiveItem } from '../../../../top-selectors/labware-locations' -import { DeckSetupTools } from '../DeckSetupTools' -import { DeckSetupContainer } from '../DeckSetupContainer' +import { + getHoveredDropdownItem, + getSelectedDropdownItem, +} from '../../../../ui/steps/selectors' import { getSelectedTerminalItemId } from '../../../../ui/steps' import { getDisableModuleRestrictions } from '../../../../feature-flags/selectors' import { getRobotType } from '../../../../file-data/selectors' import { DeckSetupDetails } from '../DeckSetupDetails' +import { DeckSetupTools } from '../DeckSetupTools' +import { DeckSetupContainer } from '../DeckSetupContainer' import type * as OpentronsComponents from '@opentrons/components' +vi.mock('../../../../ui/steps/selectors') vi.mock('../../../../top-selectors/labware-locations') vi.mock('../../../../feature-flags/selectors') vi.mock('../DeckSetupTools') @@ -41,6 +46,10 @@ describe('DeckSetupContainer', () => { slot: 'D3', cutout: 'cutoutD3', }) + vi.mocked(getSelectedDropdownItem).mockReturnValue([ + { id: null, text: null }, + ]) + vi.mocked(getHoveredDropdownItem).mockReturnValue({ id: null, text: null }) vi.mocked(DeckSetupTools).mockReturnValue(
mock DeckSetupTools
) vi.mocked(DeckSetupDetails).mockReturnValue(
mock DeckSetupDetails
diff --git a/protocol-designer/src/pages/Designer/HighlightLabware.tsx b/protocol-designer/src/pages/Designer/HighlightLabware.tsx index c2bddc9fbd4..9e2359e66c1 100644 --- a/protocol-designer/src/pages/Designer/HighlightLabware.tsx +++ b/protocol-designer/src/pages/Designer/HighlightLabware.tsx @@ -1,6 +1,7 @@ import { useSelector } from 'react-redux' import { getLabwareEntities } from '../../step-forms/selectors' import { getHoveredStepLabware } from '../../ui/steps' +import { getDesignerTab } from '../../file-data/selectors' import { LabwareLabel } from './LabwareLabel' import type { CoordinateTuple } from '@opentrons/shared-data' import type { LabwareOnDeck } from '../../step-forms' @@ -16,6 +17,7 @@ export function HighlightLabware( const { labwareOnDeck, position } = props const labwareEntities = useSelector(getLabwareEntities) const hoveredLabware = useSelector(getHoveredStepLabware) + const tab = useSelector(getDesignerTab) const adapterId = labwareEntities[labwareOnDeck.slot] != null ? labwareEntities[labwareOnDeck.slot].id @@ -23,6 +25,9 @@ export function HighlightLabware( const highlighted = hoveredLabware.includes(adapterId ?? labwareOnDeck.id) + if (tab === 'protocolSteps') { + return null + } if (highlighted) { return ( { +export const LabwareLabel = (props: LabwareLabelProps): JSX.Element => { const { labwareDef, position, isSelected, isLast, nestedLabwareInfo = [], + labelText = labwareDef.metadata.displayName, } = props const labelContainerRef = useRef(null) const designerTab = useSelector(getDesignerTab) const [labelContainerHeight, setLabelContainerHeight] = useState(0) - const deckLabels = - designerTab === 'startingDeck' - ? [ - ...nestedLabwareInfo, - { - text: labwareDef.metadata.displayName, - isSelected: isSelected, - isLast: isLast, - }, - ] - : [] + const deckLabels = [ + ...nestedLabwareInfo, + { + text: labelText, + isSelected: isSelected, + isLast: isLast, + isZoomed: designerTab === 'startingDeck', + }, + ] useEffect(() => { if (labelContainerRef.current) { diff --git a/protocol-designer/src/pages/Designer/Offdeck/HighlightOffdeckSlot.tsx b/protocol-designer/src/pages/Designer/Offdeck/HighlightOffdeckSlot.tsx new file mode 100644 index 00000000000..4f8ddfdbbea --- /dev/null +++ b/protocol-designer/src/pages/Designer/Offdeck/HighlightOffdeckSlot.tsx @@ -0,0 +1,76 @@ +import { useSelector } from 'react-redux' +import { useTranslation } from 'react-i18next' +import { DeckLabelSet, Flex, POSITION_RELATIVE } from '@opentrons/components' +import { + getHoveredDropdownItem, + getSelectedDropdownItem, +} from '../../../ui/steps/selectors' +import type { CoordinateTuple } from '@opentrons/shared-data' +import type { LabwareOnDeck } from '../../../step-forms' + +interface HighlightOffdeckSlotProps { + labwareOnDeck?: LabwareOnDeck + position: CoordinateTuple +} + +export function HighlightOffdeckSlot( + props: HighlightOffdeckSlotProps +): JSX.Element | null { + const { labwareOnDeck, position } = props + const { t } = useTranslation('application') + const hoveredDropdownItem = useSelector(getHoveredDropdownItem) + const selectedDropdownSelection = useSelector(getSelectedDropdownItem) + + if (labwareOnDeck != null) { + const isLabwareSelectionSelected = selectedDropdownSelection.some( + selected => selected.id === labwareOnDeck?.id + ) + const highlighted = hoveredDropdownItem.id === labwareOnDeck?.id + if (highlighted ?? isLabwareSelectionSelected) { + return ( + + + + ) + } + } else { + const highlightedNewLocation = hoveredDropdownItem.id === 'offDeck' + const selected = selectedDropdownSelection.some( + selected => selected.id === 'offDeck' + ) + if (highlightedNewLocation ?? selected) { + return ( + + ) + } + } + return null +} diff --git a/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx b/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx index 3759aabf4d5..05720f81555 100644 --- a/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx +++ b/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx @@ -23,12 +23,17 @@ import { DeckItemHover } from '../DeckSetup/DeckItemHover' import { SlotDetailsContainer } from '../../../organisms' import { wellFillFromWellContents } from '../../../organisms/LabwareOnDeck/utils' import { getRobotType } from '../../../file-data/selectors' +import { + getHoveredDropdownItem, + getSelectedDropdownItem, +} from '../../../ui/steps/selectors' import { SlotOverflowMenu } from '../DeckSetup/SlotOverflowMenu' -import type { DeckSlotId } from '@opentrons/shared-data' +import { HighlightOffdeckSlot } from './HighlightOffdeckSlot' +import type { CoordinateTuple, DeckSlotId } from '@opentrons/shared-data' import type { DeckSetupTabType } from '../types' const OFFDECK_MAP_WIDTH = '41.625rem' - +const ZERO_SLOT_POSITION: CoordinateTuple = [0, 0, 0] interface OffDeckDetailsProps extends DeckSetupTabType { addLabware: () => void } @@ -39,6 +44,8 @@ export function OffDeckDetails(props: OffDeckDetailsProps): JSX.Element { const [menuListId, setShowMenuListForId] = useState(null) const robotType = useSelector(getRobotType) const deckSetup = useSelector(getDeckSetupForActiveItem) + const hoveredDropdownItem = useSelector(getHoveredDropdownItem) + const selectedDropdownSelection = useSelector(getSelectedDropdownItem) const offDeckLabware = Object.values(deckSetup.labware).filter( lw => lw.slot === 'offDeck' ) @@ -98,7 +105,7 @@ export function OffDeckDetails(props: OffDeckDetailsProps): JSX.Element {
- + {offDeckLabware.map(lw => { const wellContents = allWellContentsForActiveItem ? allWellContentsForActiveItem[lw.id] @@ -110,8 +117,21 @@ export function OffDeckDetails(props: OffDeckDetailsProps): JSX.Element { yDimension: dimensions.yDimension ?? 0, zDimension: dimensions.zDimension ?? 0, } + const isLabwareSelectionSelected = selectedDropdownSelection.some( + selected => selected.id === lw.id + ) + const highlighted = hoveredDropdownItem.id === lw.id return ( - + + )} + {menuListId === lw.id ? ( - // TODO fix this rendering position { setShowMenuListForId(null) }} - menuListSlotPosition={[0, 0, 0]} + menuListSlotPosition={ZERO_SLOT_POSITION} invertY /> @@ -161,6 +185,9 @@ export function OffDeckDetails(props: OffDeckDetailsProps): JSX.Element { ) })} + + + {tab === 'startingDeck' ? ( { }) vi.mocked(selectors.getLiquidDisplayColors).mockReturnValue([]) vi.mocked(getAllWellContentsForActiveItem).mockReturnValue({}) + vi.mocked(HighlightOffdeckSlot).mockReturnValue( +
Highlight Offdeck Slot
+ ) + vi.mocked(getSelectedDropdownItem).mockReturnValue([]) + vi.mocked(getHoveredDropdownItem).mockReturnValue({ id: null, text: null }) }) it('renders off-deck overview with 1 labware', () => { @@ -62,5 +73,6 @@ describe('OffDeckDetails', () => { screen.getByText('OFF-DECK LABWARE') screen.getByText('mock LabwareRender') screen.getByText('Add labware') + expect(screen.getAllByText('Highlight Offdeck Slot')).toHaveLength(2) }) }) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/LabwareField.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/LabwareField.tsx index 5fb840e980b..07e08b8a299 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/LabwareField.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/LabwareField.tsx @@ -1,17 +1,19 @@ -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { getDisposalOptions, getLabwareOptions, } from '../../../../../ui/labware/selectors' +import { hoverSelection } from '../../../../../ui/steps/actions/actions' import { DropdownStepFormField } from '../../../../../molecules' import type { FieldProps } from '../types' export function LabwareField(props: FieldProps): JSX.Element { const { name } = props - const { i18n, t } = useTranslation('protocol_steps') + const { i18n, t } = useTranslation(['protocol_steps', 'application']) const disposalOptions = useSelector(getDisposalOptions) const options = useSelector(getLabwareOptions) + const dispatch = useDispatch() const allOptions = name === 'dispense_labware' ? [...options, ...disposalOptions] @@ -23,6 +25,12 @@ export function LabwareField(props: FieldProps): JSX.Element { name={name} options={allOptions} title={i18n.format(t(`${name}`), 'capitalize')} + onEnter={(id: string) => { + dispatch(hoverSelection({ id, text: t('application:select') })) + }} + onExit={() => { + dispatch(hoverSelection({ id: null, text: null })) + }} /> ) } diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx index 6ffbfafbcf2..d8ec3458985 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx @@ -65,6 +65,10 @@ import type { LiquidHandlingTab, StepFormProps, } from './types' +import { + hoverSelection, + selectDropdownItem, +} from '../../../../ui/steps/actions/actions' type StepFormMap = { [K in StepType]?: React.ComponentType | null @@ -239,6 +243,8 @@ export function StepFormToolbox(props: StepFormToolboxProps): JSX.Element { }) ) dispatch(analyticsEvent(stepDuration)) + dispatch(selectDropdownItem({ selection: null, mode: 'clear' })) + dispatch(hoverSelection({ id: null, text: null })) } else { setShowFormErrors(true) if (tab === 'aspirate' && isDispenseError && !isAspirateError) { @@ -300,7 +306,16 @@ export function StepFormToolbox(props: StepFormToolboxProps): JSX.Element { } childrenPadding="0" - onCloseClick={handleClose} + onCloseClick={() => { + handleClose() + dispatch( + selectDropdownItem({ + selection: null, + mode: 'clear', + }) + ) + dispatch(hoverSelection({ id: null, text: null })) + }} closeButton={} confirmButton={ diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/HeaterShakerTools/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/HeaterShakerTools/index.tsx index 1577db5da8c..392bba3d7cc 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/HeaterShakerTools/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/HeaterShakerTools/index.tsx @@ -1,4 +1,4 @@ -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { Box, @@ -8,6 +8,7 @@ import { SPACING, StyledText, } from '@opentrons/components' +import { hoverSelection } from '../../../../../../ui/steps/actions/actions' import { getHeaterShakerLabwareOptions } from '../../../../../../ui/modules/selectors' import { DropdownStepFormField, @@ -21,7 +22,7 @@ export function HeaterShakerTools(props: StepFormProps): JSX.Element { const { propsForFields, formData, visibleFormErrors } = props const { t } = useTranslation(['application', 'form', 'protocol_steps']) const moduleLabwareOptions = useSelector(getHeaterShakerLabwareOptions) - + const dispatch = useDispatch() const mappedErrorsToField = getFormErrorsMappedToField(visibleFormErrors) return ( @@ -34,6 +35,12 @@ export function HeaterShakerTools(props: StepFormProps): JSX.Element { {...propsForFields.moduleId} options={moduleLabwareOptions} title={t('protocol_steps:module')} + onEnter={(id: string) => { + dispatch(hoverSelection({ id, text: t('select') })) + }} + onExit={() => { + dispatch(hoverSelection({ id: null, text: null })) + }} /> - - - {t('protocol_steps:module')} - - - - - {slotInfo[0]} - - - {slotInfo[1]} - - - } - description={ - - - - } - /> - - + { + dispatch( + hoverSelection({ + id, + text: t('application:location'), + }) + ) + }} + onExit={() => { + dispatch(hoverSelection({ id: null, text: null })) + }} /> ) } diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/MoveLabwareField.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/MoveLabwareField.tsx index 539905ec4c2..c27e95e1eb9 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/MoveLabwareField.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/MoveLabwareField.tsx @@ -1,17 +1,25 @@ -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { getMoveLabwareOptions } from '../../../../../../ui/labware/selectors' import { DropdownStepFormField } from '../../../../../../molecules' +import { hoverSelection } from '../../../../../../ui/steps/actions/actions' import type { FieldProps } from '../../types' export function MoveLabwareField(props: FieldProps): JSX.Element { const options = useSelector(getMoveLabwareOptions) - const { t } = useTranslation('protocol_steps') + const dispatch = useDispatch() + const { t } = useTranslation(['protocol_steps', 'application']) return ( { + dispatch(hoverSelection({ id, text: t('application:select') })) + }} + onExit={() => { + dispatch(hoverSelection({ id: null, text: null })) + }} /> ) } diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/TemperatureTools/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/TemperatureTools/index.tsx index d384a6f6217..39bd3a77b8c 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/TemperatureTools/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/TemperatureTools/index.tsx @@ -1,5 +1,5 @@ import { useTranslation } from 'react-i18next' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { Box, COLORS, @@ -7,6 +7,7 @@ import { Flex, SPACING, } from '@opentrons/components' +import { hoverSelection } from '../../../../../../ui/steps/actions/actions' import { getTemperatureLabwareOptions } from '../../../../../../ui/modules/selectors' import { DropdownStepFormField, @@ -20,7 +21,7 @@ export function TemperatureTools(props: StepFormProps): JSX.Element { const { propsForFields, formData, visibleFormErrors } = props const { t } = useTranslation(['application', 'form', 'protocol_steps']) const moduleLabwareOptions = useSelector(getTemperatureLabwareOptions) - + const dispatch = useDispatch() const mappedErrorsToField = getFormErrorsMappedToField(visibleFormErrors) return ( @@ -34,6 +35,12 @@ export function TemperatureTools(props: StepFormProps): JSX.Element { tooltipContent={null} options={moduleLabwareOptions} title={t('protocol_steps:module')} + onEnter={(id: string) => { + dispatch(hoverSelection({ id, text: t('select') })) + }} + onExit={() => { + dispatch(hoverSelection({ id: null, text: null })) + }} /> diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/ThermocyclerTools/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/ThermocyclerTools/index.tsx index 3e85004549e..335facdfd6c 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/ThermocyclerTools/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/ThermocyclerTools/index.tsx @@ -8,7 +8,6 @@ import { RadioButton, SPACING, } from '@opentrons/components' - import { ProfileSettings } from './ProfileSettings' import { ProfileStepsSummary } from './ProfileStepsSummary' import { ThermocyclerState } from './ThermocyclerState' @@ -27,8 +26,7 @@ export function ThermocyclerTools(props: StepFormProps): JSX.Element { focusedField, setShowFormErrors, } = props - const { t } = useTranslation('form') - + const { t } = useTranslation(['form', 'application']) const [contentType, setContentType] = useState( formData.thermocyclerFormType as ThermocyclerContentType ) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/__tests__/MagnetTools.test.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/__tests__/MagnetTools.test.tsx index 15b4adcd78b..6078835fbf6 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/__tests__/MagnetTools.test.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/__tests__/MagnetTools.test.tsx @@ -103,9 +103,6 @@ describe('MagnetTools', () => { it('renders the text and a switch button for v2', () => { render(props) screen.getByText('Module') - screen.getByText('10') - screen.getByText('mock labware') - screen.getByText('mock module') screen.getByText('Magnet state') screen.getByLabelText('Engage') const toggleButton = screen.getByRole('switch') diff --git a/protocol-designer/src/pages/Designer/index.tsx b/protocol-designer/src/pages/Designer/index.tsx index 410faa44739..5e560fcf6e4 100644 --- a/protocol-designer/src/pages/Designer/index.tsx +++ b/protocol-designer/src/pages/Designer/index.tsx @@ -13,7 +13,10 @@ import { ToggleGroup, useOnClickOutside, } from '@opentrons/components' -import { selectTerminalItem } from '../../ui/steps/actions/actions' +import { + selectDropdownItem, + selectTerminalItem, +} from '../../ui/steps/actions/actions' import { useKitchen } from '../../organisms/Kitchen/hooks' import { getDeckSetupForActiveItem } from '../../top-selectors/labware-locations' import { generateNewProtocol } from '../../labware-ingred/actions' @@ -68,6 +71,12 @@ export function Designer(): JSX.Element { isActive: tab === 'startingDeck', onClick: () => { dispatch(selectDesignerTab({ tab: 'startingDeck' })) + dispatch( + selectDropdownItem({ + selection: null, + mode: 'clear', + }) + ) }, } const protocolStepTab = { diff --git a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts index 9a78b49d0ed..77e1f25a229 100644 --- a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts +++ b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts @@ -37,6 +37,7 @@ beforeEach(() => { def: { parameters: { magneticModuleEngageHeight: EXAMPLE_ENGAGE_HEIGHT, + isTiprack: false, }, }, } diff --git a/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts b/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts index 387a3068a18..5951fbf0a04 100644 --- a/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts +++ b/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts @@ -2,6 +2,7 @@ import last from 'lodash/last' import { HEATERSHAKER_MODULE_TYPE, MAGNETIC_MODULE_TYPE, + TEMPERATURE_MODULE_TYPE, THERMOCYCLER_MODULE_TYPE, } from '@opentrons/shared-data' import { @@ -29,6 +30,7 @@ import type { FormData, StepType, StepIdType } from '../../form-types' import type { InitialDeckSetup } from '../types' import type { FormPatch } from '../../steplist/actions/types' import type { SavedStepFormState, OrderedStepIdsState } from '../reducers' + export interface CreatePresavedStepFormArgs { stepId: StepIdType stepType: StepType @@ -118,6 +120,64 @@ const _patchDefaultDropTipLocation = (args: { return null } +const _patchDefaultLabwareLocations = (args: { + labwareEntities: LabwareEntities + pipetteEntities: PipetteEntities + stepType: StepType +}): FormUpdater => formData => { + const { labwareEntities, pipetteEntities, stepType } = args + + const formHasMoveLabware = + formData && 'labware' in formData && stepType === 'moveLabware' + + const filteredLabware = Object.values(labwareEntities).filter( + lw => + // Filter out the tiprack, adapter, and lid entities + !lw.def?.parameters.isTiprack && + !lw.def?.allowedRoles?.includes('adapter') && + !lw.def?.allowedRoles?.includes('lid') + ) + + const filteredMoveLabware = Object.values(labwareEntities).filter( + lw => + // Filter out adapter entities + !lw.def?.allowedRoles?.includes('adapter') + ) + + const formHasAspirateLabware = formData && 'aspirate_labware' in formData + const formHasMixLabware = + formData && 'labware' in formData && stepType === 'mix' + + if (filteredLabware.length === 1 && formHasAspirateLabware) { + return handleFormChange( + { aspirate_labware: filteredLabware[0].id ?? null }, + formData, + pipetteEntities, + labwareEntities + ) + } + + if (filteredLabware.length === 1 && formHasMixLabware) { + return handleFormChange( + { labware: filteredLabware[0].id ?? null }, + formData, + pipetteEntities, + labwareEntities + ) + } + + if (filteredMoveLabware.length === 1 && formHasMoveLabware) { + return handleFormChange( + { labware: filteredMoveLabware[0].id }, + formData, + pipetteEntities, + labwareEntities + ) + } + + return null +} + const _patchDefaultMagnetFields = (args: { initialDeckSetup: InitialDeckSetup orderedStepIds: OrderedStepIdsState @@ -168,13 +228,17 @@ const _patchTemperatureModuleId = (args: { stepType: StepType }): FormUpdater => () => { const { initialDeckSetup, orderedStepIds, savedStepForms, stepType } = args + const numOfModules = + Object.values(initialDeckSetup.modules).filter( + module => module.type === TEMPERATURE_MODULE_TYPE + )?.length ?? 1 const hasTemperatureModuleId = stepType === 'pause' || stepType === 'temperature' // Auto-populate moduleId field of 'pause' and 'temperature' steps. // // Bypass dependent field changes, do not use handleFormChange - if (hasTemperatureModuleId) { + if (hasTemperatureModuleId && numOfModules === 1) { const moduleId = getNextDefaultTemperatureModuleId( savedStepForms, orderedStepIds, @@ -195,6 +259,10 @@ const _patchHeaterShakerModuleId = (args: { stepType: StepType }): FormUpdater => () => { const { initialDeckSetup, stepType } = args + const numOfModules = + Object.values(initialDeckSetup.modules).filter( + module => module.type === HEATERSHAKER_MODULE_TYPE + )?.length ?? 1 const hasHeaterShakerModuleId = stepType === 'pause' || stepType === 'heaterShaker' @@ -202,7 +270,7 @@ const _patchHeaterShakerModuleId = (args: { // Note, if both a temperature module and a heater shaker module are present, the pause form // will default to use the heater shaker // Bypass dependent field changes, do not use handleFormChange - if (hasHeaterShakerModuleId) { + if (hasHeaterShakerModuleId && numOfModules === 1) { const moduleId = getModuleOnDeckByType(initialDeckSetup, HEATERSHAKER_MODULE_TYPE)?.id ?? null @@ -273,6 +341,12 @@ export const createPresavedStepForm = ({ additionalEquipmentEntities, }) + const updateDefaultLabwareLocations = _patchDefaultLabwareLocations({ + labwareEntities, + pipetteEntities, + stepType, + }) + const updateDefaultPipette = _patchDefaultPipette({ initialDeckSetup, labwareEntities, @@ -317,6 +391,7 @@ export const createPresavedStepForm = ({ updateThermocyclerFields, updateHeaterShakerModuleId, updateMagneticModuleId, + updateDefaultLabwareLocations, ].reduce( (acc, updater: FormUpdater) => { const updates = updater(acc) diff --git a/protocol-designer/src/ui/steps/actions/__tests__/actions.test.ts b/protocol-designer/src/ui/steps/actions/__tests__/actions.test.ts index 7dbe2b12324..a4d62738ffe 100644 --- a/protocol-designer/src/ui/steps/actions/__tests__/actions.test.ts +++ b/protocol-designer/src/ui/steps/actions/__tests__/actions.test.ts @@ -7,7 +7,7 @@ import * as utils from '../../../../utils' import * as stepFormSelectors from '../../../../step-forms/selectors' import { getRobotStateTimeline } from '../../../../file-data/selectors' import { getMultiSelectLastSelected } from '../../selectors' -import { selectStep, selectAllSteps, deselectAllSteps } from '../actions' +import { selectAllSteps, deselectAllSteps } from '../actions' import { duplicateStep, duplicateMultipleSteps, @@ -52,38 +52,6 @@ const initialRobotState: RobotState = { } describe('steps actions', () => { - describe('selectStep', () => { - const stepId = 'stepId' - beforeEach(() => { - when(vi.mocked(stepFormSelectors.getSavedStepForms)) - .calledWith(expect.anything()) - .thenReturn({ - stepId: { - foo: 'getSavedStepFormsResult', - } as any, - }) - }) - afterEach(() => { - vi.resetAllMocks() - }) - // TODO(IL, 2020-04-17): also test scroll to top behavior - it('should select the step and populate the form', () => { - const store: any = mockStore() - store.dispatch(selectStep(stepId)) - expect(store.getActions()).toEqual([ - { - type: 'SELECT_STEP', - payload: stepId, - }, - { - type: 'POPULATE_FORM', - payload: { - foo: 'getSavedStepFormsResult', - }, - }, - ]) - }) - }) describe('selectAllSteps', () => { let ids: string[] beforeEach(() => { diff --git a/protocol-designer/src/ui/steps/actions/__tests__/addAndSelectStep.test.ts b/protocol-designer/src/ui/steps/actions/__tests__/addAndSelectStep.test.ts index 054133c6057..c19e9f56483 100644 --- a/protocol-designer/src/ui/steps/actions/__tests__/addAndSelectStep.test.ts +++ b/protocol-designer/src/ui/steps/actions/__tests__/addAndSelectStep.test.ts @@ -1,15 +1,19 @@ import { describe, expect, it, vi, beforeEach } from 'vitest' +import { fixture12Trough, fixtureTiprack1000ul } from '@opentrons/shared-data' import { addAndSelectStep } from '../thunks' import { PRESAVED_STEP_ID } from '../../../../steplist/types' import { addHint } from '../../../../tutorial/actions' import { selectors as labwareIngredSelectors } from '../../../../labware-ingred/selectors' import * as fileDataSelectors from '../../../../file-data/selectors' +import { getInitialDeckSetup } from '../../../../step-forms/selectors' +import type { LabwareDefinition2 } from '@opentrons/shared-data' import type { StepType } from '../../../../form-types' vi.mock('../../../../tutorial/actions') vi.mock('../../../../ui/modules/selectors') vi.mock('../../../../labware-ingred/selectors') vi.mock('../../../../file-data/selectors') +vi.mock('../../../../step-forms/selectors') const dispatch = vi.fn() const getState = vi.fn() @@ -20,6 +24,12 @@ beforeEach(() => { vi.mocked(fileDataSelectors.getRobotStateTimeline).mockReturnValue( 'mockGetRobotStateTimelineValue' as any ) + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: {}, + labware: {}, + pipettes: {}, + additionalEquipmentOnDeck: {}, + }) }) describe('addAndSelectStep', () => { it('should dispatch addStep thunk, and no hints when no hints are applicable (eg pause step)', () => { @@ -43,4 +53,310 @@ describe('addAndSelectStep', () => { ], ]) }) + it('should dispatch a thermocycler selected action if the step type is thermocycler', () => { + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: { + modId: { + type: 'thermocyclerModuleType', + id: 'modId', + slot: 'B2', + model: 'thermocyclerModuleV1', + moduleState: {} as any, + }, + }, + labware: {}, + pipettes: {}, + additionalEquipmentOnDeck: {}, + }) + const stepType: StepType = 'thermocycler' + const payload = { + stepType, + } + addAndSelectStep(payload)(dispatch, getState) + expect(dispatch.mock.calls).toEqual([ + [ + { + type: 'ADD_STEP', + payload: { + id: PRESAVED_STEP_ID, + stepType: 'thermocycler', + }, + meta: { + robotStateTimeline: 'mockGetRobotStateTimelineValue', + }, + }, + ], + [ + { + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { id: 'modId', text: 'Selected', field: '1' }, + mode: 'add', + }, + }, + ], + ]) + }) + it('should dispatch a magnet module selected action if the step type is magnet', () => { + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: { + modId: { + type: 'magneticModuleType', + id: 'modId', + slot: '1', + model: 'magneticModuleV1', + moduleState: {} as any, + }, + }, + labware: {}, + pipettes: {}, + additionalEquipmentOnDeck: {}, + }) + const stepType: StepType = 'magnet' + const payload = { + stepType, + } + addAndSelectStep(payload)(dispatch, getState) + expect(dispatch.mock.calls).toEqual([ + [ + { + type: 'ADD_STEP', + payload: { + id: PRESAVED_STEP_ID, + stepType: 'magnet', + }, + meta: { + robotStateTimeline: 'mockGetRobotStateTimelineValue', + }, + }, + ], + [ + { + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { id: 'modId', text: 'Selected', field: '1' }, + mode: 'add', + }, + }, + ], + ]) + }) + it('should dispatch a temperature module selected action if the step type is temperature and only 1 temp mod', () => { + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: { + modId: { + type: 'temperatureModuleType', + id: 'modId', + slot: 'B2', + model: 'temperatureModuleV1', + moduleState: {} as any, + }, + }, + labware: {}, + pipettes: {}, + additionalEquipmentOnDeck: {}, + }) + const stepType: StepType = 'temperature' + const payload = { + stepType, + } + addAndSelectStep(payload)(dispatch, getState) + expect(dispatch.mock.calls).toEqual([ + [ + { + type: 'ADD_STEP', + payload: { + id: PRESAVED_STEP_ID, + stepType: 'temperature', + }, + meta: { + robotStateTimeline: 'mockGetRobotStateTimelineValue', + }, + }, + ], + [ + { + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { id: 'modId', text: 'Selected', field: '1' }, + mode: 'add', + }, + }, + ], + ]) + }) + it('should not dispatch hs module selected action if the step type is hs and 2 mods', () => { + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: { + modId: { + type: 'heaterShakerModuleType', + id: 'modId', + slot: 'B2', + model: 'heaterShakerModuleV1', + moduleState: {} as any, + }, + modId2: { + type: 'heaterShakerModuleType', + id: 'modId2', + slot: 'A1', + model: 'heaterShakerModuleV1', + moduleState: {} as any, + }, + }, + labware: {}, + pipettes: {}, + additionalEquipmentOnDeck: {}, + }) + const stepType: StepType = 'heaterShaker' + const payload = { + stepType, + } + addAndSelectStep(payload)(dispatch, getState) + expect(dispatch.mock.calls).toEqual([ + [ + { + type: 'ADD_STEP', + payload: { + id: PRESAVED_STEP_ID, + stepType: 'heaterShaker', + }, + meta: { + robotStateTimeline: 'mockGetRobotStateTimelineValue', + }, + }, + ], + ]) + }) + it('should dispatch labware selected action if the step type is mix and only 1 labware', () => { + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: {}, + labware: { + labware: { + id: 'labware', + def: fixture12Trough as LabwareDefinition2, + labwareDefURI: 'mockDefUri', + slot: 'A1', + }, + labware2: { + id: 'labware2', + def: fixtureTiprack1000ul as LabwareDefinition2, + labwareDefURI: 'mockDefUri', + slot: 'B1', + }, + }, + pipettes: {}, + additionalEquipmentOnDeck: {}, + }) + const stepType: StepType = 'mix' + const payload = { + stepType, + } + addAndSelectStep(payload)(dispatch, getState) + expect(dispatch.mock.calls).toEqual([ + [ + { + type: 'ADD_STEP', + payload: { + id: PRESAVED_STEP_ID, + stepType: 'mix', + }, + meta: { + robotStateTimeline: 'mockGetRobotStateTimelineValue', + }, + }, + ], + [ + { + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { id: 'labware', text: 'Selected', field: '1' }, + mode: 'add', + }, + }, + ], + ]) + }) + it('should not dispatch labware selected action if the step type is moveLiquid and 2 labware', () => { + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: {}, + labware: { + labware: { + id: 'labware', + def: fixture12Trough as LabwareDefinition2, + labwareDefURI: 'mockDefUri', + slot: 'A1', + }, + labware2: { + id: 'labware2', + def: fixture12Trough as LabwareDefinition2, + labwareDefURI: 'mockDefUri', + slot: 'B1', + }, + }, + pipettes: {}, + additionalEquipmentOnDeck: {}, + }) + const stepType: StepType = 'moveLiquid' + const payload = { + stepType, + } + addAndSelectStep(payload)(dispatch, getState) + expect(dispatch.mock.calls).toEqual([ + [ + { + type: 'ADD_STEP', + payload: { + id: PRESAVED_STEP_ID, + stepType: 'moveLiquid', + }, + meta: { + robotStateTimeline: 'mockGetRobotStateTimelineValue', + }, + }, + ], + ]) + }) + it('should dispatch move labware selected action if the step type is moveLabware and only 1 labware', () => { + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: {}, + labware: { + labware2: { + id: 'labware2', + def: fixtureTiprack1000ul as LabwareDefinition2, + labwareDefURI: 'mockDefUri', + slot: 'B1', + }, + }, + pipettes: {}, + additionalEquipmentOnDeck: {}, + }) + const stepType: StepType = 'moveLabware' + const payload = { + stepType, + } + addAndSelectStep(payload)(dispatch, getState) + expect(dispatch.mock.calls).toEqual([ + [ + { + type: 'ADD_STEP', + payload: { + id: PRESAVED_STEP_ID, + stepType: 'moveLabware', + }, + meta: { + robotStateTimeline: 'mockGetRobotStateTimelineValue', + }, + }, + ], + [ + { + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { id: 'labware2', text: 'Selected', field: '1' }, + mode: 'add', + }, + }, + ], + ]) + }) }) diff --git a/protocol-designer/src/ui/steps/actions/actions.ts b/protocol-designer/src/ui/steps/actions/actions.ts index c85db48137d..4343760c455 100644 --- a/protocol-designer/src/ui/steps/actions/actions.ts +++ b/protocol-designer/src/ui/steps/actions/actions.ts @@ -17,15 +17,19 @@ import type { AnalyticsEventAction } from '../../../analytics/actions' import type { TerminalItemId, SubstepIdentifier } from '../../../steplist/types' import type { AddStepAction, + ClearWellSelectionLabwareKeyAction, HoverOnStepAction, HoverOnSubstepAction, - SelectTerminalItemAction, HoverOnTerminalItemAction, - SetWellSelectionLabwareKeyAction, - ClearWellSelectionLabwareKeyAction, - SelectStepAction, + hoverSelectionAction, + Mode, + selectDropdownItemAction, + Selection, SelectMultipleStepsAction, SelectMultipleStepsForGroupAction, + SelectStepAction, + SelectTerminalItemAction, + SetWellSelectionLabwareKeyAction, ToggleViewSubstepAction, ViewSubstep, } from './types' @@ -48,6 +52,28 @@ export const addStep = (args: { }, } } +export const hoverSelection = (args: Selection): hoverSelectionAction => ({ + type: 'HOVER_DROPDOWN_ITEM', + payload: { id: args.id, text: args.text }, +}) +export const selectDropdownItem = (args: { + selection: Selection | null + mode: Mode +}): selectDropdownItemAction => ({ + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: + args.selection != null + ? { + id: args.selection.id, + text: args.selection.text, + field: args.selection.field, + } + : null, + mode: args.mode, + }, +}) + export const hoverOnSubstep = ( payload: SubstepIdentifier ): HoverOnSubstepAction => ({ @@ -95,9 +121,97 @@ export const resetSelectStep = (stepId: StepIdType): ThunkAction => ( type: 'POPULATE_FORM', payload: null, }) + dispatch({ + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { + id: null, + text: null, + }, + mode: 'clear', + }, + }) resetScrollElements() } +const setSelection = ( + formData: { + [x: string]: any + stepType: StepType + id: string + }, + dispatch: ThunkDispatch +): void => { + if (formData.stepType === 'moveLabware') { + dispatch({ + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { id: formData.labware, text: 'Selected', field: '1' }, + mode: 'add', + }, + }) + dispatch({ + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { id: formData.newLocation, text: 'Location', field: '2' }, + mode: 'add', + }, + }) + } else if (formData.stepType === 'moveLiquid') { + dispatch({ + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { + id: formData.aspirate_labware, + text: 'Source', + field: '1', + }, + mode: 'add', + }, + }) + dispatch({ + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { + id: formData.dispense_labware, + text: 'Destination', + field: '2', + }, + mode: 'add', + }, + }) + } else if (formData.stepType === 'mix') { + dispatch({ + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { + id: formData.labware, + text: 'Selected', + field: '1', + }, + mode: 'add', + }, + }) + } else if ( + formData.stepType === 'heaterShaker' || + formData.stepType === 'temperature' || + formData.stepType === 'thermocycler' || + formData.stepType === 'magnet' + ) { + dispatch({ + type: 'SELECT_DROPDOWN_ITEM', + payload: { + selection: { + id: formData.moduleId, + text: 'Selected', + field: '1', + }, + mode: 'add', + }, + }) + } +} + export const populateForm = (stepId: StepIdType): ThunkAction => ( dispatch: ThunkDispatch, getState: GetState @@ -108,9 +222,9 @@ export const populateForm = (stepId: StepIdType): ThunkAction => ( type: 'POPULATE_FORM', payload: formData, }) + setSelection(formData, dispatch) resetScrollElements() } - export const selectStep = (stepId: StepIdType): ThunkAction => ( dispatch: ThunkDispatch, getState: GetState @@ -126,9 +240,8 @@ export const selectStep = (stepId: StepIdType): ThunkAction => ( type: 'POPULATE_FORM', payload: formData, }) - resetScrollElements() + setSelection(formData, dispatch) } - // NOTE(sa, 2020-12-11): this is a thunk so that we can populate the batch edit form with things later export const selectMultipleSteps = ( stepIds: StepIdType[], diff --git a/protocol-designer/src/ui/steps/actions/thunks/index.ts b/protocol-designer/src/ui/steps/actions/thunks/index.ts index 47e0d846180..edb4bf08b7f 100644 --- a/protocol-designer/src/ui/steps/actions/thunks/index.ts +++ b/protocol-designer/src/ui/steps/actions/thunks/index.ts @@ -1,16 +1,23 @@ import last from 'lodash/last' +import { + HEATERSHAKER_MODULE_TYPE, + MAGNETIC_MODULE_TYPE, + TEMPERATURE_MODULE_TYPE, + THERMOCYCLER_MODULE_TYPE, +} from '@opentrons/shared-data' import { getUnsavedForm, getUnsavedFormIsPristineSetTempForm, getUnsavedFormIsPristineHeaterShakerForm, getOrderedStepIds, + getInitialDeckSetup, } from '../../../../step-forms/selectors' import { changeFormInput } from '../../../../steplist/actions/actions' import { PRESAVED_STEP_ID } from '../../../../steplist/types' import { PAUSE_UNTIL_TEMP } from '../../../../constants' import { uuid } from '../../../../utils' import { getMultiSelectLastSelected, getSelectedStepId } from '../../selectors' -import { addStep } from '../actions' +import { addStep, selectDropdownItem } from '../actions' import { actions as tutorialActions, selectors as tutorialSelectors, @@ -23,16 +30,128 @@ import type { DuplicateMultipleStepsAction, SelectMultipleStepsAction, } from '../types' + export const addAndSelectStep: (arg: { stepType: StepType }) => ThunkAction = payload => (dispatch, getState) => { const robotStateTimeline = fileDataSelectors.getRobotStateTimeline(getState()) + const initialDeckSetup = getInitialDeckSetup(getState()) + const { modules, labware } = initialDeckSetup dispatch( addStep({ stepType: payload.stepType, robotStateTimeline, }) ) + if (payload.stepType === 'thermocycler') { + const tcId = Object.entries(modules).find( + ([key, module]) => module.type === THERMOCYCLER_MODULE_TYPE + )?.[0] + if (tcId != null) { + dispatch( + selectDropdownItem({ + selection: { + id: tcId, + text: 'Selected', + field: '1', + }, + mode: 'add', + }) + ) + } + } else if (payload.stepType === 'magnet') { + const magId = Object.entries(modules).find( + ([key, module]) => module.type === MAGNETIC_MODULE_TYPE + )?.[0] + if (magId != null) { + dispatch( + selectDropdownItem({ + selection: { + id: magId, + text: 'Selected', + field: '1', + }, + mode: 'add', + }) + ) + } + } else if (payload.stepType === 'temperature') { + const temperatureModules = Object.entries(modules).filter( + ([key, module]) => module.type === TEMPERATURE_MODULE_TYPE + ) + // only set selected temperature module if only 1 type is on deck + const tempId = + temperatureModules.length === 1 ? temperatureModules[0][0] : null + if (tempId != null) { + dispatch( + selectDropdownItem({ + selection: { + id: tempId, + text: 'Selected', + field: '1', + }, + mode: 'add', + }) + ) + } + } else if (payload.stepType === 'heaterShaker') { + const hsModules = Object.entries(modules).filter( + ([key, module]) => module.type === HEATERSHAKER_MODULE_TYPE + ) + // only set selected h-s module if only 1 type is on deck + const hsId = hsModules.length === 1 ? hsModules[0][0] : null + if (hsId != null) { + dispatch( + selectDropdownItem({ + selection: { + id: hsId, + text: 'Selected', + field: '1', + }, + mode: 'add', + }) + ) + } + } else if (payload.stepType === 'mix' || payload.stepType === 'moveLiquid') { + const labwares = Object.entries(labware).filter( + ([key, lw]) => + !lw.def.parameters.isTiprack && + !lw.def.allowedRoles?.includes('adapter') && + !lw.def.allowedRoles?.includes('lid') + ) + // only set selected labware if only 1 available labware is on deck + const labwareId = labwares.length === 1 ? labwares[0][0] : null + if (labwareId != null) { + dispatch( + selectDropdownItem({ + selection: { + id: labwareId, + text: payload.stepType === 'moveLiquid' ? 'Source' : 'Selected', + field: '1', + }, + mode: 'add', + }) + ) + } + } else if (payload.stepType === 'moveLabware') { + const labwares = Object.entries(labware).filter( + ([key, lw]) => !lw.def.allowedRoles?.includes('adapter') + ) + // only set selected labware if only 1 available labware/tiprack/lid is on deck + const labwareId = labwares.length === 1 ? labwares[0][0] : null + if (labwareId != null) { + dispatch( + selectDropdownItem({ + selection: { + id: labwareId, + text: 'Selected', + field: '1', + }, + mode: 'add', + }) + ) + } + } } export interface ReorderSelectedStepAction { type: 'REORDER_SELECTED_STEP' diff --git a/protocol-designer/src/ui/steps/actions/types.ts b/protocol-designer/src/ui/steps/actions/types.ts index ebbf1e4dff2..52556930d1d 100644 --- a/protocol-designer/src/ui/steps/actions/types.ts +++ b/protocol-designer/src/ui/steps/actions/types.ts @@ -31,6 +31,24 @@ export interface DuplicateMultipleStepsAction { indexToInsert: number } } + +export type Mode = 'clear' | 'add' +export interface Selection { + id: string | null + text: string | null + field?: '1' | '2' +} +export interface selectDropdownItemAction { + type: 'SELECT_DROPDOWN_ITEM' + payload: { + selection: Selection | null + mode: 'add' | 'clear' + } +} +export interface hoverSelectionAction { + type: 'HOVER_DROPDOWN_ITEM' + payload: Selection +} export interface HoverOnSubstepAction { type: 'HOVER_ON_SUBSTEP' payload: SubstepIdentifier diff --git a/protocol-designer/src/ui/steps/reducers.ts b/protocol-designer/src/ui/steps/reducers.ts index 0a40cb6dbe2..e281cb01bc4 100644 --- a/protocol-designer/src/ui/steps/reducers.ts +++ b/protocol-designer/src/ui/steps/reducers.ts @@ -21,6 +21,7 @@ import type { SelectStepAction, SelectMultipleStepsAction, SelectTerminalItemAction, + Selection, } from './actions/types' export type CollapsedStepsState = Record @@ -188,6 +189,50 @@ const selectedSubstep: Reducer = handleActions( }, null ) +const hoveredDropdownItem: Reducer = handleActions( + { + HOVER_DROPDOWN_ITEM: ( + state, + action: { + payload: Selection + } + ) => action.payload, + }, + { id: null, text: null } +) +const selectedDropdownItem: Reducer = handleActions( + { + SELECT_DROPDOWN_ITEM: ( + state: Selection[], + action: { + payload: { + selection: Selection | null + mode: 'add' | 'clear' + } + } + ) => { + const { selection, mode } = action.payload + + switch (mode) { + case 'clear': + return [] + case 'add': { + if (!selection) { + return state + } + const updatedState = state.filter( + sel => sel.field !== selection.field + ) + + return [...updatedState, selection] + } + default: + return state + } + }, + }, + [] +) export interface StepsState { collapsedSteps: CollapsedStepsState selectedItem: SelectedItemState @@ -195,6 +240,8 @@ export interface StepsState { hoveredSubstep: SubstepIdentifier wellSelectionLabwareKey: string | null selectedSubstep: StepIdType | null + hoveredDropdownItem: Selection + selectedDropdownItem: Selection[] } export const _allReducers = { collapsedSteps, @@ -203,6 +250,8 @@ export const _allReducers = { hoveredSubstep, wellSelectionLabwareKey, selectedSubstep, + hoveredDropdownItem, + selectedDropdownItem, } export const rootReducer: Reducer = combineReducers( _allReducers diff --git a/protocol-designer/src/ui/steps/selectors.ts b/protocol-designer/src/ui/steps/selectors.ts index 53848c4a28a..c6f48ff2f2f 100644 --- a/protocol-designer/src/ui/steps/selectors.ts +++ b/protocol-designer/src/ui/steps/selectors.ts @@ -38,6 +38,7 @@ import type { CollapsedStepsState, HoverableItem, } from './reducers' +import type { Selection } from './actions/types' export const rootSelector = (state: BaseState): StepsState => state.ui.steps // ======= Selectors =============================================== @@ -102,6 +103,14 @@ export const getHoveredStepId: Selector = createSelector( item => item && item.selectionType === SINGLE_STEP_SELECTION_TYPE ? item.id : null ) +export const getHoveredDropdownItem: Selector = createSelector( + rootSelector, + (state: StepsState) => state.hoveredDropdownItem +) +export const getSelectedDropdownItem: Selector = createSelector( + rootSelector, + (state: StepsState) => state.selectedDropdownItem +) /** Array of labware (labwareId's) involved in hovered Step, or [] */ export const getHoveredStepLabware = createSelector( diff --git a/shared-data/js/fixtures.ts b/shared-data/js/fixtures.ts index 905429cd111..51f46fdf433 100644 --- a/shared-data/js/fixtures.ts +++ b/shared-data/js/fixtures.ts @@ -295,7 +295,7 @@ export function getFixtureDisplayName( } } -const STANDARD_OT2_SLOTS: AddressableAreaName[] = [ +export const STANDARD_OT2_SLOTS: AddressableAreaName[] = [ ADDRESSABLE_AREA_1, ADDRESSABLE_AREA_2, ADDRESSABLE_AREA_3, @@ -309,7 +309,7 @@ const STANDARD_OT2_SLOTS: AddressableAreaName[] = [ ADDRESSABLE_AREA_11, ] -const STANDARD_FLEX_SLOTS: AddressableAreaName[] = [ +export const STANDARD_FLEX_SLOTS: AddressableAreaName[] = [ A1_ADDRESSABLE_AREA, A2_ADDRESSABLE_AREA, A3_ADDRESSABLE_AREA, From aa57afca31e21f5aa3e20f0651b2ae56931de45f Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:29:25 -0500 Subject: [PATCH 32/42] fix(protocol-designer): refine logic for persisted state (#17142) --- protocol-designer/src/analytics/reducers.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/protocol-designer/src/analytics/reducers.ts b/protocol-designer/src/analytics/reducers.ts index c894c6be3ce..6aff3b00a84 100644 --- a/protocol-designer/src/analytics/reducers.ts +++ b/protocol-designer/src/analytics/reducers.ts @@ -8,7 +8,7 @@ export interface OptInState { hasOptedIn: boolean appVersion?: string } -const optInInitialState = { +const optInInitialState: OptInState = { hasOptedIn: true, } @@ -23,7 +23,11 @@ const hasOptedIn: Reducer = handleActions( action: RehydratePersistedAction ) => { const persistedState = action.payload?.['analytics.hasOptedIn'] - return persistedState !== undefined ? persistedState : optInInitialState + if (persistedState == null || persistedState?.hasOptedIn == null) { + return optInInitialState + } else { + return persistedState + } }, }, optInInitialState From 60398ea2b6f177be43cd30cc054abcf9e005ac72 Mon Sep 17 00:00:00 2001 From: Alise Au <20424172+ahiuchingau@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:19:19 -0500 Subject: [PATCH 33/42] refactor: Migrate Python projects from Pydantic v1 to v2 (#14871) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Overview This updates our robot-stack Python projects from Pydantic v1 to v2. Closes PLAT-326 and GitHub issue #13983. Affected projects that run on the robot: - api - robot-server - shared-data - hardware - server-utils - system-server - performance-metrics (re-lock only, depends on shared-data) Affected projects that only run in CI and on our laptops: - g-code-testing - hardware-testing - abr-testing # Test Plan When the https://github.com/Opentrons/buildroot and https://github.com/Opentrons/oe-core changes are ready: * [x] OT-2 * [x] Make sure all servers still boot without errors (`systemctl status`) * [ ] No unexpected mismatches reported by `pip check` * I get "robot-server 8.2.0 has requirement pydantic==2.9.0, but you have pydantic 2.9.2." I think we can fix this in a follow-up. * [x] Try running a protocol or something and make sure the server doesn't return an error or take an obscenely long time to respond. * [x] Flex * [x] Make sure all servers still boot on a Flex without errors (`systemctl status`) * [x] No unexpected mismatches reported by `pip check` * [x] Try running a protocol or something and make sure the server doesn't return an error or take an obscenely long time to respond. Beyond that, this PR touches a million little things in a million little ways, so it's difficult to test. We should try to merge it early in the release cycle to give us time to shake things out. # Changelog See https://docs.pydantic.dev/latest/migration/#migration-guide for everything that has changed from Pydantic v1 to v2. The basic methodology of this PR is: * Update `setup.py`, `Pipfile`, and `Pipfile.lock` files to a new Pydantic version, trying to follow Unfortunately, FastAPI is tightly coupled to Pydantic, so we need to update it too. The FastAPI bump is kept minimal. * Run [bump-pydantic](https://github.com/pydantic/bump-pydantic) on all projects. This automatically does a lot of the grunt work, but it does need manual follow-up. * Manually fix up lots of little things * Do global find+replaces for some [trivial renames](https://docs.pydantic.dev/latest/migration/#changes-to-pydanticbasemodel). I moved some of this to [a separate PR, #17123](https://github.com/Opentrons/opentrons/pull/17123), because the GitHub web UI was struggling with the big diff. # Review requests - Do the setup.py, Pipfile, and Pipfile.lock files look good? We're trying to align on a definition of "good" [here](https://opentrons.atlassian.net/wiki/spaces/RPDO/pages/4671602797/Python+dependency+management). - Do all Pydantic migrations look correct? Reference: https://docs.pydantic.dev/latest/migration/#migration-guide - Do the rewritten validators look correct? Some of these needed manual intervention. - Do the `= None` additions look correct? `bump-pydantic` added these automatically to match prior parse behavior—see https://docs.pydantic.dev/latest/migration/#required-optional-and-nullable-fields. As far as I can tell, these additions are always safe. But defaulting to `None` may not be what we actually want, e.g. it may not match the underlying JSON schema. - This was a long-lived PR that changed hands several times, so there are definitely vestigial things left over from earlier attempts. If something looks unexplained or out of place to you, please speak up. # Risk assessment ## Performance This *will,* at least in the short term, make robot-server take much longer to start up, and make the tests much slower. This is a known Pydantic v2 problem (https://github.com/pydantic/pydantic/issues/6768 etc.). Earlier testing on a Flex found it slowed from 46s to 1m54s (2.5x). I don't think we'll be able to get it back down to Pydantic v1 times, but some proofs of concept suggest that we can mitigate it to only ~1.6x slower. There are some ideas in EXEC-1060. ## Correctness High-risk due to the breadth of changes: storage reads and writes, HTTP requests and responses, communication between the `opentrons.protocol_api` and `opentrons.protocol_engine`, ... * [Pydantic's type coercion behavior has changed](https://docs.pydantic.dev/latest/migration/#validator-behavior-changes), trending in the direction of doing less type coercion. This is a good direction, but it is basically impossible to audit affected one Python protocol in the snapshot tests—see the inline review comments below. --------- Co-authored-by: Max Marrone Co-authored-by: Seth Foster --- abr-testing/Pipfile.lock | 1539 +- ...2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift].json | 1812 +- ...2b][OT2_S_v2_7_P20S_None_Walkthrough].json | 448 +- ...B_TC_TM_DeckConfiguration1NoFixtures].json | 24 +- ...03a95825][Flex_S_v2_19_QIASeq_FX_48x].json | 306 +- ...][Flex_S_v2_18_Illumina_DNA_Prep_48x].json | 216 +- ...2_15_P300M_P20S_HS_TC_TM_SmokeTestV3].json | 36 +- ..._X_v6_P300M_P20S_HS_MM_TM_TC_AllMods].json | 240 +- ...94e3c49bb][pl_Normalization_with_PCR].json | 30 +- ..._GRIP_TC_TM_GripperCollisionWithTips].json | 42 +- ...l_Dynabeads_IP_Flex_96well_RIT_final].json | 468 +- ...5c][OT2_S_v2_4_P300M_None_MM_TM_Zymo].json | 12546 ++++---- ...c080][pl_MagMax_RNA_Cells_Flex_multi].json | 42 +- ...f51][Flex_S_v2_18_KAPA_Library_Quant].json | 84 +- ..._Omega_HDQ_DNA_Cells_Flex_96_channel].json | 66 +- ...7961bc58][pl_NiNTA_Flex_96well_final].json | 864 +- ...9][pl_Omega_HDQ_DNA_Cells_Flex_multi].json | 24 +- ...pl_Omega_HDQ_DNA_Bacteria_Flex_multi].json | 30 +- ...2bc6830494][pl_langone_ribo_pt1_ramp].json | 25943 +--------------- ...TC_TM_TriggerPrepareForMountMovement].json | 12 +- ...None_MM1_MM2_EngageMagHeightFromBase].json | 26 +- ...f][pl_Dynabeads_IP_Flex_96well_final].json | 468 +- ...fd9][Flex_S_v2_19_KAPA_Library_Quant].json | 84 +- ...2_18_P1000_96_GRIP_HS_MB_TC_TM_Smoke].json | 18 +- ...apshot[42beea80be][pl_96_ch_demo_rtp].json | 90 +- ...8][OT2_X_v6_P20S_None_SimpleTransfer].json | 10 +- ...2_16_P300M_P20S_HS_TC_TM_SmokeTestV3].json | 12 +- ...50c02c81][Flex_S_v2_19_AMPure_XP_48x].json | 90 +- ...][pl_Zymo_Quick_RNA_Cells_Flex_multi].json | 48 +- ...v6_P300M_P20S_MixTransferManyLiquids].json | 372 +- ...][Flex_S_v2_19_Illumina_DNA_Prep_48x].json | 216 +- ...ega_HDQ_DNA_Bacteria_Flex_96_channel].json | 78 +- ..._customizable_serial_dilution_upload].json | 18 +- ...b47][pl_M_N_Nucleomag_DNA_Flex_multi].json | 30 +- ...96_GRIP_HS_MB_TM_MagMaxRNAExtraction].json | 306 +- ..._HS_TM_MB_TC_IlluminaDNAEnrichmentV4].json | 504 +- ...OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix].json | 58 +- ...[pl_SamplePrep_MS_Digest_Flex_upto96].json | 816 +- ...ebdcd29][pl_KAPA_Library_Quant_48_v8].json | 84 +- ...e61426a2][Flex_S_v2_18_AMPure_XP_48x].json | 90 +- ...84cbc4][Flex_S_v2_18_IDT_xGen_EZ_48x].json | 216 +- ...2_14_P300M_P20S_HS_TC_TM_SmokeTestV3].json | 36 +- ...Zymo_Quick_RNA_Cells_Flex_96_Channel].json | 120 +- ...pl_NiNTA_Flex_96well_PlatePrep_final].json | 24 +- ...747b2f9][pl_Illumina_DNA_Prep_48x_v8].json | 216 +- ..._v3_P300SGen1_None_Gen1PipetteSimple].json | 560 +- ..._TM_MB_OmegaHDQDNAExtractionBacteria].json | 78 +- ...eckConfiguration1NoModulesNoFixtures].json | 24 +- ...pl_SamplePrep_MS_Cleanup_Flex_upto96].json | 456 +- ...4d3b3a2d3][pl_96_ch_demo_rtp_with_hs].json | 54 +- ...2_13_P300M_P20S_HS_TC_TM_SmokeTestV3].json | 906 +- ...a8a5ad823d][pl_cherrypicking_flex_v3].json | 18 +- ...shot[ac5a46e74b][pl_langone_pt2_ribo].json | 102 +- ...6_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3].json | 48 +- ...2_S_v6_P300M_P20S_HS_Smoke620release].json | 456 +- ...[pl_MagMax_RNA_Cells_Flex_96_Channel].json | 102 +- ...P1000S_None_SimpleNormalizeLongRight].json | 3456 +- ...[OT2_S_v6_P1000S_None_SimpleTransfer].json | 28 +- ..._P300M_P20S_MM_TC_TM_Smoke620Release].json | 434 +- ...d2ca0089][Flex_S_v2_18_QIASeq_FX_48x].json | 306 +- ...2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests].json | 16 +- ..._P20S_P300M_TransferReTransferLiquid].json | 1300 +- ...[cecd51c8ee][pl_ExpressPlex_96_final].json | 12 +- ...pl_Zymo_Magbead_DNA_Cells_Flex_multi].json | 30 +- ...shot[d29d74d7fb][pl_QIASeq_FX_48x_v8].json | 348 +- ...oMagbeadRNAExtractionCellsOrBacteria].json | 90 +- ...mo_Magbead_DNA_Cells_Flex_96_channel].json | 90 +- ...2_17_P300M_P20S_HS_TC_TM_SmokeTestV3].json | 12 +- ...11c5][OT2_X_v2_7_P300S_TwinningError].json | 28 +- ...39e6a3][Flex_S_v2_19_IDT_xGen_EZ_48x].json | 216 +- ...shot[d6389183c0][pl_AMPure_XP_48x_v8].json | 90 +- ...2_19_P1000_96_GRIP_HS_MB_TC_TM_Smoke].json | 18 +- ...RIP_HS_TM_MB_TC_KAPALibraryQuantv4_8].json | 162 +- ...2_S_v4_P300S_None_MM_TM_TM_MOAMTemps].json | 28 +- ...P_HS_TM_MB_TC_IlluminaDNAPrep24xV4_7].json | 342 +- ...P_HS_MB_TC_TM_IlluminaDNAPrep96PART3].json | 42 +- ...0M_P300S_HS_HS_NormalUseWithTransfer].json | 312 +- ...][OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40].json | 664 +- ...2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke].json | 12 +- ...ddbb32][pl_ExpressPlex_Pooling_Final].json | 480 +- api/Pipfile | 9 +- api/Pipfile.lock | 995 +- api/setup.py | 4 +- .../calibration_storage/deck_configuration.py | 2 +- .../calibration_storage/file_operators.py | 2 +- .../opentrons/calibration_storage/helpers.py | 4 +- .../calibration_storage/ot2/models/v1.py | 45 +- .../calibration_storage/ot2/tip_length.py | 3 +- .../calibration_storage/ot3/models/v1.py | 37 +- api/src/opentrons/cli/analyze.py | 16 +- .../opentrons/hardware_control/__init__.py | 3 +- .../hardware_control/emulation/settings.py | 7 +- .../instruments/ot2/pipette_handler.py | 2 +- .../instruments/ot3/pipette_handler.py | 2 +- .../hardware_control/modules/mod_abc.py | 4 +- .../protocol_api/core/engine/protocol.py | 5 +- .../protocol_engine/commands/__init__.py | 4 + .../commands/absorbance_reader/initialize.py | 13 +- .../commands/absorbance_reader/read.py | 12 +- .../protocol_engine/commands/aspirate.py | 2 +- .../commands/aspirate_in_place.py | 2 +- .../protocol_engine/commands/blow_out.py | 2 +- .../commands/blow_out_in_place.py | 2 +- .../commands/calibration/calibrate_gripper.py | 15 +- .../commands/calibration/calibrate_module.py | 2 +- .../commands/calibration/calibrate_pipette.py | 2 +- .../move_to_maintenance_position.py | 2 +- .../protocol_engine/commands/command.py | 132 +- .../commands/command_unions.py | 9 +- .../protocol_engine/commands/comment.py | 2 +- .../commands/configure_for_volume.py | 13 +- .../commands/configure_nozzle_layout.py | 2 +- .../protocol_engine/commands/custom.py | 16 +- .../protocol_engine/commands/dispense.py | 12 +- .../commands/dispense_in_place.py | 12 +- .../protocol_engine/commands/drop_tip.py | 16 +- .../commands/drop_tip_in_place.py | 14 +- .../commands/generate_command_schema.py | 15 +- .../protocol_engine/commands/get_next_tip.py | 11 +- .../commands/get_tip_presence.py | 2 +- .../heater_shaker/close_labware_latch.py | 2 +- .../heater_shaker/deactivate_heater.py | 2 +- .../heater_shaker/deactivate_shaker.py | 2 +- .../heater_shaker/open_labware_latch.py | 2 +- .../set_and_wait_for_shake_speed.py | 2 +- .../heater_shaker/set_target_temperature.py | 2 +- .../heater_shaker/wait_for_temperature.py | 14 +- .../protocol_engine/commands/home.py | 17 +- .../protocol_engine/commands/liquid_probe.py | 12 +- .../protocol_engine/commands/load_labware.py | 16 +- .../protocol_engine/commands/load_liquid.py | 2 +- .../commands/load_liquid_class.py | 11 +- .../protocol_engine/commands/load_module.py | 14 +- .../protocol_engine/commands/load_pipette.py | 26 +- .../commands/magnetic_module/disengage.py | 2 +- .../commands/magnetic_module/engage.py | 2 +- .../protocol_engine/commands/move_labware.py | 21 +- .../protocol_engine/commands/move_relative.py | 2 +- .../commands/move_to_addressable_area.py | 2 +- .../move_to_addressable_area_for_drop_tip.py | 18 +- .../commands/move_to_coordinates.py | 2 +- .../protocol_engine/commands/move_to_well.py | 2 +- .../commands/movement_common.py | 13 +- .../protocol_engine/commands/pick_up_tip.py | 2 +- .../commands/pipetting_common.py | 18 +- .../commands/prepare_to_aspirate.py | 2 +- .../commands/reload_labware.py | 2 +- .../protocol_engine/commands/retract_axis.py | 2 +- .../commands/robot/close_gripper_jaw.py | 15 +- .../commands/robot/move_axes_relative.py | 11 +- .../commands/robot/move_axes_to.py | 17 +- .../protocol_engine/commands/robot/move_to.py | 11 +- .../protocol_engine/commands/save_position.py | 19 +- .../commands/set_rail_lights.py | 2 +- .../commands/set_status_bar.py | 2 +- .../commands/temperature_module/deactivate.py | 2 +- .../set_target_temperature.py | 2 +- .../wait_for_temperature.py | 14 +- .../commands/thermocycler/close_lid.py | 2 +- .../commands/thermocycler/deactivate_block.py | 2 +- .../commands/thermocycler/deactivate_lid.py | 2 +- .../commands/thermocycler/open_lid.py | 2 +- .../thermocycler/run_extended_profile.py | 10 +- .../commands/thermocycler/run_profile.py | 12 +- .../set_target_block_temperature.py | 15 +- .../set_target_lid_temperature.py | 2 +- .../wait_for_block_temperature.py | 2 +- .../thermocycler/wait_for_lid_temperature.py | 2 +- .../protocol_engine/commands/touch_tip.py | 18 +- .../unsafe/unsafe_drop_tip_in_place.py | 14 +- .../commands/verify_tip_presence.py | 15 +- .../commands/wait_for_duration.py | 13 +- .../commands/wait_for_resume.py | 13 +- .../errors/error_occurrence.py | 37 +- .../protocol_engine/state/commands.py | 8 +- .../protocol_engine/state/labware.py | 12 +- .../protocol_engine/state/state_summary.py | 4 +- api/src/opentrons/protocol_engine/types.py | 57 +- .../extract_labware_definitions.py | 5 +- .../protocol_runner/json_file_reader.py | 12 +- .../protocol_runner/json_translator.py | 59 +- .../protocol_runner/legacy_command_mapper.py | 6 +- api/src/opentrons/protocols/labware.py | 18 +- .../protocols/models/json_protocol.py | 14 +- api/src/opentrons/types.py | 2 +- .../calibration_storage/test_deck_attitude.py | 2 +- .../test_instrument_calibration.py | 4 +- .../hardware_control/test_gripper.py | 7 +- .../core/engine/test_instrument_core.py | 15 +- .../core/engine/test_labware_core.py | 56 +- .../core/engine/test_module_core.py | 3 +- .../core/engine/test_protocol_core.py | 67 +- .../core/engine/test_well_core.py | 13 +- .../test_liquid_class_properties.py | 6 +- .../opentrons/protocol_api/test_validation.py | 32 +- .../clients/test_child_thread_transport.py | 3 +- .../clients/test_sync_client.py | 7 +- .../commands/test_move_labware.py | 31 +- .../opentrons/protocol_engine/conftest.py | 18 +- .../errors/test_error_occurrence.py | 5 +- .../execution/test_command_executor.py | 43 +- .../execution/test_equipment_handler.py | 3 +- .../execution/test_tip_handler.py | 3 +- .../resources/test_labware_validation.py | 70 +- .../protocol_engine/state/command_fixtures.py | 23 +- .../state/test_addressable_area_store_old.py | 2 +- .../state/test_geometry_view.py | 31 +- .../state/test_labware_view_old.py | 74 +- .../state/test_liquid_class_store_old.py | 2 +- .../state/test_module_store_old.py | 44 +- .../state/test_module_view_old.py | 10 +- .../state/test_pipette_store_old.py | 4 +- .../protocol_engine/state/test_tip_state.py | 15 +- .../protocol_engine/test_protocol_engine.py | 5 +- .../opentrons/protocol_engine/test_types.py | 10 +- .../protocol_runner/smoke_tests/conftest.py | 2 +- .../smoke_tests/test_legacy_command_mapper.py | 14 +- .../test_legacy_module_commands.py | 11 +- .../protocol_runner/test_json_translator.py | 31 +- .../protocol_runner/test_protocol_runner.py | 24 +- g-code-testing/Pipfile | 2 +- g-code-testing/Pipfile.lock | 332 +- .../g_code_test_data/g_code_configuration.py | 31 +- hardware-testing/Pipfile | 2 +- hardware-testing/Pipfile.lock | 842 +- .../opentrons_api/helpers_ot3.py | 14 +- .../opentrons_api/p1000_gen3_ul_per_mm.py | 2 +- .../production_qc/firmware_check.py | 4 +- .../robot_assembly_qc_ot3/test_instruments.py | 2 +- hardware-testing/mypy.ini | 1 + hardware/Pipfile | 5 +- hardware/Pipfile.lock | 1485 +- hardware/mypy.ini | 3 - .../drivers/can_bus/settings.py | 25 +- hardware/setup.py | 2 + performance-metrics/Pipfile | 2 +- performance-metrics/Pipfile.lock | 70 +- .../system_resource_tracker/__main__.py | 2 +- robot-server/Config.in | 1 + robot-server/Pipfile | 16 +- robot-server/Pipfile.lock | 1722 +- robot-server/opentrons-robot-server.service | 2 +- .../robot_server/errors/error_responses.py | 26 +- robot-server/robot_server/health/models.py | 18 +- robot-server/robot_server/health/router.py | 4 + .../instruments/instrument_models.py | 14 +- .../robot_server/modules/module_models.py | 3 +- .../_migrations/_up_to_3_worker.py | 6 +- .../robot_server/persistence/pydantic.py | 27 +- .../robot_server/protocols/protocol_models.py | 10 +- .../robot/calibration/check/models.py | 22 +- .../robot/calibration/deck/models.py | 8 +- .../calibration/pipette_offset/models.py | 8 +- .../robot/calibration/tip_length/models.py | 8 +- .../robot_server/robot/calibration/util.py | 2 +- .../runs/router/labware_router.py | 1 + robot-server/robot_server/runs/run_store.py | 20 +- .../robot_server/service/json_api/request.py | 5 +- .../robot_server/service/json_api/response.py | 36 +- .../robot_server/service/labware/models.py | 8 +- .../service/legacy/models/control.py | 28 +- .../service/legacy/models/deck_calibration.py | 6 +- .../service/legacy/models/modules.py | 22 +- .../service/legacy/models/motors.py | 11 +- .../service/legacy/models/networking.py | 50 +- .../service/legacy/models/pipettes.py | 8 +- .../service/legacy/models/settings.py | 18 +- .../service/legacy/routers/networking.py | 4 +- .../service/legacy/routers/settings.py | 2 +- .../service/pipette_offset/models.py | 2 +- .../service/session/models/command.py | 8 +- .../service/session/models/common.py | 2 +- .../service/session/models/session.py | 2 +- .../robot_server/service/session/router.py | 2 +- .../robot_server/service/tip_length/models.py | 2 +- robot-server/robot_server/settings.py | 12 +- robot-server/scripts/spec_generator.py | 12 +- robot-server/setup.py | 5 +- robot-server/tests/conftest.py | 21 + .../tests/errors/test_exception_handlers.py | 28 +- .../http_api/runs/test_persistence.py | 15 +- .../tests/integration/robot_client.py | 2 +- .../system/test_system_time.tavern.yaml | 8 - .../integration/test_identify.tavern.yaml | 7 +- .../test_settings_log_level.tavern.yaml | 28 +- .../test_settings_reset_options.tavern.yaml | 3 - .../maintenance_runs/test_run_data_manager.py | 17 +- .../tests/persistence/test_pydantic.py | 35 + .../tests/runs/router/test_base_router.py | 2 + .../tests/runs/router/test_labware_router.py | 11 +- .../tests/runs/test_error_recovery_mapping.py | 8 +- .../tests/runs/test_run_controller.py | 2 +- .../tests/runs/test_run_data_manager.py | 57 +- robot-server/tests/runs/test_run_store.py | 29 +- .../tests/service/json_api/test_request.py | 30 +- .../service/json_api/test_resource_links.py | 8 +- .../service/legacy/models/test_control.py | 4 +- .../service/legacy/routers/test_settings.py | 2 +- robot-server/tests/subsystems/test_router.py | 2 +- .../tests/system/test_system_router.py | 18 +- server-utils/Pipfile | 2 +- server-utils/Pipfile.lock | 425 +- server-utils/setup.py | 4 +- shared-data/command/schemas/11.json | 8868 +++--- shared-data/python/Pipfile | 4 +- shared-data/python/Pipfile.lock | 974 +- shared-data/python/mypy.ini | 19 - .../gripper/gripper_definition.py | 32 +- .../labware/labware_definition.py | 44 +- .../liquid_classes/liquid_class_definition.py | 79 +- .../opentrons_shared_data/pipette/__init__.py | 6 +- .../pipette/pipette_definition.py | 79 +- .../scripts/update_configuration_files.py | 22 +- .../protocol/models/__init__.py | 3 +- .../protocol/models/protocol_schema_v6.py | 114 +- .../protocol/models/protocol_schema_v7.py | 107 +- .../protocol/models/protocol_schema_v8.py | 19 +- .../protocol/models/shared_models.py | 57 +- shared-data/python/setup.py | 4 +- .../python/tests/deck/test_typechecks.py | 4 +- .../python/tests/labware/test_typechecks.py | 2 +- .../python/tests/pipette/test_typechecks.py | 14 +- .../tests/pipette/test_validate_schema.py | 55 +- .../tests/protocol/test_protocol_schema_v6.py | 5 +- .../tests/protocol/test_protocol_schema_v7.py | 5 +- .../tests/protocol/test_protocol_schema_v8.py | 13 +- .../python/tests/protocol/test_typechecks.py | 7 +- system-server/Pipfile | 7 +- system-server/Pipfile.lock | 672 +- system-server/setup.py | 1 + .../system_server/settings/settings.py | 20 +- update-server/Pipfile | 2 +- update-server/Pipfile.lock | 571 +- .../otupdate/common/update_actions.py | 4 +- usb-bridge/Pipfile | 2 +- usb-bridge/Pipfile.lock | 556 +- 336 files changed, 28385 insertions(+), 52676 deletions(-) create mode 100644 robot-server/tests/persistence/test_pydantic.py diff --git a/abr-testing/Pipfile.lock b/abr-testing/Pipfile.lock index a1b677f52bb..a2f82b44925 100644 --- a/abr-testing/Pipfile.lock +++ b/abr-testing/Pipfile.lock @@ -22,108 +22,93 @@ }, "aiohappyeyeballs": { "hashes": [ - "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", - "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572" + "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745", + "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8" ], "markers": "python_version >= '3.8'", - "version": "==2.4.3" + "version": "==2.4.4" }, "aiohttp": { "hashes": [ - "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", - "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c", - "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24", - "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480", - "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2", - "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5", - "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", - "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", - "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", - "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", - "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486", - "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", - "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", - "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", - "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68", - "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1", - "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d", - "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd", - "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", - "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8", - "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7", - "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", - "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7", - "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", - "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", - "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", - "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", - "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", - "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8", - "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", - "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", - "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", - "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", - "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce", - "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b", - "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8", - "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", - "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", - "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a", - "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", - "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", - "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab", - "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", - "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", - "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9", - "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572", - "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554", - "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d", - "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257", - "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", - "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b", - "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", - "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090", - "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6", - "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc", - "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", - "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", - "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", - "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", - "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", - "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", - "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026", - "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb", - "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", - "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", - "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", - "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f", - "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983", - "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", - "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", - "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa", - "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c", - "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2", - "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", - "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", - "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762", - "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a", - "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8", - "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", - "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", - "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc", - "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91", - "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23", - "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527", - "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", - "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", - "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7", - "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f", - "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a", - "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", - "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414" + "sha256:012f176945af138abc10c4a48743327a92b4ca9adc7a0e078077cdb5dbab7be0", + "sha256:02c13415b5732fb6ee7ff64583a5e6ed1c57aa68f17d2bda79c04888dfdc2769", + "sha256:03b6002e20938fc6ee0918c81d9e776bebccc84690e2b03ed132331cca065ee5", + "sha256:04814571cb72d65a6899db6099e377ed00710bf2e3eafd2985166f2918beaf59", + "sha256:0580f2e12de2138f34debcd5d88894786453a76e98febaf3e8fe5db62d01c9bf", + "sha256:06a8e2ee1cbac16fe61e51e0b0c269400e781b13bcfc33f5425912391a542985", + "sha256:076bc454a7e6fd646bc82ea7f98296be0b1219b5e3ef8a488afbdd8e81fbac50", + "sha256:0c9527819b29cd2b9f52033e7fb9ff08073df49b4799c89cb5754624ecd98299", + "sha256:0dc49f42422163efb7e6f1df2636fe3db72713f6cd94688e339dbe33fe06d61d", + "sha256:14cdb5a9570be5a04eec2ace174a48ae85833c2aadc86de68f55541f66ce42ab", + "sha256:15fccaf62a4889527539ecb86834084ecf6e9ea70588efde86e8bc775e0e7542", + "sha256:24213ba85a419103e641e55c27dc7ff03536c4873470c2478cce3311ba1eee7b", + "sha256:31d5093d3acd02b31c649d3a69bb072d539d4c7659b87caa4f6d2bcf57c2fa2b", + "sha256:3691ed7726fef54e928fe26344d930c0c8575bc968c3e239c2e1a04bd8cf7838", + "sha256:386fbe79863eb564e9f3615b959e28b222259da0c48fd1be5929ac838bc65683", + "sha256:3bbbfff4c679c64e6e23cb213f57cc2c9165c9a65d63717108a644eb5a7398df", + "sha256:3de34936eb1a647aa919655ff8d38b618e9f6b7f250cc19a57a4bf7fd2062b6d", + "sha256:40d1c7a7f750b5648642586ba7206999650208dbe5afbcc5284bcec6579c9b91", + "sha256:44224d815853962f48fe124748227773acd9686eba6dc102578defd6fc99e8d9", + "sha256:47ad15a65fb41c570cd0ad9a9ff8012489e68176e7207ec7b82a0940dddfd8be", + "sha256:482cafb7dc886bebeb6c9ba7925e03591a62ab34298ee70d3dd47ba966370d2c", + "sha256:49c7dbbc1a559ae14fc48387a115b7d4bbc84b4a2c3b9299c31696953c2a5219", + "sha256:4b2c7ac59c5698a7a8207ba72d9e9c15b0fc484a560be0788b31312c2c5504e4", + "sha256:4cca22a61b7fe45da8fc73c3443150c3608750bbe27641fc7558ec5117b27fdf", + "sha256:4cfce37f31f20800a6a6620ce2cdd6737b82e42e06e6e9bd1b36f546feb3c44f", + "sha256:502a1464ccbc800b4b1995b302efaf426e8763fadf185e933c2931df7db9a199", + "sha256:53bf2097e05c2accc166c142a2090e4c6fd86581bde3fd9b2d3f9e93dda66ac1", + "sha256:593c114a2221444f30749cc5e5f4012488f56bd14de2af44fe23e1e9894a9c60", + "sha256:5d6958671b296febe7f5f859bea581a21c1d05430d1bbdcf2b393599b1cdce77", + "sha256:5ef359ebc6949e3a34c65ce20230fae70920714367c63afd80ea0c2702902ccf", + "sha256:613e5169f8ae77b1933e42e418a95931fb4867b2991fc311430b15901ed67079", + "sha256:61b9bae80ed1f338c42f57c16918853dc51775fb5cb61da70d590de14d8b5fb4", + "sha256:6362cc6c23c08d18ddbf0e8c4d5159b5df74fea1a5278ff4f2c79aed3f4e9f46", + "sha256:65a96e3e03300b41f261bbfd40dfdbf1c301e87eab7cd61c054b1f2e7c89b9e8", + "sha256:65e55ca7debae8faaffee0ebb4b47a51b4075f01e9b641c31e554fd376595c6c", + "sha256:68386d78743e6570f054fe7949d6cb37ef2b672b4d3405ce91fafa996f7d9b4d", + "sha256:68ff6f48b51bd78ea92b31079817aff539f6c8fc80b6b8d6ca347d7c02384e33", + "sha256:6ab29b8a0beb6f8eaf1e5049252cfe74adbaafd39ba91e10f18caeb0e99ffb34", + "sha256:77ae58586930ee6b2b6f696c82cf8e78c8016ec4795c53e36718365f6959dc82", + "sha256:77c4aa15a89847b9891abf97f3d4048f3c2d667e00f8a623c89ad2dccee6771b", + "sha256:78153314f26d5abef3239b4a9af20c229c6f3ecb97d4c1c01b22c4f87669820c", + "sha256:7852bbcb4d0d2f0c4d583f40c3bc750ee033265d80598d0f9cb6f372baa6b836", + "sha256:7e97d622cb083e86f18317282084bc9fbf261801b0192c34fe4b1febd9f7ae69", + "sha256:7f3dc0e330575f5b134918976a645e79adf333c0a1439dcf6899a80776c9ab39", + "sha256:80886dac673ceaef499de2f393fc80bb4481a129e6cb29e624a12e3296cc088f", + "sha256:811f23b3351ca532af598405db1093f018edf81368e689d1b508c57dcc6b6a32", + "sha256:86a5dfcc39309470bd7b68c591d84056d195428d5d2e0b5ccadfbaf25b026ebc", + "sha256:8b3cf2dc0f0690a33f2d2b2cb15db87a65f1c609f53c37e226f84edb08d10f52", + "sha256:8cc5203b817b748adccb07f36390feb730b1bc5f56683445bfe924fc270b8816", + "sha256:909af95a72cedbefe5596f0bdf3055740f96c1a4baa0dd11fd74ca4de0b4e3f1", + "sha256:974d3a2cce5fcfa32f06b13ccc8f20c6ad9c51802bb7f829eae8a1845c4019ec", + "sha256:98283b94cc0e11c73acaf1c9698dea80c830ca476492c0fe2622bd931f34b487", + "sha256:98f5635f7b74bcd4f6f72fcd85bea2154b323a9f05226a80bc7398d0c90763b0", + "sha256:99b7920e7165be5a9e9a3a7f1b680f06f68ff0d0328ff4079e5163990d046767", + "sha256:9bca390cb247dbfaec3c664326e034ef23882c3f3bfa5fbf0b56cad0320aaca5", + "sha256:9e2e576caec5c6a6b93f41626c9c02fc87cd91538b81a3670b2e04452a63def6", + "sha256:9ef405356ba989fb57f84cac66f7b0260772836191ccefbb987f414bcd2979d9", + "sha256:a55d2ad345684e7c3dd2c20d2f9572e9e1d5446d57200ff630e6ede7612e307f", + "sha256:ab7485222db0959a87fbe8125e233b5a6f01f4400785b36e8a7878170d8c3138", + "sha256:b1fc6b45010a8d0ff9e88f9f2418c6fd408c99c211257334aff41597ebece42e", + "sha256:b78f053a7ecfc35f0451d961dacdc671f4bcbc2f58241a7c820e9d82559844cf", + "sha256:b99acd4730ad1b196bfb03ee0803e4adac371ae8efa7e1cbc820200fc5ded109", + "sha256:be2b516f56ea883a3e14dda17059716593526e10fb6303189aaf5503937db408", + "sha256:beb39a6d60a709ae3fb3516a1581777e7e8b76933bb88c8f4420d875bb0267c6", + "sha256:bf3d1a519a324af764a46da4115bdbd566b3c73fb793ffb97f9111dbc684fc4d", + "sha256:c49a76c1038c2dd116fa443eba26bbb8e6c37e924e2513574856de3b6516be99", + "sha256:c5532f0441fc09c119e1dca18fbc0687e64fbeb45aa4d6a87211ceaee50a74c4", + "sha256:c6b9e6d7e41656d78e37ce754813fa44b455c3d0d0dced2a047def7dc5570b74", + "sha256:c87bf31b7fdab94ae3adbe4a48e711bfc5f89d21cf4c197e75561def39e223bc", + "sha256:cbad88a61fa743c5d283ad501b01c153820734118b65aee2bd7dbb735475ce0d", + "sha256:cf14627232dfa8730453752e9cdc210966490992234d77ff90bc8dc0dce361d5", + "sha256:db1d0b28fcb7f1d35600150c3e4b490775251dea70f894bf15c678fdd84eda6a", + "sha256:ddf5f7d877615f6a1e75971bfa5ac88609af3b74796ff3e06879e8422729fd01", + "sha256:e44a9a3c053b90c6f09b1bb4edd880959f5328cf63052503f892c41ea786d99f", + "sha256:efb15a17a12497685304b2d976cb4939e55137df7b09fa53f1b6a023f01fcb4e", + "sha256:fbbaea811a2bba171197b08eea288b9402faa2bab2ba0858eecdd0a4105753a3" ], - "markers": "python_version >= '3.8'", - "version": "==3.10.10" + "markers": "python_version >= '3.9'", + "version": "==3.11.10" }, "aionotify": { "hashes": [ @@ -141,6 +126,14 @@ "markers": "python_version >= '3.7'", "version": "==1.3.1" }, + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "anyio": { "hashes": [ "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780", @@ -151,11 +144,11 @@ }, "async-timeout": { "hashes": [ - "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", - "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028" + "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", + "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3" ], - "markers": "python_version < '3.11'", - "version": "==4.0.3" + "markers": "python_version >= '3.8'", + "version": "==5.0.1" }, "attrs": { "hashes": [ @@ -167,36 +160,34 @@ }, "bcrypt": { "hashes": [ - "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", - "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", - "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", - "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", - "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", - "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170", - "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", - "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", - "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", - "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184", - "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a", - "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", - "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", - "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", - "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", - "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", - "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", - "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", - "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", - "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", - "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", - "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", - "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", - "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", - "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", - "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", - "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db" + "sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837", + "sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6", + "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17", + "sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99", + "sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe", + "sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54", + "sha256:76132c176a6d9953cdc83c296aeaed65e1a708485fd55abf163e0d9f8f16ce0e", + "sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396", + "sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d", + "sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685", + "sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413", + "sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526", + "sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad", + "sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a", + "sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea", + "sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005", + "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f", + "sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf", + "sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425", + "sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84", + "sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c", + "sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139", + "sha256:e158009a54c4c8bc91d5e0da80920d048f918c61a581f0a63e4e93bb556d362f", + "sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c", + "sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331" ], "markers": "python_version >= '3.7'", - "version": "==4.2.0" + "version": "==4.2.1" }, "cachetools": { "hashes": [ @@ -284,7 +275,7 @@ "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" ], - "markers": "platform_python_implementation != 'PyPy'", + "markers": "python_version >= '3.8'", "version": "==1.17.1" }, "charset-normalizer": { @@ -406,53 +397,45 @@ "markers": "python_version >= '3.7'", "version": "==8.1.7" }, - "colorama": { - "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - ], - "markers": "platform_system == 'Windows'", - "version": "==0.4.6" - }, "cryptography": { "hashes": [ - "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", - "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", - "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa", - "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83", - "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff", - "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", - "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", - "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664", - "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08", - "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", - "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", - "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", - "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", - "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", - "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", - "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", - "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3", - "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", - "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", - "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", - "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c", - "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", - "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", - "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", - "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7", - "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", - "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7" - ], - "markers": "python_version >= '3.7'", - "version": "==43.0.3" + "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", + "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731", + "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", + "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", + "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", + "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c", + "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", + "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", + "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", + "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", + "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", + "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c", + "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", + "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", + "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", + "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", + "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa", + "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", + "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", + "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", + "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", + "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", + "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", + "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", + "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", + "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756", + "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4" + ], + "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'", + "version": "==44.0.0" }, "exceptiongroup": { "hashes": [ "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], - "markers": "python_version < '3.11'", + "markers": "python_version >= '3.7'", "version": "==1.2.2" }, "frozenlist": { @@ -555,20 +538,20 @@ }, "google-api-core": { "hashes": [ - "sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35", - "sha256:a6652b6bd51303902494998626653671703c420f6f4c88cfd3f50ed723e9d021" + "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9", + "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf" ], "markers": "python_version >= '3.7'", - "version": "==2.22.0" + "version": "==2.24.0" }, "google-api-python-client": { "hashes": [ - "sha256:4427b2f47cd88b0355d540c2c52215f68c337f3bc9d6aae1ceeae4525977504c", - "sha256:a9d26d630810ed4631aea21d1de3e42072f98240aaf184a8a1a874a371115034" + "sha256:1b420062e03bfcaa1c79e2e00a612d29a6a934151ceb3d272fe150a656dc8f17", + "sha256:a521bbbb2ec0ba9d6f307cdd64ed6e21eeac372d1bd7493a4ab5022941f784ad" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==2.151.0" + "version": "==2.154.0" }, "google-auth": { "hashes": [ @@ -595,11 +578,11 @@ }, "googleapis-common-protos": { "hashes": [ - "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63", - "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0" + "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c", + "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed" ], "markers": "python_version >= '3.7'", - "version": "==1.65.0" + "version": "==1.66.0" }, "gspread": { "hashes": [ @@ -633,11 +616,81 @@ }, "jsonschema": { "hashes": [ - "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d", - "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6" + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" ], - "markers": "python_version >= '3.7'", - "version": "==4.17.3" + "markers": "python_version >= '3.8'", + "version": "==4.23.0" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", + "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.10.1" + }, + "msgpack": { + "hashes": [ + "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982", + "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3", + "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40", + "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee", + "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693", + "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950", + "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151", + "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24", + "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305", + "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b", + "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c", + "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659", + "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d", + "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18", + "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746", + "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868", + "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2", + "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba", + "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228", + "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2", + "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273", + "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c", + "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653", + "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a", + "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596", + "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd", + "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8", + "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa", + "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85", + "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc", + "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836", + "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3", + "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58", + "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128", + "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db", + "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f", + "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77", + "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad", + "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13", + "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8", + "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b", + "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a", + "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543", + "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b", + "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce", + "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d", + "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a", + "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c", + "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f", + "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e", + "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011", + "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04", + "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480", + "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a", + "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d", + "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d" + ], + "markers": "python_version >= '3.8'", + "version": "==1.0.8" }, "multidict": { "hashes": [ @@ -776,7 +829,7 @@ "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" ], - "markers": "python_version < '3.11'", + "markers": "python_version >= '3.9'", "version": "==1.26.4" }, "oauth2client": { @@ -817,11 +870,11 @@ }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "pandas": { "hashes": [ @@ -874,12 +927,12 @@ }, "pandas-stubs": { "hashes": [ - "sha256:3a6f8f142105a42550be677ba741ba532621f4e0acad2155c0e7b2450f114cfa", - "sha256:d4ab618253f0acf78a5d0d2bfd6dffdd92d91a56a69bdc8144e5a5c6d25be3b5" + "sha256:74aa79c167af374fe97068acc90776c0ebec5266a6e5c69fe11e9c2cf51f2267", + "sha256:cf819383c6d9ae7d4dabf34cd47e1e45525bb2f312e6ad2939c2c204cb708acd" ], "index": "pypi", "markers": "python_version >= '3.10'", - "version": "==2.2.3.241009" + "version": "==2.2.3.241126" }, "paramiko": { "hashes": [ @@ -900,107 +953,91 @@ }, "propcache": { "hashes": [ - "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", - "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", - "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", - "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb", - "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", - "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", - "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957", - "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68", - "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f", - "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798", - "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418", - "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6", - "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162", - "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", - "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", - "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", - "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", - "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110", - "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", - "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8", - "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638", - "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a", - "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", - "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", - "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", - "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850", - "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", - "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", - "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", - "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89", - "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", - "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", - "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", - "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861", - "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", - "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", - "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b", - "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", - "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", - "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", - "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", - "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563", - "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5", - "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", - "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9", - "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12", - "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", - "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", - "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", - "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9", - "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed", - "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336", - "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90", - "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063", - "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad", - "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6", - "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8", - "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", - "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", - "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", - "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", - "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", - "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df", - "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b", - "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", - "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2", - "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630", - "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48", - "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61", - "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", - "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", - "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", - "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6", - "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562", - "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", - "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58", - "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", - "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99", - "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37", - "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", - "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", - "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d", - "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04", - "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", - "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", - "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394", - "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea", - "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", - "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1", - "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", - "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577", - "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7", - "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", - "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d", - "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", - "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d", - "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", - "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504" + "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4", + "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", + "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", + "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f", + "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9", + "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", + "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e", + "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", + "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf", + "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034", + "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", + "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16", + "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30", + "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba", + "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95", + "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d", + "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae", + "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", + "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2", + "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", + "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce", + "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54", + "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629", + "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", + "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1", + "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b", + "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf", + "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b", + "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587", + "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097", + "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea", + "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", + "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7", + "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541", + "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6", + "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634", + "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3", + "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d", + "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034", + "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465", + "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2", + "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf", + "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1", + "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04", + "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", + "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583", + "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb", + "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b", + "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c", + "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958", + "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc", + "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4", + "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82", + "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e", + "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce", + "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9", + "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", + "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536", + "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505", + "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052", + "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", + "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", + "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f", + "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681", + "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347", + "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af", + "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", + "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787", + "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", + "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", + "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439", + "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3", + "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6", + "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca", + "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", + "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d", + "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3", + "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16", + "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717", + "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", + "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd", + "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212" ], - "markers": "python_version >= '3.8'", - "version": "==0.2.0" + "markers": "python_version >= '3.9'", + "version": "==0.2.1" }, "proto-plus": { "hashes": [ @@ -1012,20 +1049,20 @@ }, "protobuf": { "hashes": [ - "sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24", - "sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535", - "sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b", - "sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548", - "sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584", - "sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b", - "sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36", - "sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135", - "sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868", - "sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687", - "sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed" + "sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c", + "sha256:027fbcc48cea65a6b17028510fdd054147057fa78f4772eb547b9274e5219331", + "sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34", + "sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110", + "sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0", + "sha256:50879eb0eb1246e3a5eabbbe566b44b10348939b7cc1b267567e8c3d07213853", + "sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57", + "sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb", + "sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d", + "sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155", + "sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18" ], "markers": "python_version >= '3.8'", - "version": "==5.28.3" + "version": "==5.29.1" }, "pyasn1": { "hashes": [ @@ -1053,52 +1090,125 @@ }, "pydantic": { "hashes": [ - "sha256:0399094464ae7f28482de22383e667625e38e1516d6b213176df1acdd0c477ea", - "sha256:076c49e24b73d346c45f9282d00dbfc16eef7ae27c970583d499f11110d9e5b0", - "sha256:07d00ca5ef0de65dd274005433ce2bb623730271d495a7d190a91c19c5679d34", - "sha256:0890fbd7fec9e151c7512941243d830b2d6076d5df159a2030952d480ab80a4e", - "sha256:0bfb5b378b78229119d66ced6adac2e933c67a0aa1d0a7adffbe432f3ec14ce4", - "sha256:0d32227ea9a3bf537a2273fd2fdb6d64ab4d9b83acd9e4e09310a777baaabb98", - "sha256:11965f421f7eb026439d4eb7464e9182fe6d69c3d4d416e464a4485d1ba61ab6", - "sha256:1fc8cc264afaf47ae6a9bcbd36c018d0c6b89293835d7fb0e5e1a95898062d59", - "sha256:2206a1752d9fac011e95ca83926a269fb0ef5536f7e053966d058316e24d929f", - "sha256:22a1794e01591884741be56c6fba157c4e99dcc9244beb5a87bd4aa54b84ea8b", - "sha256:4739c206bfb6bb2bdc78dcd40bfcebb2361add4ceac6d170e741bb914e9eff0f", - "sha256:4a5d5b877c7d3d9e17399571a8ab042081d22fe6904416a8b20f8af5909e6c8f", - "sha256:566bebdbe6bc0ac593fa0f67d62febbad9f8be5433f686dc56401ba4aab034e3", - "sha256:570ad0aeaf98b5e33ff41af75aba2ef6604ee25ce0431ecd734a28e74a208555", - "sha256:573254d844f3e64093f72fcd922561d9c5696821ff0900a0db989d8c06ab0c25", - "sha256:5d4320510682d5a6c88766b2a286d03b87bd3562bf8d78c73d63bab04b21e7b4", - "sha256:6d8a38a44bb6a15810084316ed69c854a7c06e0c99c5429f1d664ad52cec353c", - "sha256:6eb56074b11a696e0b66c7181da682e88c00e5cebe6570af8013fcae5e63e186", - "sha256:7e66aa0fa7f8aa9d0a620361834f6eb60d01d3e9cea23ca1a92cda99e6f61dac", - "sha256:7ea24e8614f541d69ea72759ff635df0e612b7dc9d264d43f51364df310081a3", - "sha256:7f31742c95e3f9443b8c6fa07c119623e61d76603be9c0d390bcf7e888acabcb", - "sha256:83ee8c9916689f8e6e7d90161e6663ac876be2efd32f61fdcfa3a15e87d4e413", - "sha256:8b2cf5e26da84f2d2dee3f60a3f1782adedcee785567a19b68d0af7e1534bd1f", - "sha256:945407f4d08cd12485757a281fca0e5b41408606228612f421aa4ea1b63a095d", - "sha256:9c46f58ef2df958ed2ea7437a8be0897d5efe9ee480818405338c7da88186fb3", - "sha256:9d7d48fbc5289efd23982a0d68e973a1f37d49064ccd36d86de4543aff21e086", - "sha256:9f28a81978e936136c44e6a70c65bde7548d87f3807260f73aeffbf76fb94c2f", - "sha256:a415b9e95fa602b10808113967f72b2da8722061265d6af69268c111c254832d", - "sha256:a82746c6d6e91ca17e75f7f333ed41d70fce93af520a8437821dec3ee52dfb10", - "sha256:ad57004e5d73aee36f1e25e4e73a4bc853b473a1c30f652dc8d86b0a987ffce3", - "sha256:c6444368b651a14c2ce2fb22145e1496f7ab23cbdb978590d47c8d34a7bc0289", - "sha256:d216f8d0484d88ab72ab45d699ac669fe031275e3fa6553e3804e69485449fa0", - "sha256:d3449633c207ec3d2d672eedb3edbe753e29bd4e22d2e42a37a2c1406564c20f", - "sha256:d5b5b7c6bafaef90cbb7dafcb225b763edd71d9e22489647ee7df49d6d341890", - "sha256:d7a8a1dd68bac29f08f0a3147de1885f4dccec35d4ea926e6e637fac03cdb4b3", - "sha256:d8d72553d2f3f57ce547de4fa7dc8e3859927784ab2c88343f1fc1360ff17a08", - "sha256:dce355fe7ae53e3090f7f5fa242423c3a7b53260747aa398b4b3aaf8b25f41c3", - "sha256:e351df83d1c9cffa53d4e779009a093be70f1d5c6bb7068584086f6a19042526", - "sha256:ec5c44e6e9eac5128a9bfd21610df3b8c6b17343285cc185105686888dc81206", - "sha256:f5bb81fcfc6d5bff62cd786cbd87480a11d23f16d5376ad2e057c02b3b44df96", - "sha256:fd34012691fbd4e67bdf4accb1f0682342101015b78327eaae3543583fcd451e", - "sha256:fea36c2065b7a1d28c6819cc2e93387b43dd5d3cf5a1e82d8132ee23f36d1f10", - "sha256:ff09600cebe957ecbb4a27496fe34c1d449e7957ed20a202d5029a71a8af2e35" + "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d", + "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9" ], - "markers": "python_version >= '3.7'", - "version": "==1.10.19" + "markers": "python_version >= '3.8'", + "version": "==2.10.3" + }, + "pydantic-core": { + "hashes": [ + "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9", + "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b", + "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c", + "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529", + "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc", + "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854", + "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d", + "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278", + "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a", + "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c", + "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f", + "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27", + "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f", + "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac", + "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2", + "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97", + "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a", + "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919", + "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9", + "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4", + "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c", + "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131", + "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5", + "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd", + "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089", + "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107", + "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6", + "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60", + "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf", + "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5", + "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08", + "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05", + "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2", + "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e", + "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c", + "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17", + "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62", + "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23", + "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be", + "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067", + "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02", + "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f", + "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235", + "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840", + "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5", + "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807", + "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16", + "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c", + "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864", + "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e", + "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a", + "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35", + "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737", + "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a", + "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3", + "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52", + "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05", + "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31", + "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89", + "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de", + "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6", + "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36", + "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c", + "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154", + "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb", + "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e", + "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd", + "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3", + "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f", + "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78", + "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960", + "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618", + "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08", + "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4", + "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c", + "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c", + "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330", + "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8", + "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792", + "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025", + "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9", + "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f", + "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01", + "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337", + "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4", + "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f", + "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd", + "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51", + "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab", + "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc", + "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676", + "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381", + "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed", + "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb", + "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967", + "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073", + "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae", + "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c", + "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206", + "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b" + ], + "markers": "python_version >= '3.8'", + "version": "==2.27.1" + }, + "pydantic-settings": { + "hashes": [ + "sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87", + "sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0" + ], + "markers": "python_version >= '3.8'", + "version": "==2.6.1" }, "pynacl": { "hashes": [ @@ -1121,47 +1231,9 @@ "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84", "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c" ], - "markers": "python_version >= '3.1'", + "markers": "python_version >= '3.9'", "version": "==3.2.0" }, - "pyrsistent": { - "hashes": [ - "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", - "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", - "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", - "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", - "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca", - "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", - "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", - "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", - "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714", - "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf", - "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", - "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", - "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", - "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d", - "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054", - "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", - "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", - "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423", - "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", - "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", - "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", - "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0", - "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", - "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", - "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce", - "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", - "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", - "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86", - "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f", - "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", - "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98", - "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022" - ], - "markers": "python_version >= '3.8'", - "version": "==0.20.0" - }, "pyserial": { "hashes": [ "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", @@ -1182,9 +1254,17 @@ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, + "python-dotenv": { + "hashes": [ + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" + ], + "markers": "python_version >= '3.8'", + "version": "==1.0.1" + }, "pytz": { "hashes": [ "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", @@ -1200,29 +1280,13 @@ "markers": "python_full_version >= '3.6.0'", "version": "==1.2.1" }, - "pywin32": { - "hashes": [ - "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", - "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", - "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6", - "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", - "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff", - "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de", - "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e", - "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", - "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0", - "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", - "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", - "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920", - "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341", - "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e", - "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", - "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c", - "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", - "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4" - ], - "markers": "platform_system == 'Windows' and platform_python_implementation == 'CPython'", - "version": "==308" + "referencing": { + "hashes": [ + "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", + "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" + ], + "markers": "python_version >= '3.8'", + "version": "==0.35.1" }, "requests": { "hashes": [ @@ -1240,6 +1304,115 @@ "markers": "python_version >= '3.4'", "version": "==2.0.0" }, + "rpds-py": { + "hashes": [ + "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518", + "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", + "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", + "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5", + "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9", + "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543", + "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2", + "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a", + "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d", + "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", + "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d", + "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd", + "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b", + "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4", + "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99", + "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", + "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd", + "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe", + "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1", + "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", + "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f", + "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3", + "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca", + "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d", + "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e", + "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc", + "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea", + "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", + "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b", + "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c", + "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff", + "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723", + "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e", + "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493", + "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6", + "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83", + "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091", + "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1", + "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", + "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1", + "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728", + "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16", + "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c", + "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", + "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7", + "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a", + "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730", + "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967", + "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25", + "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24", + "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055", + "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d", + "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0", + "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e", + "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", + "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c", + "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f", + "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd", + "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652", + "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8", + "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11", + "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333", + "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96", + "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64", + "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b", + "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e", + "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c", + "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9", + "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec", + "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb", + "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37", + "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad", + "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9", + "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c", + "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf", + "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", + "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f", + "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d", + "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09", + "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", + "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566", + "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74", + "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338", + "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", + "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c", + "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648", + "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84", + "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3", + "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123", + "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520", + "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831", + "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", + "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf", + "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b", + "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2", + "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3", + "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130", + "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b", + "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de", + "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5", + "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d", + "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00", + "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e" + ], + "markers": "python_version >= '3.9'", + "version": "==0.22.3" + }, "rsa": { "hashes": [ "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", @@ -1250,28 +1423,28 @@ }, "setuptools": { "hashes": [ - "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd", - "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686" + "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", + "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d" ], - "markers": "python_version >= '3.8'", - "version": "==75.3.0" + "markers": "python_version >= '3.9'", + "version": "==75.6.0" }, "six": { "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.17.0" }, "slack-sdk": { "hashes": [ - "sha256:0515fb93cd03b18de61f876a8304c4c3cef4dd3c2a3bad62d7394d2eb5a3c8e6", - "sha256:4cc44c9ffe4bb28a01fbe3264c2f466c783b893a4eca62026ab845ec7c176ff1" + "sha256:a5e74c00c99dc844ad93e501ab764a20d86fa8184bbc9432af217496f632c4ee", + "sha256:b8cccadfa3d4005a5e6529f52000d25c583f46173fda8e9136fdd2bc58923ff6" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==3.33.3" + "version": "==3.33.5" }, "slackclient": { "hashes": [ @@ -1348,167 +1521,162 @@ }, "wrapt": { "hashes": [ - "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc", - "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81", - "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09", - "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e", - "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca", - "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0", - "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb", - "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487", - "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40", - "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c", - "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060", - "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202", - "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41", - "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9", - "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b", - "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664", - "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d", - "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362", - "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00", - "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc", - "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1", - "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267", - "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956", - "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966", - "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1", - "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228", - "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72", - "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d", - "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292", - "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0", - "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0", - "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36", - "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c", - "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5", - "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f", - "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73", - "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b", - "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2", - "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593", - "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39", - "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389", - "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf", - "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf", - "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89", - "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c", - "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c", - "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f", - "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440", - "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465", - "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136", - "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b", - "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8", - "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3", - "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8", - "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6", - "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e", - "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f", - "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c", - "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e", - "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8", - "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2", - "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020", - "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35", - "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d", - "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3", - "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537", - "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809", - "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d", - "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a", - "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4" + "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d", + "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301", + "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635", + "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a", + "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed", + "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721", + "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801", + "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b", + "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1", + "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88", + "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8", + "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0", + "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f", + "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578", + "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7", + "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045", + "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada", + "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d", + "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b", + "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a", + "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977", + "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea", + "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346", + "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13", + "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22", + "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339", + "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9", + "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181", + "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c", + "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90", + "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a", + "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489", + "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f", + "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504", + "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea", + "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569", + "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4", + "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce", + "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab", + "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a", + "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f", + "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c", + "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9", + "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf", + "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d", + "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627", + "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d", + "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4", + "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c", + "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d", + "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad", + "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b", + "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33", + "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371", + "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1", + "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393", + "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106", + "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df", + "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379", + "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451", + "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b", + "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575", + "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed", + "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb", + "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838" ], - "markers": "python_version >= '3.6'", - "version": "==1.16.0" + "markers": "python_version >= '3.8'", + "version": "==1.17.0" }, "yarl": { "hashes": [ - "sha256:06157fb3c58f2736a5e47c8fcbe1afc8b5de6fb28b14d25574af9e62150fcaac", - "sha256:067a63fcfda82da6b198fa73079b1ca40b7c9b7994995b6ee38acda728b64d47", - "sha256:0b1794853124e2f663f0ea54efb0340b457f08d40a1cef78edfa086576179c91", - "sha256:0bdff5e0995522706c53078f531fb586f56de9c4c81c243865dd5c66c132c3b5", - "sha256:117ed8b3732528a1e41af3aa6d4e08483c2f0f2e3d3d7dca7cf538b3516d93df", - "sha256:14bc88baa44e1f84164a392827b5defb4fa8e56b93fecac3d15315e7c8e5d8b3", - "sha256:1654ec814b18be1af2c857aa9000de7a601400bd4c9ca24629b18486c2e35463", - "sha256:16bca6678a83657dd48df84b51bd56a6c6bd401853aef6d09dc2506a78484c7b", - "sha256:1a3b91c44efa29e6c8ef8a9a2b583347998e2ba52c5d8280dbd5919c02dfc3b5", - "sha256:1a52a1ffdd824fb1835272e125385c32fd8b17fbdefeedcb4d543cc23b332d74", - "sha256:1ce36ded585f45b1e9bb36d0ae94765c6608b43bd2e7f5f88079f7a85c61a4d3", - "sha256:299f11b44d8d3a588234adbe01112126010bd96d9139c3ba7b3badd9829261c3", - "sha256:2b24ec55fad43e476905eceaf14f41f6478780b870eda5d08b4d6de9a60b65b4", - "sha256:2d374d70fdc36f5863b84e54775452f68639bc862918602d028f89310a034ab0", - "sha256:2d9f0606baaec5dd54cb99667fcf85183a7477f3766fbddbe3f385e7fc253299", - "sha256:2e7ba4c9377e48fb7b20dedbd473cbcbc13e72e1826917c185157a137dac9df2", - "sha256:2f0a6423295a0d282d00e8701fe763eeefba8037e984ad5de44aa349002562ac", - "sha256:327828786da2006085a4d1feb2594de6f6d26f8af48b81eb1ae950c788d97f61", - "sha256:380e6c38ef692b8fd5a0f6d1fa8774d81ebc08cfbd624b1bca62a4d4af2f9931", - "sha256:3b74ff4767d3ef47ffe0cd1d89379dc4d828d4873e5528976ced3b44fe5b0a21", - "sha256:3e844be8d536afa129366d9af76ed7cb8dfefec99f5f1c9e4f8ae542279a6dc3", - "sha256:459e81c2fb920b5f5df744262d1498ec2c8081acdcfe18181da44c50f51312f7", - "sha256:46ddf6e0b975cd680eb83318aa1d321cb2bf8d288d50f1754526230fcf59ba96", - "sha256:482c122b72e3c5ec98f11457aeb436ae4aecca75de19b3d1de7cf88bc40db82f", - "sha256:561c87fea99545ef7d692403c110b2f99dced6dff93056d6e04384ad3bc46243", - "sha256:578d00c9b7fccfa1745a44f4eddfdc99d723d157dad26764538fbdda37209857", - "sha256:58c8e9620eb82a189c6c40cb6b59b4e35b2ee68b1f2afa6597732a2b467d7e8f", - "sha256:5b29beab10211a746f9846baa39275e80034e065460d99eb51e45c9a9495bcca", - "sha256:5d1d42556b063d579cae59e37a38c61f4402b47d70c29f0ef15cee1acaa64488", - "sha256:5f236cb5999ccd23a0ab1bd219cfe0ee3e1c1b65aaf6dd3320e972f7ec3a39da", - "sha256:62a91aefff3d11bf60e5956d340eb507a983a7ec802b19072bb989ce120cd948", - "sha256:64cc6e97f14cf8a275d79c5002281f3040c12e2e4220623b5759ea7f9868d6a5", - "sha256:6f4c9156c4d1eb490fe374fb294deeb7bc7eaccda50e23775b2354b6a6739934", - "sha256:7294e38f9aa2e9f05f765b28ffdc5d81378508ce6dadbe93f6d464a8c9594473", - "sha256:7615058aabad54416ddac99ade09a5510cf77039a3b903e94e8922f25ed203d7", - "sha256:7e48cdb8226644e2fbd0bdb0a0f87906a3db07087f4de77a1b1b1ccfd9e93685", - "sha256:7f63d176a81555984e91f2c84c2a574a61cab7111cc907e176f0f01538e9ff6e", - "sha256:7f6595c852ca544aaeeb32d357e62c9c780eac69dcd34e40cae7b55bc4fb1147", - "sha256:7fac95714b09da9278a0b52e492466f773cfe37651cf467a83a1b659be24bf71", - "sha256:81713b70bea5c1386dc2f32a8f0dab4148a2928c7495c808c541ee0aae614d67", - "sha256:846dd2e1243407133d3195d2d7e4ceefcaa5f5bf7278f0a9bda00967e6326b04", - "sha256:84c063af19ef5130084db70ada40ce63a84f6c1ef4d3dbc34e5e8c4febb20822", - "sha256:881764d610e3269964fc4bb3c19bb6fce55422828e152b885609ec176b41cf11", - "sha256:8994b29c462de9a8fce2d591028b986dbbe1b32f3ad600b2d3e1c482c93abad6", - "sha256:8c79e9d7e3d8a32d4824250a9c6401194fb4c2ad9a0cec8f6a96e09a582c2cc0", - "sha256:8ee427208c675f1b6e344a1f89376a9613fc30b52646a04ac0c1f6587c7e46ec", - "sha256:949681f68e0e3c25377462be4b658500e85ca24323d9619fdc41f68d46a1ffda", - "sha256:9e275792097c9f7e80741c36de3b61917aebecc08a67ae62899b074566ff8556", - "sha256:9fb815155aac6bfa8d86184079652c9715c812d506b22cfa369196ef4e99d1b4", - "sha256:a2a64e62c7a0edd07c1c917b0586655f3362d2c2d37d474db1a509efb96fea1c", - "sha256:a7ac5b4984c468ce4f4a553df281450df0a34aefae02e58d77a0847be8d1e11f", - "sha256:aa46dce75078fceaf7cecac5817422febb4355fbdda440db55206e3bd288cfb8", - "sha256:ae3476e934b9d714aa8000d2e4c01eb2590eee10b9d8cd03e7983ad65dfbfcba", - "sha256:b0341e6d9a0c0e3cdc65857ef518bb05b410dbd70d749a0d33ac0f39e81a4258", - "sha256:b40d1bf6e6f74f7c0a567a9e5e778bbd4699d1d3d2c0fe46f4b717eef9e96b95", - "sha256:b5c4804e4039f487e942c13381e6c27b4b4e66066d94ef1fae3f6ba8b953f383", - "sha256:b5d6a6c9602fd4598fa07e0389e19fe199ae96449008d8304bf5d47cb745462e", - "sha256:b5f1ac7359e17efe0b6e5fec21de34145caef22b260e978336f325d5c84e6938", - "sha256:c0167540094838ee9093ef6cc2c69d0074bbf84a432b4995835e8e5a0d984374", - "sha256:c180ac742a083e109c1a18151f4dd8675f32679985a1c750d2ff806796165b55", - "sha256:c73df5b6e8fabe2ddb74876fb82d9dd44cbace0ca12e8861ce9155ad3c886139", - "sha256:c7e177c619342e407415d4f35dec63d2d134d951e24b5166afcdfd1362828e17", - "sha256:cbad927ea8ed814622305d842c93412cb47bd39a496ed0f96bfd42b922b4a217", - "sha256:cc353841428d56b683a123a813e6a686e07026d6b1c5757970a877195f880c2d", - "sha256:cc7c92c1baa629cb03ecb0c3d12564f172218fb1739f54bf5f3881844daadc6d", - "sha256:cc7d768260f4ba4ea01741c1b5fe3d3a6c70eb91c87f4c8761bbcce5181beafe", - "sha256:d0eea830b591dbc68e030c86a9569826145df485b2b4554874b07fea1275a199", - "sha256:d216e5d9b8749563c7f2c6f7a0831057ec844c68b4c11cb10fc62d4fd373c26d", - "sha256:d401f07261dc5aa36c2e4efc308548f6ae943bfff20fcadb0a07517a26b196d8", - "sha256:d6324274b4e0e2fa1b3eccb25997b1c9ed134ff61d296448ab8269f5ac068c4c", - "sha256:d8a8b74d843c2638f3864a17d97a4acda58e40d3e44b6303b8cc3d3c44ae2d29", - "sha256:d9b6b28a57feb51605d6ae5e61a9044a31742db557a3b851a74c13bc61de5172", - "sha256:de599af166970d6a61accde358ec9ded821234cbbc8c6413acfec06056b8e860", - "sha256:e594b22688d5747b06e957f1ef822060cb5cb35b493066e33ceac0cf882188b7", - "sha256:e5b078134f48552c4d9527db2f7da0b5359abd49393cdf9794017baec7506170", - "sha256:eb6dce402734575e1a8cc0bb1509afca508a400a57ce13d306ea2c663bad1138", - "sha256:f1790a4b1e8e8e028c391175433b9c8122c39b46e1663228158e61e6f915bf06", - "sha256:f5efe0661b9fcd6246f27957f6ae1c0eb29bc60552820f01e970b4996e016004", - "sha256:f9cbfbc5faca235fbdf531b93aa0f9f005ec7d267d9d738761a4d42b744ea159", - "sha256:fbea1751729afe607d84acfd01efd95e3b31db148a181a441984ce9b3d3469da", - "sha256:fca4b4307ebe9c3ec77a084da3a9d1999d164693d16492ca2b64594340999988", - "sha256:ff5c6771c7e3511a06555afa317879b7db8d640137ba55d6ab0d0c50425cab75" + "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", + "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193", + "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318", + "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee", + "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e", + "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1", + "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a", + "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", + "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1", + "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", + "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", + "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb", + "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", + "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc", + "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5", + "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", + "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", + "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", + "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24", + "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b", + "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910", + "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", + "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", + "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed", + "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1", + "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04", + "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", + "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5", + "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d", + "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889", + "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae", + "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b", + "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c", + "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", + "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34", + "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", + "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990", + "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", + "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", + "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069", + "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", + "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6", + "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", + "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", + "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", + "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", + "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8", + "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e", + "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e", + "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985", + "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8", + "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", + "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5", + "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690", + "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", + "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789", + "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", + "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca", + "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", + "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5", + "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59", + "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9", + "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8", + "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db", + "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde", + "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7", + "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", + "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3", + "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", + "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", + "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", + "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8", + "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", + "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd", + "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", + "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760", + "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", + "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", + "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", + "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", + "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719", + "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62" ], "markers": "python_version >= '3.9'", - "version": "==1.17.1" + "version": "==1.18.3" } }, "develop": { @@ -1694,79 +1862,80 @@ }, "colorama": { "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", + "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" ], - "markers": "platform_system == 'Windows'", - "version": "==0.4.6" + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.4.4" }, "coverage": { "hashes": [ - "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376", - "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9", - "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111", - "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172", - "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491", - "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546", - "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2", - "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11", - "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08", - "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c", - "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2", - "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963", - "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613", - "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0", - "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db", - "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf", - "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73", - "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117", - "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1", - "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e", - "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522", - "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25", - "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc", - "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea", - "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52", - "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a", - "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07", - "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06", - "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa", - "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901", - "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b", - "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17", - "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0", - "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21", - "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19", - "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5", - "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51", - "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3", - "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3", - "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f", - "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076", - "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a", - "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718", - "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba", - "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e", - "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27", - "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e", - "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09", - "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e", - "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70", - "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f", - "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72", - "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a", - "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef", - "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b", - "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b", - "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f", - "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806", - "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b", - "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1", - "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c", - "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858" + "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4", + "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c", + "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f", + "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b", + "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6", + "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae", + "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692", + "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4", + "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4", + "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717", + "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d", + "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198", + "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1", + "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3", + "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb", + "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d", + "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08", + "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf", + "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b", + "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710", + "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c", + "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae", + "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077", + "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00", + "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb", + "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664", + "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014", + "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9", + "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6", + "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e", + "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9", + "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa", + "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", + "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b", + "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a", + "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8", + "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030", + "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678", + "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015", + "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902", + "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97", + "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845", + "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419", + "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464", + "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be", + "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9", + "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7", + "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be", + "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1", + "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba", + "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5", + "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073", + "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4", + "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a", + "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a", + "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3", + "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599", + "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0", + "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b", + "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec", + "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1", + "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3" ], "markers": "python_version >= '3.9'", - "version": "==7.6.4" + "version": "==7.6.9" }, "flake8": { "hashes": [ @@ -1805,20 +1974,20 @@ }, "google-api-core": { "hashes": [ - "sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35", - "sha256:a6652b6bd51303902494998626653671703c420f6f4c88cfd3f50ed723e9d021" + "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9", + "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf" ], "markers": "python_version >= '3.7'", - "version": "==2.22.0" + "version": "==2.24.0" }, "google-api-python-client": { "hashes": [ - "sha256:4427b2f47cd88b0355d540c2c52215f68c337f3bc9d6aae1ceeae4525977504c", - "sha256:a9d26d630810ed4631aea21d1de3e42072f98240aaf184a8a1a874a371115034" + "sha256:1b420062e03bfcaa1c79e2e00a612d29a6a934151ceb3d272fe150a656dc8f17", + "sha256:a521bbbb2ec0ba9d6f307cdd64ed6e21eeac372d1bd7493a4ab5022941f784ad" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==2.151.0" + "version": "==2.154.0" }, "google-api-python-client-stubs": { "hashes": [ @@ -1846,11 +2015,11 @@ }, "googleapis-common-protos": { "hashes": [ - "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63", - "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0" + "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c", + "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed" ], "markers": "python_version >= '3.7'", - "version": "==1.65.0" + "version": "==1.66.0" }, "httplib2": { "hashes": [ @@ -1928,11 +2097,11 @@ }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "pathspec": { "hashes": [ @@ -1968,20 +2137,20 @@ }, "protobuf": { "hashes": [ - "sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24", - "sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535", - "sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b", - "sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548", - "sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584", - "sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b", - "sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36", - "sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135", - "sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868", - "sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687", - "sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed" + "sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c", + "sha256:027fbcc48cea65a6b17028510fdd054147057fa78f4772eb547b9274e5219331", + "sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34", + "sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110", + "sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0", + "sha256:50879eb0eb1246e3a5eabbbe566b44b10348939b7cc1b267567e8c3d07213853", + "sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57", + "sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb", + "sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d", + "sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155", + "sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18" ], "markers": "python_version >= '3.8'", - "version": "==5.28.3" + "version": "==5.29.1" }, "py": { "hashes": [ @@ -2036,7 +2205,7 @@ "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84", "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c" ], - "markers": "python_version >= '3.1'", + "markers": "python_version >= '3.9'", "version": "==3.2.0" }, "pytest": { @@ -2082,11 +2251,41 @@ }, "tomli": { "hashes": [ - "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38", - "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed" + "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", + "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", + "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", + "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", + "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", + "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", + "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", + "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", + "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", + "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", + "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", + "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", + "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", + "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", + "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", + "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", + "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", + "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", + "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", + "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", + "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", + "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" ], - "markers": "python_version < '3.11'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==2.2.1" }, "types-httplib2": { "hashes": [ diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[004ebb2b82][OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[004ebb2b82][OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift].json index 1e59022b2a8..8dc5a722eab 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[004ebb2b82][OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[004ebb2b82][OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift].json @@ -6876,9 +6876,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -6890,9 +6890,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -6911,9 +6911,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -6945,9 +6945,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -6978,9 +6978,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7011,9 +7011,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7045,9 +7045,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7079,9 +7079,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7113,9 +7113,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7176,9 +7176,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7208,9 +7208,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -7238,9 +7238,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -7252,9 +7252,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -7273,9 +7273,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7307,9 +7307,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7340,9 +7340,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7373,9 +7373,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7407,9 +7407,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7441,9 +7441,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7475,9 +7475,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7538,9 +7538,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7570,9 +7570,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -7600,9 +7600,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -7614,9 +7614,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -7635,9 +7635,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7669,9 +7669,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7702,9 +7702,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7735,9 +7735,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7769,9 +7769,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7803,9 +7803,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7837,9 +7837,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7900,9 +7900,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -7932,9 +7932,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -7962,9 +7962,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -7976,9 +7976,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -7997,9 +7997,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8031,9 +8031,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8064,9 +8064,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8097,9 +8097,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8131,9 +8131,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8165,9 +8165,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8199,9 +8199,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8262,9 +8262,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8294,9 +8294,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -8324,9 +8324,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -8338,9 +8338,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -8359,9 +8359,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8393,9 +8393,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8426,9 +8426,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8459,9 +8459,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8493,9 +8493,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8527,9 +8527,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8561,9 +8561,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8624,9 +8624,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8656,9 +8656,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -8686,9 +8686,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -8700,9 +8700,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -8721,9 +8721,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8755,9 +8755,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8788,9 +8788,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8821,9 +8821,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8855,9 +8855,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8889,9 +8889,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8923,9 +8923,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -8986,9 +8986,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9018,9 +9018,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -9048,9 +9048,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -9062,9 +9062,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -9083,9 +9083,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9117,9 +9117,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9150,9 +9150,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9183,9 +9183,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9217,9 +9217,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9251,9 +9251,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9285,9 +9285,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9348,9 +9348,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9380,9 +9380,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -9410,9 +9410,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -9424,9 +9424,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -9445,9 +9445,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9479,9 +9479,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9512,9 +9512,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9545,9 +9545,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9579,9 +9579,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9613,9 +9613,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9647,9 +9647,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9710,9 +9710,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9742,9 +9742,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -9892,9 +9892,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -9906,9 +9906,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 51.099999999999994, - "tipVolume": 300 + "tipVolume": 300.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -9927,9 +9927,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9961,9 +9961,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -9994,9 +9994,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10026,9 +10026,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -10056,9 +10056,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -10070,9 +10070,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 51.099999999999994, - "tipVolume": 300 + "tipVolume": 300.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -10091,9 +10091,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10125,9 +10125,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10159,9 +10159,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10193,9 +10193,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10227,9 +10227,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10276,9 +10276,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10309,9 +10309,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10342,9 +10342,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10376,9 +10376,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10410,9 +10410,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10444,9 +10444,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10477,9 +10477,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10509,9 +10509,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -10554,9 +10554,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -10568,9 +10568,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 51.099999999999994, - "tipVolume": 300 + "tipVolume": 300.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -10589,9 +10589,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10623,9 +10623,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10672,9 +10672,9 @@ "volume": 19.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10706,9 +10706,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10739,9 +10739,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -10769,9 +10769,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -10783,9 +10783,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 51.099999999999994, - "tipVolume": 300 + "tipVolume": 300.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -10804,9 +10804,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10837,9 +10837,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -10912,9 +10912,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -10926,9 +10926,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 51.099999999999994, - "tipVolume": 300 + "tipVolume": 300.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -10947,9 +10947,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10981,9 +10981,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11014,9 +11014,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11046,9 +11046,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -11091,9 +11091,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -11105,9 +11105,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -11126,9 +11126,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11160,9 +11160,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11193,9 +11193,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11225,9 +11225,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -11255,9 +11255,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -11269,9 +11269,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -11290,9 +11290,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11324,9 +11324,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11357,9 +11357,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11389,9 +11389,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -11419,9 +11419,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -11433,9 +11433,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -11454,9 +11454,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11488,9 +11488,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11521,9 +11521,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11553,9 +11553,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -11583,9 +11583,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -11597,9 +11597,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -11618,9 +11618,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11652,9 +11652,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11685,9 +11685,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11717,9 +11717,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -11747,9 +11747,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -11761,9 +11761,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -11782,9 +11782,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11816,9 +11816,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11849,9 +11849,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11881,9 +11881,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -11911,9 +11911,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -11925,9 +11925,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -11946,9 +11946,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11980,9 +11980,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12013,9 +12013,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12045,9 +12045,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -12075,9 +12075,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -12089,9 +12089,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -12110,9 +12110,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12144,9 +12144,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12177,9 +12177,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12209,9 +12209,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -12239,9 +12239,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -12253,9 +12253,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -12274,9 +12274,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12308,9 +12308,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12341,9 +12341,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12373,9 +12373,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -12403,9 +12403,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -12417,9 +12417,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -12438,9 +12438,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12472,9 +12472,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12506,9 +12506,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12540,9 +12540,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12573,9 +12573,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -12603,9 +12603,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -12617,9 +12617,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -12638,9 +12638,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12672,9 +12672,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12705,9 +12705,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12737,9 +12737,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -12767,9 +12767,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -12781,9 +12781,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -12802,9 +12802,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12836,9 +12836,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12870,9 +12870,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12904,9 +12904,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12938,9 +12938,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12972,9 +12972,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13005,9 +13005,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13037,9 +13037,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -13067,9 +13067,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -13081,9 +13081,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -13102,9 +13102,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13136,9 +13136,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13169,9 +13169,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13201,9 +13201,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -13231,9 +13231,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -13245,9 +13245,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -13266,9 +13266,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13300,9 +13300,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13334,9 +13334,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13368,9 +13368,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13402,9 +13402,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13436,9 +13436,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13469,9 +13469,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13501,9 +13501,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -13531,9 +13531,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -13545,9 +13545,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -13566,9 +13566,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13600,9 +13600,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13633,9 +13633,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13665,9 +13665,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -13695,9 +13695,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -13709,9 +13709,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -13730,9 +13730,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13764,9 +13764,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13798,9 +13798,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13832,9 +13832,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13866,9 +13866,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13900,9 +13900,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13933,9 +13933,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13965,9 +13965,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -13995,9 +13995,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -14009,9 +14009,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -14030,9 +14030,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14064,9 +14064,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14097,9 +14097,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14129,9 +14129,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -14159,9 +14159,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -14173,9 +14173,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -14194,9 +14194,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14228,9 +14228,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14262,9 +14262,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14296,9 +14296,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14330,9 +14330,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14364,9 +14364,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14397,9 +14397,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14429,9 +14429,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -14459,9 +14459,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -14473,9 +14473,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -14494,9 +14494,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14528,9 +14528,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14561,9 +14561,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14593,9 +14593,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -14623,9 +14623,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -14637,9 +14637,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -14658,9 +14658,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14692,9 +14692,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14726,9 +14726,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14760,9 +14760,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14794,9 +14794,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14828,9 +14828,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14861,9 +14861,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14893,9 +14893,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -14923,9 +14923,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -14937,9 +14937,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -14958,9 +14958,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14992,9 +14992,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15025,9 +15025,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15057,9 +15057,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15087,9 +15087,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -15101,9 +15101,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -15122,9 +15122,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15156,9 +15156,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15190,9 +15190,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15224,9 +15224,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15258,9 +15258,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15292,9 +15292,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15325,9 +15325,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15357,9 +15357,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15387,9 +15387,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -15401,9 +15401,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -15422,9 +15422,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15456,9 +15456,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15489,9 +15489,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15521,9 +15521,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15551,9 +15551,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -15565,9 +15565,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -15586,9 +15586,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15620,9 +15620,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15654,9 +15654,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15688,9 +15688,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15722,9 +15722,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15756,9 +15756,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15789,9 +15789,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15821,9 +15821,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15851,9 +15851,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -15865,9 +15865,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -15886,9 +15886,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15920,9 +15920,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15953,9 +15953,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15985,9 +15985,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16015,9 +16015,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -16029,9 +16029,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 35.910000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -16050,9 +16050,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16084,9 +16084,9 @@ "volume": 7.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16118,9 +16118,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16152,9 +16152,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16186,9 +16186,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16220,9 +16220,9 @@ "volume": 8.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16253,9 +16253,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16285,9 +16285,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16405,9 +16405,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -16419,9 +16419,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 51.099999999999994, - "tipVolume": 300 + "tipVolume": 300.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -16440,9 +16440,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16474,9 +16474,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16507,9 +16507,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16539,9 +16539,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[011481812b][OT2_S_v2_7_P20S_None_Walkthrough].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[011481812b][OT2_S_v2_7_P20S_None_Walkthrough].json index 387b9f0e3f5..3a1a9bca236 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[011481812b][OT2_S_v2_7_P20S_None_Walkthrough].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[011481812b][OT2_S_v2_7_P20S_None_Walkthrough].json @@ -2348,9 +2348,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -2362,9 +2362,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 30.950000000000003, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -2398,9 +2398,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2432,9 +2432,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2466,9 +2466,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2500,9 +2500,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2534,9 +2534,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2568,9 +2568,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2602,9 +2602,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2636,9 +2636,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2670,9 +2670,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2704,9 +2704,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2738,9 +2738,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2772,9 +2772,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2806,9 +2806,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2840,9 +2840,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2874,9 +2874,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2908,9 +2908,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2942,9 +2942,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -2976,9 +2976,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3010,9 +3010,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3059,9 +3059,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3093,9 +3093,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3142,9 +3142,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3176,9 +3176,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3210,9 +3210,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3243,9 +3243,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3276,9 +3276,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3310,9 +3310,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3343,9 +3343,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3376,9 +3376,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3410,9 +3410,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3443,9 +3443,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3475,9 +3475,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -3505,9 +3505,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -3519,9 +3519,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 30.950000000000003, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -3555,9 +3555,9 @@ "volume": 4.444444444444445, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3589,9 +3589,9 @@ "volume": 6.666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3638,9 +3638,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3672,9 +3672,9 @@ "volume": 4.444444444444445, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3706,9 +3706,9 @@ "volume": 6.666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3755,9 +3755,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3789,9 +3789,9 @@ "volume": 4.444444444444445, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3823,9 +3823,9 @@ "volume": 6.666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3872,9 +3872,9 @@ "volume": 13.333333333333334, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3906,9 +3906,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3940,9 +3940,9 @@ "volume": 2.5, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -3974,9 +3974,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4008,9 +4008,9 @@ "volume": 2.5, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4056,9 +4056,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4088,9 +4088,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -4118,9 +4118,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -4132,9 +4132,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 30.950000000000003, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -4153,9 +4153,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4187,9 +4187,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4221,9 +4221,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4255,9 +4255,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4289,9 +4289,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4323,9 +4323,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4357,9 +4357,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4391,9 +4391,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4425,9 +4425,9 @@ "volume": 13.333333333333332, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4458,9 +4458,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -4488,9 +4488,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -4502,9 +4502,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 30.950000000000003, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -4523,9 +4523,9 @@ "volume": 14.333333333333332, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4557,9 +4557,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4591,9 +4591,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4625,9 +4625,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4659,9 +4659,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4693,9 +4693,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4727,9 +4727,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4761,9 +4761,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4795,9 +4795,9 @@ "volume": 1.6666666666666667, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4828,9 +4828,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -4860,9 +4860,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0190369ce5][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0190369ce5][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures].json index df7062d67b5..3d1cdd1d3c1 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0190369ce5][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0190369ce5][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures].json @@ -10789,9 +10789,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -10921,9 +10921,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -11121,9 +11121,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -11253,9 +11253,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0903a95825][Flex_S_v2_19_QIASeq_FX_48x].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0903a95825][Flex_S_v2_19_QIASeq_FX_48x].json index d1d7e581f85..a7e09aba292 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0903a95825][Flex_S_v2_19_QIASeq_FX_48x].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0903a95825][Flex_S_v2_19_QIASeq_FX_48x].json @@ -20183,9 +20183,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20583,9 +20583,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20983,9 +20983,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -23990,9 +23990,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -24487,9 +24487,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -24984,9 +24984,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -26804,9 +26804,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27301,9 +27301,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27798,9 +27798,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27956,9 +27956,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -28086,9 +28086,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -28216,9 +28216,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -28498,9 +28498,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -28694,9 +28694,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -28890,9 +28890,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29265,9 +29265,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29509,9 +29509,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29753,9 +29753,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35050,9 +35050,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35547,9 +35547,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36044,9 +36044,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -37850,9 +37850,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -38333,9 +38333,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -38816,9 +38816,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -41809,9 +41809,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42292,9 +42292,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42775,9 +42775,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42933,9 +42933,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -43063,9 +43063,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -43193,9 +43193,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44732,9 +44732,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44962,9 +44962,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -45192,9 +45192,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -56010,9 +56010,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -56507,9 +56507,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -57004,9 +57004,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -58824,9 +58824,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -59321,9 +59321,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -59818,9 +59818,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -62861,9 +62861,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -63358,9 +63358,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -63855,9 +63855,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -64013,9 +64013,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -64143,9 +64143,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -64273,9 +64273,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -64589,9 +64589,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -64819,9 +64819,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -65049,9 +65049,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -65424,9 +65424,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -65668,9 +65668,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -65912,9 +65912,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0a9ef592c8][Flex_S_v2_18_Illumina_DNA_Prep_48x].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0a9ef592c8][Flex_S_v2_18_Illumina_DNA_Prep_48x].json index f9343e792c6..705c9658155 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0a9ef592c8][Flex_S_v2_18_Illumina_DNA_Prep_48x].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0a9ef592c8][Flex_S_v2_18_Illumina_DNA_Prep_48x].json @@ -14067,9 +14067,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -14199,9 +14199,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -14331,9 +14331,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -14910,9 +14910,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15342,9 +15342,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15774,9 +15774,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19117,9 +19117,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19549,9 +19549,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19981,9 +19981,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22137,9 +22137,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22569,9 +22569,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -23001,9 +23001,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -26344,9 +26344,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -26776,9 +26776,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27208,9 +27208,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27588,9 +27588,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27940,9 +27940,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -28292,9 +28292,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36140,9 +36140,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36540,9 +36540,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36940,9 +36940,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -39946,9 +39946,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40346,9 +40346,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40746,9 +40746,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42565,9 +42565,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42965,9 +42965,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -43365,9 +43365,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -43745,9 +43745,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44097,9 +44097,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44449,9 +44449,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46022,9 +46022,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46286,9 +46286,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46550,9 +46550,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46845,9 +46845,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -47009,9 +47009,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -47173,9 +47173,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0c4ae179bb][OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0c4ae179bb][OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3].json index c5a57c18fc4..84e33cd17bd 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0c4ae179bb][OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0c4ae179bb][OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3].json @@ -11844,9 +11844,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15853,9 +15853,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16208,9 +16208,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16562,9 +16562,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16840,9 +16840,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16939,9 +16939,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[134037b2aa][OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[134037b2aa][OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods].json index 19b3454722f..a0e4e4b52b4 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[134037b2aa][OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[134037b2aa][OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods].json @@ -6112,9 +6112,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -6147,8 +6147,8 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -6181,8 +6181,8 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -6214,9 +6214,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -6244,9 +6244,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -6279,8 +6279,8 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -6313,8 +6313,8 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -6346,9 +6346,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -6376,9 +6376,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -6411,8 +6411,8 @@ "volume": 25.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -6445,8 +6445,8 @@ "volume": 25.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -6478,9 +6478,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -6508,9 +6508,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -6543,8 +6543,8 @@ "volume": 25.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -6577,8 +6577,8 @@ "volume": 25.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -6610,9 +6610,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -6640,9 +6640,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -6675,8 +6675,8 @@ "volume": 25.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -6709,8 +6709,8 @@ "volume": 25.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -6742,9 +6742,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -6772,9 +6772,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -6807,8 +6807,8 @@ "volume": 25.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -6841,8 +6841,8 @@ "volume": 25.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -6874,9 +6874,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -6904,9 +6904,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -6939,8 +6939,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -6973,8 +6973,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -7006,9 +7006,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -7036,9 +7036,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -7071,8 +7071,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -7105,8 +7105,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -7138,9 +7138,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -7168,9 +7168,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -7203,8 +7203,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -7237,8 +7237,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -7270,9 +7270,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -7300,9 +7300,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -7335,8 +7335,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -7369,8 +7369,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -7402,9 +7402,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -7432,9 +7432,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -7467,8 +7467,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -7501,8 +7501,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -7534,9 +7534,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -7564,9 +7564,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -7599,8 +7599,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -7633,8 +7633,8 @@ "volume": 22.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -7666,9 +7666,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[194e3c49bb][pl_Normalization_with_PCR].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[194e3c49bb][pl_Normalization_with_PCR].json index 1dad0a643db..15d4ad5cd55 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[194e3c49bb][pl_Normalization_with_PCR].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[194e3c49bb][pl_Normalization_with_PCR].json @@ -6021,9 +6021,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -6636,9 +6636,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -7478,9 +7478,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -8322,9 +8322,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -9166,9 +9166,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19c783e363][Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19c783e363][Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips].json index 7a817b9879d..bc40fdbb1d4 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19c783e363][Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19c783e363][Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips].json @@ -12022,9 +12022,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -12057,8 +12057,8 @@ "volume": 100.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -12091,8 +12091,8 @@ "volume": 100.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -12165,9 +12165,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -12200,8 +12200,8 @@ "volume": 100.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -12234,8 +12234,8 @@ "volume": 100.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", @@ -12322,9 +12322,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -12357,8 +12357,8 @@ "volume": 200.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 1.0 }, "origin": "bottom", @@ -12391,8 +12391,8 @@ "volume": 200.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, + "x": 0.0, + "y": 0.0, "z": 0.5 }, "origin": "bottom", diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1b73b8a126][pl_Dynabeads_IP_Flex_96well_RIT_final].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1b73b8a126][pl_Dynabeads_IP_Flex_96well_RIT_final].json index d4ea924e585..29df1897867 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1b73b8a126][pl_Dynabeads_IP_Flex_96well_RIT_final].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1b73b8a126][pl_Dynabeads_IP_Flex_96well_RIT_final].json @@ -16970,9 +16970,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -17262,9 +17262,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -17492,9 +17492,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -17722,9 +17722,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -17952,9 +17952,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -18182,9 +18182,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -18412,9 +18412,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -18642,9 +18642,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -18872,9 +18872,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19102,9 +19102,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19332,9 +19332,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19562,9 +19562,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19792,9 +19792,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20103,9 +20103,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20366,9 +20366,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20629,9 +20629,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20892,9 +20892,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21155,9 +21155,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21418,9 +21418,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21681,9 +21681,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21944,9 +21944,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22207,9 +22207,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22470,9 +22470,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22733,9 +22733,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22996,9 +22996,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29040,9 +29040,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29408,9 +29408,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29638,9 +29638,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29868,9 +29868,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -30098,9 +30098,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -30328,9 +30328,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -30558,9 +30558,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -30788,9 +30788,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31018,9 +31018,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31248,9 +31248,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31478,9 +31478,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31708,9 +31708,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31938,9 +31938,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -34042,9 +34042,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -34393,9 +34393,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -34623,9 +34623,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -34853,9 +34853,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35083,9 +35083,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35313,9 +35313,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35543,9 +35543,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35773,9 +35773,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36003,9 +36003,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36233,9 +36233,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36463,9 +36463,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36693,9 +36693,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36923,9 +36923,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -39027,9 +39027,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -39378,9 +39378,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -39608,9 +39608,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -39838,9 +39838,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40068,9 +40068,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40298,9 +40298,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40528,9 +40528,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40758,9 +40758,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40988,9 +40988,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -41218,9 +41218,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -41448,9 +41448,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -41678,9 +41678,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -41908,9 +41908,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44012,9 +44012,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44363,9 +44363,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44593,9 +44593,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44823,9 +44823,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -45053,9 +45053,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -45283,9 +45283,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -45513,9 +45513,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -45743,9 +45743,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -45973,9 +45973,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46203,9 +46203,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46433,9 +46433,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46663,9 +46663,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46893,9 +46893,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -52985,9 +52985,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1c19a2055c][OT2_S_v2_4_P300M_None_MM_TM_Zymo].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1c19a2055c][OT2_S_v2_4_P300M_None_MM_TM_Zymo].json index fc41febf592..25c3ac466ec 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1c19a2055c][OT2_S_v2_4_P300M_None_MM_TM_Zymo].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1c19a2055c][OT2_S_v2_4_P300M_None_MM_TM_Zymo].json @@ -10682,9 +10682,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -10696,9 +10696,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -10717,9 +10717,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10751,9 +10751,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10785,9 +10785,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10819,9 +10819,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10853,9 +10853,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10887,9 +10887,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10921,9 +10921,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10955,9 +10955,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -10989,9 +10989,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11023,9 +11023,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11057,9 +11057,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11091,9 +11091,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11125,9 +11125,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11159,9 +11159,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11193,9 +11193,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11227,9 +11227,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11261,9 +11261,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11295,9 +11295,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11329,9 +11329,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11363,9 +11363,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11397,9 +11397,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11431,9 +11431,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11465,9 +11465,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11499,9 +11499,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11533,9 +11533,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11567,9 +11567,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11601,9 +11601,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11635,9 +11635,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11669,9 +11669,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11703,9 +11703,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11737,9 +11737,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11771,9 +11771,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11805,9 +11805,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11839,9 +11839,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11873,9 +11873,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11907,9 +11907,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11941,9 +11941,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -11975,9 +11975,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12009,9 +12009,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12043,9 +12043,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12077,9 +12077,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12111,9 +12111,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12145,9 +12145,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12179,9 +12179,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12213,9 +12213,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12247,9 +12247,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12281,9 +12281,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12315,9 +12315,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12349,9 +12349,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12383,9 +12383,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12417,9 +12417,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12451,9 +12451,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12485,9 +12485,9 @@ "volume": 3.333333333333343, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12519,9 +12519,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12553,9 +12553,9 @@ "volume": 13.333333333333343, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12587,9 +12587,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12621,9 +12621,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12655,9 +12655,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12689,9 +12689,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12723,9 +12723,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12757,9 +12757,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12791,9 +12791,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12825,9 +12825,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12859,9 +12859,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12893,9 +12893,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12927,9 +12927,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12961,9 +12961,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -12995,9 +12995,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13029,9 +13029,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13063,9 +13063,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13097,9 +13097,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13131,9 +13131,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13165,9 +13165,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13199,9 +13199,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13233,9 +13233,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13267,9 +13267,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13301,9 +13301,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13335,9 +13335,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13369,9 +13369,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13403,9 +13403,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13437,9 +13437,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13471,9 +13471,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13505,9 +13505,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13539,9 +13539,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13573,9 +13573,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13607,9 +13607,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13641,9 +13641,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13675,9 +13675,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13709,9 +13709,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13743,9 +13743,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13777,9 +13777,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13811,9 +13811,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13845,9 +13845,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13879,9 +13879,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13913,9 +13913,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13947,9 +13947,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -13981,9 +13981,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14015,9 +14015,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14049,9 +14049,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14083,9 +14083,9 @@ "volume": 3.333333333333343, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14117,9 +14117,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14151,9 +14151,9 @@ "volume": 13.333333333333343, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14185,9 +14185,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14219,9 +14219,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14253,9 +14253,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14287,9 +14287,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14321,9 +14321,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14355,9 +14355,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14389,9 +14389,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14423,9 +14423,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14457,9 +14457,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14491,9 +14491,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14525,9 +14525,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14559,9 +14559,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14593,9 +14593,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14627,9 +14627,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14661,9 +14661,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14695,9 +14695,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14729,9 +14729,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14763,9 +14763,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14797,9 +14797,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14831,9 +14831,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14865,9 +14865,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14899,9 +14899,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14933,9 +14933,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -14967,9 +14967,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15001,9 +15001,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15035,9 +15035,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15069,9 +15069,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15103,9 +15103,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15137,9 +15137,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15171,9 +15171,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15205,9 +15205,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15239,9 +15239,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15273,9 +15273,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15307,9 +15307,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15341,9 +15341,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15375,9 +15375,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15409,9 +15409,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15443,9 +15443,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15477,9 +15477,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15511,9 +15511,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15545,9 +15545,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15579,9 +15579,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15613,9 +15613,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15647,9 +15647,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15681,9 +15681,9 @@ "volume": 3.333333333333343, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15715,9 +15715,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15749,9 +15749,9 @@ "volume": 13.333333333333343, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15782,9 +15782,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15815,9 +15815,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -15848,9 +15848,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15921,9 +15921,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -15935,9 +15935,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -15971,9 +15971,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16005,9 +16005,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16039,9 +16039,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16073,9 +16073,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16107,9 +16107,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16141,9 +16141,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16175,9 +16175,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16209,9 +16209,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16243,9 +16243,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16277,9 +16277,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16311,9 +16311,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16345,9 +16345,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16379,9 +16379,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16413,9 +16413,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16447,9 +16447,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16481,9 +16481,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16515,9 +16515,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16549,9 +16549,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16583,9 +16583,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16617,9 +16617,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16651,9 +16651,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16685,9 +16685,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16719,9 +16719,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16753,9 +16753,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16787,9 +16787,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16821,9 +16821,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16855,9 +16855,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16889,9 +16889,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16923,9 +16923,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16957,9 +16957,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -16991,9 +16991,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17025,9 +17025,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17059,9 +17059,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17093,9 +17093,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17127,9 +17127,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17161,9 +17161,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17195,9 +17195,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17229,9 +17229,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17263,9 +17263,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17297,9 +17297,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17331,9 +17331,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17365,9 +17365,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17399,9 +17399,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17433,9 +17433,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17467,9 +17467,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17501,9 +17501,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17535,9 +17535,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17569,9 +17569,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17603,9 +17603,9 @@ "volume": 6.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17637,9 +17637,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17671,9 +17671,9 @@ "volume": 16.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17704,9 +17704,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17737,9 +17737,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17771,9 +17771,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17820,9 +17820,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17854,9 +17854,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17888,9 +17888,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17922,9 +17922,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17956,9 +17956,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -17990,9 +17990,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18024,9 +18024,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18058,9 +18058,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18092,9 +18092,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18126,9 +18126,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18160,9 +18160,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18194,9 +18194,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18228,9 +18228,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18262,9 +18262,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18296,9 +18296,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18330,9 +18330,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18364,9 +18364,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18398,9 +18398,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18432,9 +18432,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18466,9 +18466,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18500,9 +18500,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18534,9 +18534,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18568,9 +18568,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18602,9 +18602,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18636,9 +18636,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18670,9 +18670,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18704,9 +18704,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18738,9 +18738,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18772,9 +18772,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18806,9 +18806,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18840,9 +18840,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18874,9 +18874,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18908,9 +18908,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18942,9 +18942,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -18976,9 +18976,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19010,9 +19010,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19044,9 +19044,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19078,9 +19078,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19112,9 +19112,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19146,9 +19146,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19180,9 +19180,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19214,9 +19214,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19248,9 +19248,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19282,9 +19282,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19316,9 +19316,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19350,9 +19350,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19384,9 +19384,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19418,9 +19418,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19452,9 +19452,9 @@ "volume": 6.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19486,9 +19486,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19520,9 +19520,9 @@ "volume": 16.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19553,9 +19553,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19586,9 +19586,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19620,9 +19620,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19669,9 +19669,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19703,9 +19703,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19737,9 +19737,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19771,9 +19771,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19805,9 +19805,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19839,9 +19839,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19873,9 +19873,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19907,9 +19907,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19941,9 +19941,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -19975,9 +19975,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20009,9 +20009,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20043,9 +20043,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20077,9 +20077,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20111,9 +20111,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20145,9 +20145,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20179,9 +20179,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20213,9 +20213,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20247,9 +20247,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20281,9 +20281,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20315,9 +20315,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20349,9 +20349,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20383,9 +20383,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20417,9 +20417,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20451,9 +20451,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20485,9 +20485,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20519,9 +20519,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20553,9 +20553,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20587,9 +20587,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20621,9 +20621,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20655,9 +20655,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20689,9 +20689,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20723,9 +20723,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20757,9 +20757,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20791,9 +20791,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20825,9 +20825,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20859,9 +20859,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20893,9 +20893,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20927,9 +20927,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20961,9 +20961,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -20995,9 +20995,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21029,9 +21029,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21063,9 +21063,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21097,9 +21097,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21131,9 +21131,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21165,9 +21165,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21199,9 +21199,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21233,9 +21233,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21267,9 +21267,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21301,9 +21301,9 @@ "volume": 6.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21335,9 +21335,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21369,9 +21369,9 @@ "volume": 16.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21402,9 +21402,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21435,9 +21435,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21469,9 +21469,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21518,9 +21518,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21552,9 +21552,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21586,9 +21586,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21620,9 +21620,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21654,9 +21654,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21688,9 +21688,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21722,9 +21722,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21756,9 +21756,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21790,9 +21790,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21824,9 +21824,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21858,9 +21858,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21892,9 +21892,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21926,9 +21926,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21960,9 +21960,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -21994,9 +21994,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22028,9 +22028,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22062,9 +22062,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22096,9 +22096,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22130,9 +22130,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22164,9 +22164,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22198,9 +22198,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22232,9 +22232,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22266,9 +22266,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22300,9 +22300,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22334,9 +22334,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22368,9 +22368,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22402,9 +22402,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22436,9 +22436,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22470,9 +22470,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22504,9 +22504,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22538,9 +22538,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22572,9 +22572,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22606,9 +22606,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22640,9 +22640,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22674,9 +22674,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22708,9 +22708,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22742,9 +22742,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22776,9 +22776,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22810,9 +22810,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22844,9 +22844,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22878,9 +22878,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22912,9 +22912,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22946,9 +22946,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -22980,9 +22980,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23014,9 +23014,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23048,9 +23048,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23082,9 +23082,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23116,9 +23116,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23150,9 +23150,9 @@ "volume": 6.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23184,9 +23184,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23218,9 +23218,9 @@ "volume": 16.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23251,9 +23251,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23284,9 +23284,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23318,9 +23318,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23367,9 +23367,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23401,9 +23401,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23435,9 +23435,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23469,9 +23469,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23503,9 +23503,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23537,9 +23537,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23571,9 +23571,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23605,9 +23605,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23639,9 +23639,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23673,9 +23673,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23707,9 +23707,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23741,9 +23741,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23775,9 +23775,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23809,9 +23809,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23843,9 +23843,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23877,9 +23877,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23911,9 +23911,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23945,9 +23945,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -23979,9 +23979,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24013,9 +24013,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24047,9 +24047,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24081,9 +24081,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24115,9 +24115,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24149,9 +24149,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24183,9 +24183,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24217,9 +24217,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24251,9 +24251,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24285,9 +24285,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24319,9 +24319,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24353,9 +24353,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24387,9 +24387,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24421,9 +24421,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24455,9 +24455,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24489,9 +24489,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24523,9 +24523,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24557,9 +24557,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24591,9 +24591,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24625,9 +24625,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24659,9 +24659,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24693,9 +24693,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24727,9 +24727,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24761,9 +24761,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24795,9 +24795,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24829,9 +24829,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24863,9 +24863,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24897,9 +24897,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24931,9 +24931,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24965,9 +24965,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -24999,9 +24999,9 @@ "volume": 6.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25033,9 +25033,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25067,9 +25067,9 @@ "volume": 16.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25100,9 +25100,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25133,9 +25133,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25166,9 +25166,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -25211,9 +25211,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -25225,9 +25225,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -25246,9 +25246,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25280,9 +25280,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25314,9 +25314,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25348,9 +25348,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25382,9 +25382,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25416,9 +25416,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25450,9 +25450,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25484,9 +25484,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25518,9 +25518,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25552,9 +25552,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25586,9 +25586,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25620,9 +25620,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25654,9 +25654,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25688,9 +25688,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25722,9 +25722,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25756,9 +25756,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25790,9 +25790,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25824,9 +25824,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25858,9 +25858,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25892,9 +25892,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25926,9 +25926,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25960,9 +25960,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -25994,9 +25994,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26028,9 +26028,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26062,9 +26062,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26096,9 +26096,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26130,9 +26130,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26164,9 +26164,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26198,9 +26198,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26232,9 +26232,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26266,9 +26266,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26300,9 +26300,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26334,9 +26334,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26368,9 +26368,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26402,9 +26402,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26436,9 +26436,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26470,9 +26470,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26504,9 +26504,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26538,9 +26538,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26572,9 +26572,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26606,9 +26606,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26640,9 +26640,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26674,9 +26674,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26708,9 +26708,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26742,9 +26742,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26776,9 +26776,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26810,9 +26810,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26844,9 +26844,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26878,9 +26878,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26912,9 +26912,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26946,9 +26946,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -26980,9 +26980,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27014,9 +27014,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27048,9 +27048,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27082,9 +27082,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27116,9 +27116,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27150,9 +27150,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27184,9 +27184,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27218,9 +27218,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27252,9 +27252,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27286,9 +27286,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27320,9 +27320,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27354,9 +27354,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27388,9 +27388,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27422,9 +27422,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27456,9 +27456,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27490,9 +27490,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27524,9 +27524,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27558,9 +27558,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27592,9 +27592,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27626,9 +27626,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27660,9 +27660,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27694,9 +27694,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27728,9 +27728,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27762,9 +27762,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27796,9 +27796,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27830,9 +27830,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27864,9 +27864,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27898,9 +27898,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27932,9 +27932,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -27966,9 +27966,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28000,9 +28000,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28034,9 +28034,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28068,9 +28068,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28102,9 +28102,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28136,9 +28136,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28170,9 +28170,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28204,9 +28204,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28238,9 +28238,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28272,9 +28272,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28306,9 +28306,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28340,9 +28340,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28374,9 +28374,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28408,9 +28408,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28442,9 +28442,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28476,9 +28476,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28510,9 +28510,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28544,9 +28544,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28578,9 +28578,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28612,9 +28612,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28646,9 +28646,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28680,9 +28680,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28714,9 +28714,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28748,9 +28748,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28782,9 +28782,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28816,9 +28816,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28850,9 +28850,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28884,9 +28884,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28918,9 +28918,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28952,9 +28952,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -28986,9 +28986,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29020,9 +29020,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29054,9 +29054,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29088,9 +29088,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29122,9 +29122,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29156,9 +29156,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29190,9 +29190,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29224,9 +29224,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29258,9 +29258,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29292,9 +29292,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29326,9 +29326,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29360,9 +29360,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29394,9 +29394,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29428,9 +29428,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29462,9 +29462,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29496,9 +29496,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29530,9 +29530,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29564,9 +29564,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29598,9 +29598,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29632,9 +29632,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29666,9 +29666,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29700,9 +29700,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29734,9 +29734,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29768,9 +29768,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29802,9 +29802,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29836,9 +29836,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29870,9 +29870,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29904,9 +29904,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29938,9 +29938,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -29972,9 +29972,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30006,9 +30006,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30040,9 +30040,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30074,9 +30074,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30108,9 +30108,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30142,9 +30142,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30176,9 +30176,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30210,9 +30210,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30244,9 +30244,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30278,9 +30278,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30312,9 +30312,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30346,9 +30346,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30380,9 +30380,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30414,9 +30414,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30448,9 +30448,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30482,9 +30482,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30516,9 +30516,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30550,9 +30550,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30599,9 +30599,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30633,9 +30633,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30667,9 +30667,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30701,9 +30701,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30735,9 +30735,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30769,9 +30769,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30803,9 +30803,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30837,9 +30837,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30871,9 +30871,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30905,9 +30905,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30939,9 +30939,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -30973,9 +30973,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31007,9 +31007,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31041,9 +31041,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31075,9 +31075,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31109,9 +31109,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31143,9 +31143,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31177,9 +31177,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31211,9 +31211,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31245,9 +31245,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31279,9 +31279,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31313,9 +31313,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31347,9 +31347,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31381,9 +31381,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31415,9 +31415,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31449,9 +31449,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31483,9 +31483,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31517,9 +31517,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31551,9 +31551,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31585,9 +31585,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31619,9 +31619,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31653,9 +31653,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31687,9 +31687,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31721,9 +31721,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31755,9 +31755,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31789,9 +31789,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31823,9 +31823,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31857,9 +31857,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31891,9 +31891,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31925,9 +31925,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31958,9 +31958,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -31991,9 +31991,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32024,9 +32024,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -32084,9 +32084,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -32098,9 +32098,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -32134,9 +32134,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32168,9 +32168,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32202,9 +32202,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32236,9 +32236,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32270,9 +32270,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32304,9 +32304,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32338,9 +32338,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32372,9 +32372,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32406,9 +32406,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32440,9 +32440,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32474,9 +32474,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32508,9 +32508,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32542,9 +32542,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32576,9 +32576,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32610,9 +32610,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32644,9 +32644,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32678,9 +32678,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32712,9 +32712,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32746,9 +32746,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32780,9 +32780,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32814,9 +32814,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32848,9 +32848,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32882,9 +32882,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32916,9 +32916,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32950,9 +32950,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -32984,9 +32984,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33018,9 +33018,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33052,9 +33052,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33086,9 +33086,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33120,9 +33120,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33154,9 +33154,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33188,9 +33188,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33222,9 +33222,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33256,9 +33256,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33290,9 +33290,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33324,9 +33324,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33358,9 +33358,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33392,9 +33392,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33426,9 +33426,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33460,9 +33460,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33494,9 +33494,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33528,9 +33528,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33562,9 +33562,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33596,9 +33596,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33630,9 +33630,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33664,9 +33664,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33698,9 +33698,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33732,9 +33732,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33766,9 +33766,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33800,9 +33800,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33834,9 +33834,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33867,9 +33867,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33900,9 +33900,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33934,9 +33934,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -33983,9 +33983,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34017,9 +34017,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34051,9 +34051,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34085,9 +34085,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34119,9 +34119,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34153,9 +34153,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34187,9 +34187,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34221,9 +34221,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34255,9 +34255,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34289,9 +34289,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34323,9 +34323,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34357,9 +34357,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34391,9 +34391,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34425,9 +34425,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34459,9 +34459,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34493,9 +34493,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34527,9 +34527,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34561,9 +34561,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34595,9 +34595,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34629,9 +34629,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34663,9 +34663,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34697,9 +34697,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34731,9 +34731,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34765,9 +34765,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34799,9 +34799,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34833,9 +34833,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34867,9 +34867,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34901,9 +34901,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34935,9 +34935,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -34969,9 +34969,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35003,9 +35003,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35037,9 +35037,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35071,9 +35071,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35105,9 +35105,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35139,9 +35139,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35173,9 +35173,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35207,9 +35207,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35241,9 +35241,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35275,9 +35275,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35309,9 +35309,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35343,9 +35343,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35377,9 +35377,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35411,9 +35411,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35445,9 +35445,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35479,9 +35479,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35513,9 +35513,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35547,9 +35547,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35581,9 +35581,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35615,9 +35615,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35649,9 +35649,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35683,9 +35683,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35716,9 +35716,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35749,9 +35749,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35783,9 +35783,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35832,9 +35832,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35866,9 +35866,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35900,9 +35900,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35934,9 +35934,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -35968,9 +35968,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36002,9 +36002,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36036,9 +36036,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36070,9 +36070,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36104,9 +36104,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36138,9 +36138,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36172,9 +36172,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36206,9 +36206,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36240,9 +36240,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36274,9 +36274,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36308,9 +36308,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36342,9 +36342,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36376,9 +36376,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36410,9 +36410,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36444,9 +36444,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36478,9 +36478,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36512,9 +36512,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36546,9 +36546,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36580,9 +36580,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36614,9 +36614,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36648,9 +36648,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36682,9 +36682,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36716,9 +36716,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36750,9 +36750,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36784,9 +36784,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36818,9 +36818,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36852,9 +36852,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36886,9 +36886,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36920,9 +36920,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36954,9 +36954,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -36988,9 +36988,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37022,9 +37022,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37056,9 +37056,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37090,9 +37090,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37124,9 +37124,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37158,9 +37158,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37192,9 +37192,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37226,9 +37226,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37260,9 +37260,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37294,9 +37294,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37328,9 +37328,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37362,9 +37362,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37396,9 +37396,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37430,9 +37430,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37464,9 +37464,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37498,9 +37498,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37532,9 +37532,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37565,9 +37565,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37598,9 +37598,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37631,9 +37631,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -37676,9 +37676,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -37690,9 +37690,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -37711,9 +37711,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37745,9 +37745,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37779,9 +37779,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37813,9 +37813,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37847,9 +37847,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37881,9 +37881,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37915,9 +37915,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37949,9 +37949,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -37983,9 +37983,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38017,9 +38017,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38051,9 +38051,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38085,9 +38085,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38119,9 +38119,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38153,9 +38153,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38187,9 +38187,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38221,9 +38221,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38255,9 +38255,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38289,9 +38289,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38323,9 +38323,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38357,9 +38357,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38391,9 +38391,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38425,9 +38425,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38459,9 +38459,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38493,9 +38493,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38527,9 +38527,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38561,9 +38561,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38595,9 +38595,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38629,9 +38629,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38663,9 +38663,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38697,9 +38697,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38731,9 +38731,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38765,9 +38765,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38799,9 +38799,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38833,9 +38833,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38867,9 +38867,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38901,9 +38901,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38935,9 +38935,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -38969,9 +38969,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39003,9 +39003,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39037,9 +39037,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39071,9 +39071,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39105,9 +39105,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39139,9 +39139,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39173,9 +39173,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39207,9 +39207,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39241,9 +39241,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39275,9 +39275,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39309,9 +39309,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39343,9 +39343,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39377,9 +39377,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39411,9 +39411,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39445,9 +39445,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39479,9 +39479,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39513,9 +39513,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39547,9 +39547,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39581,9 +39581,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39615,9 +39615,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39649,9 +39649,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39683,9 +39683,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39717,9 +39717,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39751,9 +39751,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39785,9 +39785,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39819,9 +39819,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39853,9 +39853,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39887,9 +39887,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39921,9 +39921,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39955,9 +39955,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -39989,9 +39989,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40023,9 +40023,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40057,9 +40057,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40091,9 +40091,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40125,9 +40125,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40159,9 +40159,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40193,9 +40193,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40227,9 +40227,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40261,9 +40261,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40295,9 +40295,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40329,9 +40329,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40363,9 +40363,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40397,9 +40397,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40431,9 +40431,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40465,9 +40465,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40499,9 +40499,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40533,9 +40533,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40567,9 +40567,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40601,9 +40601,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40635,9 +40635,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40669,9 +40669,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40703,9 +40703,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40737,9 +40737,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40771,9 +40771,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40805,9 +40805,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40839,9 +40839,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40873,9 +40873,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40907,9 +40907,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40941,9 +40941,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -40975,9 +40975,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41009,9 +41009,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41043,9 +41043,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41077,9 +41077,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41111,9 +41111,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41145,9 +41145,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41179,9 +41179,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41213,9 +41213,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41247,9 +41247,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41281,9 +41281,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41315,9 +41315,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41349,9 +41349,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41383,9 +41383,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41417,9 +41417,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41451,9 +41451,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41485,9 +41485,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41519,9 +41519,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41553,9 +41553,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41587,9 +41587,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41621,9 +41621,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41655,9 +41655,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41689,9 +41689,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41723,9 +41723,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41757,9 +41757,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41791,9 +41791,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41825,9 +41825,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41859,9 +41859,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41893,9 +41893,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41927,9 +41927,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41961,9 +41961,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -41995,9 +41995,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42029,9 +42029,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42063,9 +42063,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42097,9 +42097,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42131,9 +42131,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42165,9 +42165,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42199,9 +42199,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42233,9 +42233,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42267,9 +42267,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42301,9 +42301,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42335,9 +42335,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42369,9 +42369,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42403,9 +42403,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42437,9 +42437,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42471,9 +42471,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42505,9 +42505,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42539,9 +42539,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42573,9 +42573,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42607,9 +42607,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42641,9 +42641,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42675,9 +42675,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42709,9 +42709,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42743,9 +42743,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42777,9 +42777,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42811,9 +42811,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42845,9 +42845,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42879,9 +42879,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42913,9 +42913,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42947,9 +42947,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -42981,9 +42981,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43015,9 +43015,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43064,9 +43064,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43098,9 +43098,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43132,9 +43132,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43166,9 +43166,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43200,9 +43200,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43234,9 +43234,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43268,9 +43268,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43302,9 +43302,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43336,9 +43336,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43370,9 +43370,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43404,9 +43404,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43438,9 +43438,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43472,9 +43472,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43506,9 +43506,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43540,9 +43540,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43574,9 +43574,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43608,9 +43608,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43642,9 +43642,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43676,9 +43676,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43710,9 +43710,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43744,9 +43744,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43778,9 +43778,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43812,9 +43812,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43846,9 +43846,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43880,9 +43880,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43914,9 +43914,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43948,9 +43948,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -43982,9 +43982,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44016,9 +44016,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44050,9 +44050,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44084,9 +44084,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44118,9 +44118,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44152,9 +44152,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44186,9 +44186,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44220,9 +44220,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44254,9 +44254,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44288,9 +44288,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44322,9 +44322,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44356,9 +44356,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44390,9 +44390,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44423,9 +44423,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44456,9 +44456,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44489,9 +44489,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44549,9 +44549,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -44563,9 +44563,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -44599,9 +44599,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44633,9 +44633,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44667,9 +44667,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44701,9 +44701,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44735,9 +44735,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44769,9 +44769,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44803,9 +44803,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44837,9 +44837,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44871,9 +44871,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44905,9 +44905,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44939,9 +44939,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -44973,9 +44973,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45007,9 +45007,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45041,9 +45041,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45075,9 +45075,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45109,9 +45109,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45143,9 +45143,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45177,9 +45177,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45211,9 +45211,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45245,9 +45245,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45279,9 +45279,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45313,9 +45313,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45347,9 +45347,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45381,9 +45381,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45415,9 +45415,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45449,9 +45449,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45483,9 +45483,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45517,9 +45517,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45551,9 +45551,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45585,9 +45585,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45619,9 +45619,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45653,9 +45653,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45687,9 +45687,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45721,9 +45721,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45755,9 +45755,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45789,9 +45789,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45823,9 +45823,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45857,9 +45857,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45891,9 +45891,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45925,9 +45925,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45959,9 +45959,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -45993,9 +45993,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46027,9 +46027,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46061,9 +46061,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46095,9 +46095,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46129,9 +46129,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46163,9 +46163,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46197,9 +46197,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46231,9 +46231,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46265,9 +46265,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46299,9 +46299,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46332,9 +46332,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46365,9 +46365,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46399,9 +46399,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46448,9 +46448,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46482,9 +46482,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46516,9 +46516,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46550,9 +46550,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46584,9 +46584,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46618,9 +46618,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46652,9 +46652,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46686,9 +46686,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46720,9 +46720,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46754,9 +46754,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46788,9 +46788,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46822,9 +46822,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46856,9 +46856,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46890,9 +46890,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46924,9 +46924,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46958,9 +46958,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -46992,9 +46992,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47026,9 +47026,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47060,9 +47060,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47094,9 +47094,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47128,9 +47128,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47162,9 +47162,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47196,9 +47196,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47230,9 +47230,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47264,9 +47264,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47298,9 +47298,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47332,9 +47332,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47366,9 +47366,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47400,9 +47400,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47434,9 +47434,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47468,9 +47468,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47502,9 +47502,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47536,9 +47536,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47570,9 +47570,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47604,9 +47604,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47638,9 +47638,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47672,9 +47672,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47706,9 +47706,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47740,9 +47740,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47774,9 +47774,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47808,9 +47808,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47842,9 +47842,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47876,9 +47876,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47910,9 +47910,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47944,9 +47944,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -47978,9 +47978,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48012,9 +48012,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48046,9 +48046,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48080,9 +48080,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48114,9 +48114,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48148,9 +48148,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48181,9 +48181,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48214,9 +48214,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48248,9 +48248,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48297,9 +48297,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48331,9 +48331,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48365,9 +48365,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48399,9 +48399,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48433,9 +48433,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48467,9 +48467,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48501,9 +48501,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48535,9 +48535,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48569,9 +48569,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48603,9 +48603,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48637,9 +48637,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48671,9 +48671,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48705,9 +48705,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48739,9 +48739,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48773,9 +48773,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48807,9 +48807,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48841,9 +48841,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48875,9 +48875,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48909,9 +48909,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48943,9 +48943,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -48977,9 +48977,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49011,9 +49011,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49045,9 +49045,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49079,9 +49079,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49113,9 +49113,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49147,9 +49147,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49181,9 +49181,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49215,9 +49215,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49249,9 +49249,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49283,9 +49283,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49317,9 +49317,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49351,9 +49351,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49385,9 +49385,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49419,9 +49419,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49453,9 +49453,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49487,9 +49487,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49521,9 +49521,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49555,9 +49555,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49589,9 +49589,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49623,9 +49623,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49657,9 +49657,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49691,9 +49691,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49725,9 +49725,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49759,9 +49759,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49793,9 +49793,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49827,9 +49827,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49861,9 +49861,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49895,9 +49895,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49929,9 +49929,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49963,9 +49963,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -49997,9 +49997,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50030,9 +50030,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50063,9 +50063,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50096,9 +50096,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -50141,9 +50141,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -50155,9 +50155,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -50176,9 +50176,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50210,9 +50210,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50244,9 +50244,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50278,9 +50278,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50312,9 +50312,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50346,9 +50346,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50380,9 +50380,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50414,9 +50414,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50448,9 +50448,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50482,9 +50482,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50516,9 +50516,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50550,9 +50550,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50584,9 +50584,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50618,9 +50618,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50652,9 +50652,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50686,9 +50686,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50720,9 +50720,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50754,9 +50754,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50788,9 +50788,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50822,9 +50822,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50856,9 +50856,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50890,9 +50890,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50924,9 +50924,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50958,9 +50958,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -50992,9 +50992,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51026,9 +51026,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51060,9 +51060,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51094,9 +51094,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51128,9 +51128,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51162,9 +51162,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51196,9 +51196,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51230,9 +51230,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51264,9 +51264,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51298,9 +51298,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51332,9 +51332,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51366,9 +51366,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51400,9 +51400,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51434,9 +51434,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51468,9 +51468,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51502,9 +51502,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51536,9 +51536,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51570,9 +51570,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51604,9 +51604,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51638,9 +51638,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51672,9 +51672,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51706,9 +51706,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51740,9 +51740,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51774,9 +51774,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51808,9 +51808,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51842,9 +51842,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51876,9 +51876,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51910,9 +51910,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51944,9 +51944,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -51978,9 +51978,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52012,9 +52012,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52046,9 +52046,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52080,9 +52080,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52114,9 +52114,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52148,9 +52148,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52182,9 +52182,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52216,9 +52216,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52250,9 +52250,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52284,9 +52284,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52318,9 +52318,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52352,9 +52352,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52386,9 +52386,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52420,9 +52420,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52454,9 +52454,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52488,9 +52488,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52522,9 +52522,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52556,9 +52556,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52590,9 +52590,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52624,9 +52624,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52658,9 +52658,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52692,9 +52692,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52726,9 +52726,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52760,9 +52760,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52794,9 +52794,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52828,9 +52828,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52862,9 +52862,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52896,9 +52896,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52930,9 +52930,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52964,9 +52964,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -52998,9 +52998,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53032,9 +53032,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53066,9 +53066,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53100,9 +53100,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53134,9 +53134,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53168,9 +53168,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53202,9 +53202,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53236,9 +53236,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53270,9 +53270,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53304,9 +53304,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53338,9 +53338,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53372,9 +53372,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53406,9 +53406,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53440,9 +53440,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53474,9 +53474,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53508,9 +53508,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53542,9 +53542,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53576,9 +53576,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53610,9 +53610,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53644,9 +53644,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53678,9 +53678,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53712,9 +53712,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53746,9 +53746,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53780,9 +53780,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53814,9 +53814,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53848,9 +53848,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53882,9 +53882,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53916,9 +53916,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53950,9 +53950,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -53984,9 +53984,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54018,9 +54018,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54052,9 +54052,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54086,9 +54086,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54120,9 +54120,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54154,9 +54154,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54188,9 +54188,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54222,9 +54222,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54256,9 +54256,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54290,9 +54290,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54324,9 +54324,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54358,9 +54358,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54392,9 +54392,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54426,9 +54426,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54460,9 +54460,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54494,9 +54494,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54528,9 +54528,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54562,9 +54562,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54596,9 +54596,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54630,9 +54630,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54664,9 +54664,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54698,9 +54698,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54732,9 +54732,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54766,9 +54766,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54800,9 +54800,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54834,9 +54834,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54868,9 +54868,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54902,9 +54902,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54936,9 +54936,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -54970,9 +54970,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55004,9 +55004,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55038,9 +55038,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55072,9 +55072,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55106,9 +55106,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55140,9 +55140,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55174,9 +55174,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55208,9 +55208,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55242,9 +55242,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55276,9 +55276,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55310,9 +55310,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55344,9 +55344,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55378,9 +55378,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55412,9 +55412,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55446,9 +55446,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55480,9 +55480,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55529,9 +55529,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55563,9 +55563,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55597,9 +55597,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55631,9 +55631,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55665,9 +55665,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55699,9 +55699,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55733,9 +55733,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55767,9 +55767,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55801,9 +55801,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55835,9 +55835,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55869,9 +55869,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55903,9 +55903,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55937,9 +55937,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -55971,9 +55971,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56005,9 +56005,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56039,9 +56039,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56073,9 +56073,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56107,9 +56107,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56141,9 +56141,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56175,9 +56175,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56209,9 +56209,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56243,9 +56243,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56277,9 +56277,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56311,9 +56311,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56345,9 +56345,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56379,9 +56379,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56413,9 +56413,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56447,9 +56447,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56481,9 +56481,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56515,9 +56515,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56549,9 +56549,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56583,9 +56583,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56617,9 +56617,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56651,9 +56651,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56685,9 +56685,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56719,9 +56719,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56753,9 +56753,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56787,9 +56787,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56821,9 +56821,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56855,9 +56855,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56888,9 +56888,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56921,9 +56921,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -56954,9 +56954,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -57014,9 +57014,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -57028,9 +57028,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -57064,9 +57064,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57098,9 +57098,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57132,9 +57132,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57166,9 +57166,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57200,9 +57200,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57234,9 +57234,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57268,9 +57268,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57302,9 +57302,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57336,9 +57336,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57370,9 +57370,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57404,9 +57404,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57438,9 +57438,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57472,9 +57472,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57506,9 +57506,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57540,9 +57540,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57574,9 +57574,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57608,9 +57608,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57642,9 +57642,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57676,9 +57676,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57710,9 +57710,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57744,9 +57744,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57778,9 +57778,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57812,9 +57812,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57846,9 +57846,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57880,9 +57880,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57914,9 +57914,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57948,9 +57948,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -57982,9 +57982,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58016,9 +58016,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58050,9 +58050,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58084,9 +58084,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58118,9 +58118,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58152,9 +58152,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58186,9 +58186,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58220,9 +58220,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58254,9 +58254,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58288,9 +58288,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58322,9 +58322,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58356,9 +58356,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58390,9 +58390,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58424,9 +58424,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58458,9 +58458,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58492,9 +58492,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58526,9 +58526,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58560,9 +58560,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58594,9 +58594,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58628,9 +58628,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58662,9 +58662,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58696,9 +58696,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58730,9 +58730,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58764,9 +58764,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58797,9 +58797,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58830,9 +58830,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58864,9 +58864,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58913,9 +58913,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58947,9 +58947,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -58981,9 +58981,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59015,9 +59015,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59049,9 +59049,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59083,9 +59083,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59117,9 +59117,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59151,9 +59151,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59185,9 +59185,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59219,9 +59219,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59253,9 +59253,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59287,9 +59287,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59321,9 +59321,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59355,9 +59355,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59389,9 +59389,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59423,9 +59423,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59457,9 +59457,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59491,9 +59491,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59525,9 +59525,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59559,9 +59559,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59593,9 +59593,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59627,9 +59627,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59661,9 +59661,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59695,9 +59695,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59729,9 +59729,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59763,9 +59763,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59797,9 +59797,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59831,9 +59831,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59865,9 +59865,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59899,9 +59899,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59933,9 +59933,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -59967,9 +59967,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60001,9 +60001,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60035,9 +60035,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60069,9 +60069,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60103,9 +60103,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60137,9 +60137,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60171,9 +60171,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60205,9 +60205,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60239,9 +60239,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60273,9 +60273,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60307,9 +60307,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60341,9 +60341,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60375,9 +60375,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60409,9 +60409,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60443,9 +60443,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60477,9 +60477,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60511,9 +60511,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60545,9 +60545,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60579,9 +60579,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60613,9 +60613,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60646,9 +60646,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60679,9 +60679,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60713,9 +60713,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60762,9 +60762,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60796,9 +60796,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60830,9 +60830,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60864,9 +60864,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60898,9 +60898,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60932,9 +60932,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -60966,9 +60966,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61000,9 +61000,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61034,9 +61034,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61068,9 +61068,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61102,9 +61102,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61136,9 +61136,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61170,9 +61170,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61204,9 +61204,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61238,9 +61238,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61272,9 +61272,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61306,9 +61306,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61340,9 +61340,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61374,9 +61374,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61408,9 +61408,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61442,9 +61442,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61476,9 +61476,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61510,9 +61510,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61544,9 +61544,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61578,9 +61578,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61612,9 +61612,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61646,9 +61646,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61680,9 +61680,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61714,9 +61714,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61748,9 +61748,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61782,9 +61782,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61816,9 +61816,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61850,9 +61850,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61884,9 +61884,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61918,9 +61918,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61952,9 +61952,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -61986,9 +61986,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62020,9 +62020,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62054,9 +62054,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62088,9 +62088,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62122,9 +62122,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62156,9 +62156,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62190,9 +62190,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62224,9 +62224,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62258,9 +62258,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62292,9 +62292,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62326,9 +62326,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62360,9 +62360,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62394,9 +62394,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62428,9 +62428,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62462,9 +62462,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62495,9 +62495,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62528,9 +62528,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62561,9 +62561,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -62606,9 +62606,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -62620,9 +62620,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -62641,9 +62641,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62675,9 +62675,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62709,9 +62709,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62743,9 +62743,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62777,9 +62777,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62811,9 +62811,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62845,9 +62845,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62879,9 +62879,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62913,9 +62913,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62947,9 +62947,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -62981,9 +62981,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63015,9 +63015,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63049,9 +63049,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63083,9 +63083,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63117,9 +63117,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63151,9 +63151,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63185,9 +63185,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63219,9 +63219,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63253,9 +63253,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63287,9 +63287,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63321,9 +63321,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63355,9 +63355,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63389,9 +63389,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63423,9 +63423,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63457,9 +63457,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63491,9 +63491,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63525,9 +63525,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63559,9 +63559,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63593,9 +63593,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63627,9 +63627,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63661,9 +63661,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63695,9 +63695,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63729,9 +63729,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63763,9 +63763,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63797,9 +63797,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63831,9 +63831,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63865,9 +63865,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63899,9 +63899,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63933,9 +63933,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -63967,9 +63967,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64001,9 +64001,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64035,9 +64035,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64069,9 +64069,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64103,9 +64103,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64137,9 +64137,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64171,9 +64171,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64205,9 +64205,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64239,9 +64239,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64273,9 +64273,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64307,9 +64307,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64341,9 +64341,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64375,9 +64375,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64409,9 +64409,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64443,9 +64443,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64477,9 +64477,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64511,9 +64511,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64545,9 +64545,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64579,9 +64579,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64613,9 +64613,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64647,9 +64647,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64681,9 +64681,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64715,9 +64715,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64749,9 +64749,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64783,9 +64783,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64817,9 +64817,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64851,9 +64851,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64885,9 +64885,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64919,9 +64919,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64953,9 +64953,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -64987,9 +64987,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65021,9 +65021,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65055,9 +65055,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65089,9 +65089,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65123,9 +65123,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65157,9 +65157,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65191,9 +65191,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65225,9 +65225,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65259,9 +65259,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65293,9 +65293,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65327,9 +65327,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65361,9 +65361,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65395,9 +65395,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65429,9 +65429,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65463,9 +65463,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65497,9 +65497,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65531,9 +65531,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65565,9 +65565,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65599,9 +65599,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65633,9 +65633,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65667,9 +65667,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65701,9 +65701,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65735,9 +65735,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65784,9 +65784,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65818,9 +65818,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65852,9 +65852,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65886,9 +65886,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65920,9 +65920,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65954,9 +65954,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -65988,9 +65988,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66022,9 +66022,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66056,9 +66056,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66090,9 +66090,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66124,9 +66124,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66158,9 +66158,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66192,9 +66192,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66226,9 +66226,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66260,9 +66260,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66294,9 +66294,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66328,9 +66328,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66362,9 +66362,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66396,9 +66396,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66430,9 +66430,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66464,9 +66464,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66498,9 +66498,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66532,9 +66532,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66566,9 +66566,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66600,9 +66600,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66634,9 +66634,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66668,9 +66668,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66702,9 +66702,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66736,9 +66736,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66770,9 +66770,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66804,9 +66804,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66838,9 +66838,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66872,9 +66872,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66906,9 +66906,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66940,9 +66940,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -66974,9 +66974,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67008,9 +67008,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67042,9 +67042,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67076,9 +67076,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67110,9 +67110,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67143,9 +67143,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67176,9 +67176,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67209,9 +67209,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -67269,9 +67269,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -67283,9 +67283,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -67319,9 +67319,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67353,9 +67353,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67387,9 +67387,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67421,9 +67421,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67455,9 +67455,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67489,9 +67489,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67523,9 +67523,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67557,9 +67557,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67591,9 +67591,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67625,9 +67625,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67659,9 +67659,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67693,9 +67693,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67727,9 +67727,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67761,9 +67761,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67795,9 +67795,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67829,9 +67829,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67863,9 +67863,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67897,9 +67897,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67931,9 +67931,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67965,9 +67965,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -67999,9 +67999,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68033,9 +68033,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68067,9 +68067,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68101,9 +68101,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68135,9 +68135,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68169,9 +68169,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68203,9 +68203,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68237,9 +68237,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68271,9 +68271,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68305,9 +68305,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68339,9 +68339,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68373,9 +68373,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68407,9 +68407,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68441,9 +68441,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68475,9 +68475,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68509,9 +68509,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68543,9 +68543,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68577,9 +68577,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68611,9 +68611,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68645,9 +68645,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68679,9 +68679,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68713,9 +68713,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68747,9 +68747,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68781,9 +68781,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68815,9 +68815,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68848,9 +68848,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68881,9 +68881,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68915,9 +68915,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68964,9 +68964,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -68998,9 +68998,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69032,9 +69032,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69066,9 +69066,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69100,9 +69100,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69134,9 +69134,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69168,9 +69168,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69202,9 +69202,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69236,9 +69236,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69270,9 +69270,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69304,9 +69304,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69338,9 +69338,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69372,9 +69372,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69406,9 +69406,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69440,9 +69440,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69474,9 +69474,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69508,9 +69508,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69542,9 +69542,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69576,9 +69576,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69610,9 +69610,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69644,9 +69644,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69678,9 +69678,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69712,9 +69712,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69746,9 +69746,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69780,9 +69780,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69814,9 +69814,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69848,9 +69848,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69882,9 +69882,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69916,9 +69916,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69950,9 +69950,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -69984,9 +69984,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70018,9 +70018,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70052,9 +70052,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70086,9 +70086,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70120,9 +70120,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70154,9 +70154,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70188,9 +70188,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70222,9 +70222,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70256,9 +70256,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70290,9 +70290,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70324,9 +70324,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70358,9 +70358,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70392,9 +70392,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70426,9 +70426,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70460,9 +70460,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70493,9 +70493,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70526,9 +70526,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70559,9 +70559,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -70604,9 +70604,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -70618,9 +70618,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -70639,9 +70639,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70673,9 +70673,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70707,9 +70707,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70741,9 +70741,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70775,9 +70775,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70809,9 +70809,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70843,9 +70843,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70877,9 +70877,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70911,9 +70911,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70945,9 +70945,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -70979,9 +70979,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71013,9 +71013,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71047,9 +71047,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71081,9 +71081,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71115,9 +71115,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71164,9 +71164,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71198,9 +71198,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71232,9 +71232,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71266,9 +71266,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71300,9 +71300,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71334,9 +71334,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71368,9 +71368,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71402,9 +71402,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71436,9 +71436,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71470,9 +71470,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71504,9 +71504,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71538,9 +71538,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71572,9 +71572,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71606,9 +71606,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71640,9 +71640,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71674,9 +71674,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71708,9 +71708,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71742,9 +71742,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71776,9 +71776,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71810,9 +71810,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71844,9 +71844,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71878,9 +71878,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71912,9 +71912,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71946,9 +71946,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -71980,9 +71980,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72014,9 +72014,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72048,9 +72048,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72082,9 +72082,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72116,9 +72116,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72150,9 +72150,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72184,9 +72184,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72218,9 +72218,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72252,9 +72252,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72286,9 +72286,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72320,9 +72320,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72354,9 +72354,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72388,9 +72388,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72422,9 +72422,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72456,9 +72456,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72490,9 +72490,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72523,9 +72523,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72556,9 +72556,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72589,9 +72589,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -72632,9 +72632,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -72646,9 +72646,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 31.000000000000004, - "tipVolume": 20 + "tipVolume": 20.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -72667,9 +72667,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72701,9 +72701,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72735,9 +72735,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72769,9 +72769,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72803,9 +72803,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72837,9 +72837,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72871,9 +72871,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72905,9 +72905,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72939,9 +72939,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -72973,9 +72973,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73007,9 +73007,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73041,9 +73041,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73075,9 +73075,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73109,9 +73109,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73143,9 +73143,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73177,9 +73177,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73211,9 +73211,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73245,9 +73245,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73279,9 +73279,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73313,9 +73313,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73347,9 +73347,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73381,9 +73381,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73415,9 +73415,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73449,9 +73449,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73483,9 +73483,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73517,9 +73517,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73551,9 +73551,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73585,9 +73585,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73619,9 +73619,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73653,9 +73653,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73687,9 +73687,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73721,9 +73721,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73755,9 +73755,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73789,9 +73789,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73823,9 +73823,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73857,9 +73857,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73891,9 +73891,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73925,9 +73925,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73959,9 +73959,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -73993,9 +73993,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74027,9 +74027,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74061,9 +74061,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74095,9 +74095,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74129,9 +74129,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74163,9 +74163,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74197,9 +74197,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74231,9 +74231,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74265,9 +74265,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74299,9 +74299,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74333,9 +74333,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74367,9 +74367,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74401,9 +74401,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74435,9 +74435,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74469,9 +74469,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74503,9 +74503,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74537,9 +74537,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74571,9 +74571,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74605,9 +74605,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74639,9 +74639,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74673,9 +74673,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74707,9 +74707,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74741,9 +74741,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74775,9 +74775,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74809,9 +74809,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74843,9 +74843,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74877,9 +74877,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74911,9 +74911,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74945,9 +74945,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -74979,9 +74979,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75013,9 +75013,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75047,9 +75047,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75081,9 +75081,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75115,9 +75115,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75149,9 +75149,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75183,9 +75183,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75217,9 +75217,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75251,9 +75251,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75285,9 +75285,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75319,9 +75319,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75353,9 +75353,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75387,9 +75387,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75421,9 +75421,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75455,9 +75455,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75489,9 +75489,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75523,9 +75523,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75557,9 +75557,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75591,9 +75591,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75625,9 +75625,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75659,9 +75659,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75693,9 +75693,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75727,9 +75727,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75761,9 +75761,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75795,9 +75795,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75829,9 +75829,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75863,9 +75863,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75897,9 +75897,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75931,9 +75931,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75965,9 +75965,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -75999,9 +75999,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76033,9 +76033,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76067,9 +76067,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76101,9 +76101,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76135,9 +76135,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76169,9 +76169,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76203,9 +76203,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76237,9 +76237,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76271,9 +76271,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76305,9 +76305,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76339,9 +76339,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76373,9 +76373,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76407,9 +76407,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76441,9 +76441,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76475,9 +76475,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76509,9 +76509,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76543,9 +76543,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76577,9 +76577,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76611,9 +76611,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76645,9 +76645,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76679,9 +76679,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76713,9 +76713,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76747,9 +76747,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76781,9 +76781,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76815,9 +76815,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76849,9 +76849,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76883,9 +76883,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76917,9 +76917,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76951,9 +76951,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -76985,9 +76985,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77019,9 +77019,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77053,9 +77053,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77087,9 +77087,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77121,9 +77121,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77155,9 +77155,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77189,9 +77189,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77223,9 +77223,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77257,9 +77257,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77291,9 +77291,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77325,9 +77325,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77359,9 +77359,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77393,9 +77393,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77427,9 +77427,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77461,9 +77461,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77495,9 +77495,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77529,9 +77529,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77563,9 +77563,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77597,9 +77597,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77631,9 +77631,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77665,9 +77665,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77699,9 +77699,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77733,9 +77733,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77767,9 +77767,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77801,9 +77801,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77835,9 +77835,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77869,9 +77869,9 @@ "volume": 20.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77903,9 +77903,9 @@ "volume": 6.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77937,9 +77937,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -77971,9 +77971,9 @@ "volume": 16.666666666666657, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78020,9 +78020,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78054,9 +78054,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78088,9 +78088,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78122,9 +78122,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78156,9 +78156,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78190,9 +78190,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78224,9 +78224,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78258,9 +78258,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78292,9 +78292,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78326,9 +78326,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78360,9 +78360,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78394,9 +78394,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78428,9 +78428,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78462,9 +78462,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78496,9 +78496,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78530,9 +78530,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78564,9 +78564,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78598,9 +78598,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78632,9 +78632,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78666,9 +78666,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78700,9 +78700,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78734,9 +78734,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78768,9 +78768,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78802,9 +78802,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78836,9 +78836,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78870,9 +78870,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78904,9 +78904,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78938,9 +78938,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -78972,9 +78972,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79006,9 +79006,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79040,9 +79040,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79074,9 +79074,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79108,9 +79108,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79142,9 +79142,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79176,9 +79176,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79210,9 +79210,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79244,9 +79244,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79278,9 +79278,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79312,9 +79312,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79346,9 +79346,9 @@ "volume": 18.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79379,9 +79379,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79412,9 +79412,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79445,9 +79445,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -79518,9 +79518,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -79532,9 +79532,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 51.099999999999994, - "tipVolume": 300 + "tipVolume": 300.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -79568,9 +79568,9 @@ "volume": 166.66666666666666, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79602,9 +79602,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79636,9 +79636,9 @@ "volume": 176.66666666666666, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79669,9 +79669,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79702,9 +79702,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79736,9 +79736,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79785,9 +79785,9 @@ "volume": 166.66666666666666, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79819,9 +79819,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79853,9 +79853,9 @@ "volume": 176.66666666666666, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79886,9 +79886,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79919,9 +79919,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -79953,9 +79953,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80002,9 +80002,9 @@ "volume": 166.66666666666666, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80036,9 +80036,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80070,9 +80070,9 @@ "volume": 176.66666666666666, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80103,9 +80103,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80136,9 +80136,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80169,9 +80169,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -80214,9 +80214,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -80228,9 +80228,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 51.099999999999994, - "tipVolume": 300 + "tipVolume": 300.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -80249,9 +80249,9 @@ "volume": 50.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80298,9 +80298,9 @@ "volume": 50.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80347,9 +80347,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80381,9 +80381,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80415,9 +80415,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80449,9 +80449,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80483,9 +80483,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80517,9 +80517,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80551,9 +80551,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80585,9 +80585,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80619,9 +80619,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80653,9 +80653,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80687,9 +80687,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80721,9 +80721,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80755,9 +80755,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80789,9 +80789,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80823,9 +80823,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80857,9 +80857,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80891,9 +80891,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80925,9 +80925,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80959,9 +80959,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -80993,9 +80993,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81027,9 +81027,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81061,9 +81061,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81095,9 +81095,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81129,9 +81129,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81163,9 +81163,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81197,9 +81197,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81231,9 +81231,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81265,9 +81265,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81299,9 +81299,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81333,9 +81333,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81367,9 +81367,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81401,9 +81401,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81435,9 +81435,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81469,9 +81469,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81503,9 +81503,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81537,9 +81537,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81571,9 +81571,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81605,9 +81605,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81639,9 +81639,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81673,9 +81673,9 @@ "volume": 5.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81706,9 +81706,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81739,9 +81739,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81772,9 +81772,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -81832,9 +81832,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top" }, @@ -81846,9 +81846,9 @@ "y": 0.0, "z": 0.0 }, - "tipDiameter": 0, + "tipDiameter": 0.0, "tipLength": 51.099999999999994, - "tipVolume": 300 + "tipVolume": 300.0 }, "startedAt": "TIMESTAMP", "status": "succeeded" @@ -81867,9 +81867,9 @@ "volume": 50.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81901,9 +81901,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81935,9 +81935,9 @@ "volume": 60.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -81968,9 +81968,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -82001,9 +82001,9 @@ "volume": 10.0, "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "top", "volumeOffset": 0.0 @@ -82034,9 +82034,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1d37cbc080][pl_MagMax_RNA_Cells_Flex_multi].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1d37cbc080][pl_MagMax_RNA_Cells_Flex_multi].json index 6258b8500a1..03bb82c7b3c 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1d37cbc080][pl_MagMax_RNA_Cells_Flex_multi].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1d37cbc080][pl_MagMax_RNA_Cells_Flex_multi].json @@ -12766,9 +12766,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -13646,9 +13646,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -14526,9 +14526,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16474,9 +16474,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -17354,9 +17354,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -18234,9 +18234,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19114,9 +19114,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[238912ff51][Flex_S_v2_18_KAPA_Library_Quant].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[238912ff51][Flex_S_v2_18_KAPA_Library_Quant].json index a18cfa29797..f98ef8886da 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[238912ff51][Flex_S_v2_18_KAPA_Library_Quant].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[238912ff51][Flex_S_v2_18_KAPA_Library_Quant].json @@ -12914,9 +12914,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15070,9 +15070,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16025,9 +16025,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16980,9 +16980,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -17949,9 +17949,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -18904,9 +18904,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19859,9 +19859,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20549,9 +20549,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21145,9 +21145,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21741,9 +21741,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22777,9 +22777,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -23771,9 +23771,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -24765,9 +24765,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -26946,9 +26946,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[248a2a3107][pl_Omega_HDQ_DNA_Cells_Flex_96_channel].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[248a2a3107][pl_Omega_HDQ_DNA_Cells_Flex_96_channel].json index 6e3feab4269..427cd1c997b 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[248a2a3107][pl_Omega_HDQ_DNA_Cells_Flex_96_channel].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[248a2a3107][pl_Omega_HDQ_DNA_Cells_Flex_96_channel].json @@ -28560,9 +28560,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31094,9 +31094,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31352,9 +31352,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31532,9 +31532,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31772,9 +31772,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31952,9 +31952,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -32192,9 +32192,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -32372,9 +32372,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -32612,9 +32612,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -34792,9 +34792,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35050,9 +35050,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[277961bc58][pl_NiNTA_Flex_96well_final].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[277961bc58][pl_NiNTA_Flex_96well_final].json index 6a4c99f2bbc..7602c8613f4 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[277961bc58][pl_NiNTA_Flex_96well_final].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[277961bc58][pl_NiNTA_Flex_96well_final].json @@ -20073,9 +20073,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20336,9 +20336,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20599,9 +20599,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20862,9 +20862,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21125,9 +21125,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21388,9 +21388,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21651,9 +21651,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -21914,9 +21914,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22177,9 +22177,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22440,9 +22440,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22703,9 +22703,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -22966,9 +22966,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -23317,9 +23317,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -23547,9 +23547,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -23777,9 +23777,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -24007,9 +24007,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -24237,9 +24237,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -24467,9 +24467,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -24697,9 +24697,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -24927,9 +24927,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -25157,9 +25157,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -25387,9 +25387,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -25617,9 +25617,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -25847,9 +25847,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -26158,9 +26158,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -26421,9 +26421,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -26684,9 +26684,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -26947,9 +26947,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27210,9 +27210,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27473,9 +27473,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27736,9 +27736,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -27999,9 +27999,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -28262,9 +28262,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -28525,9 +28525,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -28788,9 +28788,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29051,9 +29051,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29402,9 +29402,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29632,9 +29632,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -29862,9 +29862,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -30092,9 +30092,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -30322,9 +30322,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -30552,9 +30552,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -30782,9 +30782,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31012,9 +31012,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31242,9 +31242,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31472,9 +31472,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31702,9 +31702,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -31932,9 +31932,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -32243,9 +32243,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -32506,9 +32506,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -32769,9 +32769,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -33032,9 +33032,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -33295,9 +33295,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -33558,9 +33558,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -33821,9 +33821,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -34084,9 +34084,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -34347,9 +34347,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -34610,9 +34610,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -34873,9 +34873,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35136,9 +35136,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35518,9 +35518,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35748,9 +35748,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -35978,9 +35978,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36208,9 +36208,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36438,9 +36438,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36668,9 +36668,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -36898,9 +36898,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -37128,9 +37128,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -37358,9 +37358,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -37588,9 +37588,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -37818,9 +37818,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -38048,9 +38048,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -38359,9 +38359,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -38622,9 +38622,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -38885,9 +38885,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -39148,9 +39148,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -39411,9 +39411,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -39674,9 +39674,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -39937,9 +39937,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40200,9 +40200,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40463,9 +40463,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40726,9 +40726,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -40989,9 +40989,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -41252,9 +41252,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -41603,9 +41603,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -41833,9 +41833,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42063,9 +42063,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42293,9 +42293,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42523,9 +42523,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42753,9 +42753,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -42983,9 +42983,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -43213,9 +43213,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -43443,9 +43443,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -43673,9 +43673,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -43903,9 +43903,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44133,9 +44133,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44444,9 +44444,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44707,9 +44707,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -44970,9 +44970,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -45233,9 +45233,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -45496,9 +45496,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -45759,9 +45759,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46022,9 +46022,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46285,9 +46285,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46548,9 +46548,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -46811,9 +46811,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -47074,9 +47074,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -47337,9 +47337,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -47688,9 +47688,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -47918,9 +47918,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -48148,9 +48148,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -48378,9 +48378,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -48608,9 +48608,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -48838,9 +48838,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -49068,9 +49068,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -49298,9 +49298,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -49528,9 +49528,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -49758,9 +49758,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -49988,9 +49988,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -50218,9 +50218,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -50529,9 +50529,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -50792,9 +50792,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -51055,9 +51055,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -51318,9 +51318,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -51581,9 +51581,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -51844,9 +51844,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -52107,9 +52107,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -52370,9 +52370,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -52633,9 +52633,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -52896,9 +52896,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -53159,9 +53159,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -53422,9 +53422,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -53854,9 +53854,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -54117,9 +54117,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -54380,9 +54380,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -54643,9 +54643,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -54906,9 +54906,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -55169,9 +55169,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -55432,9 +55432,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -55695,9 +55695,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -55958,9 +55958,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -56221,9 +56221,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -56484,9 +56484,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -56747,9 +56747,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[28fdeebdd9][pl_Omega_HDQ_DNA_Cells_Flex_multi].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[28fdeebdd9][pl_Omega_HDQ_DNA_Cells_Flex_multi].json index d52ff5e72e4..1598272fc5c 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[28fdeebdd9][pl_Omega_HDQ_DNA_Cells_Flex_multi].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[28fdeebdd9][pl_Omega_HDQ_DNA_Cells_Flex_multi].json @@ -14220,9 +14220,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -14987,9 +14987,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -15754,9 +15754,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -16521,9 +16521,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[29bb5df52d][pl_Omega_HDQ_DNA_Bacteria_Flex_multi].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[29bb5df52d][pl_Omega_HDQ_DNA_Bacteria_Flex_multi].json index e8cb6c52713..d6a2126b774 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[29bb5df52d][pl_Omega_HDQ_DNA_Bacteria_Flex_multi].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[29bb5df52d][pl_Omega_HDQ_DNA_Bacteria_Flex_multi].json @@ -17037,9 +17037,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -17819,9 +17819,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -18601,9 +18601,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -19383,9 +19383,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, @@ -20026,9 +20026,9 @@ "pipetteId": "UUID", "wellLocation": { "offset": { - "x": 0, - "y": 0, - "z": 0 + "x": 0.0, + "y": 0.0, + "z": 0.0 }, "origin": "default" }, diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2bc6830494][pl_langone_ribo_pt1_ramp].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2bc6830494][pl_langone_ribo_pt1_ramp].json index 9e8f25df1f1..103852d1fad 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2bc6830494][pl_langone_ribo_pt1_ramp].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2bc6830494][pl_langone_ribo_pt1_ramp].json @@ -5958,25759 +5958,6 @@ }, "startedAt": "TIMESTAMP", "status": "succeeded" - }, - { - "commandType": "loadLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c06d611a9cd16f109d926a07372b0d89", - "notes": [], - "params": { - "displayName": "8", - "loadName": "nest_96_wellplate_2ml_deep", - "location": { - "moduleId": "UUID" - }, - "namespace": "opentrons", - "version": 2 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "NEST", - "brandId": [ - "503001", - "503501" - ], - "links": [ - "https://www.nest-biotech.com/deep-well-plates/59253726.html" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.6, - "yDimension": 85.3, - "zDimension": 41 - }, - "gripForce": 15.0, - "gripHeightFromLabwareBottom": 21.9, - "gripperOffsets": {}, - "groups": [ - { - "brand": { - "brand": "NEST", - "brandId": [] - }, - "metadata": { - "displayCategory": "wellPlate", - "displayName": "NEST 96 Deep Well Plate 2mL", - "wellBottomShape": "v" - }, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "wellPlate", - "displayName": "NEST 96 Deep Well Plate 2mL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": true, - "isTiprack": false, - "loadName": "nest_96_wellplate_2ml_deep", - "magneticModuleEngageHeight": 6.8, - "quirks": [] - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": { - "opentrons_96_deep_well_adapter": { - "x": 0, - "y": 0, - "z": 16.3 - }, - "opentrons_96_deep_well_temp_mod_adapter": { - "x": 0, - "y": 0, - "z": 16.1 - } - }, - "stackingOffsetWithModule": { - "magneticBlockV1": { - "x": 0, - "y": 0, - "z": 2.66 - } - }, - "version": 2, - "wells": { - "A1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "B1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "C1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "D1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "E1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "F1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "G1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "H1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - } - } - }, - "labwareId": "UUID" - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "heaterShaker/closeLabwareLatch", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7b9b3bc1ec8ef40fd43a1478e9a1896d", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "80d3c25d5533b9c4f4b83a66d4af895e", - "notes": [], - "params": { - "loadName": "nest_12_reservoir_15ml", - "location": { - "slotName": "A2" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "NEST", - "brandId": [ - "360102" - ], - "links": [ - "https://www.nest-biotech.com/reagent-reserviors/59178414.html" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 31.4 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": { - "wellBottomShape": "v" - }, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9" - ] - } - ], - "metadata": { - "displayCategory": "reservoir", - "displayName": "NEST 12 Well Reservoir 15 mL", - "displayVolumeUnits": "mL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1" - ], - [ - "A10" - ], - [ - "A11" - ], - [ - "A12" - ], - [ - "A2" - ], - [ - "A3" - ], - [ - "A4" - ], - [ - "A5" - ], - [ - "A6" - ], - [ - "A7" - ], - [ - "A8" - ], - [ - "A9" - ] - ], - "parameters": { - "format": "trough", - "isMagneticModuleCompatible": false, - "isTiprack": false, - "loadName": "nest_12_reservoir_15ml", - "quirks": [ - "centerMultichannelOnWells", - "touchTipDisabled" - ] - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 14.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A10": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 95.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A11": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 104.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A12": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 113.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A2": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 23.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A3": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 32.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A4": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 41.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A5": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 50.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A6": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 59.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A7": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 68.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A8": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 77.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A9": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 86.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - } - } - }, - "labwareId": "UUID" - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "39705bcf605998607e3ff52963471b4d", - "notes": [], - "params": { - "loadName": "opentrons_flex_96_tiprack_50ul", - "location": { - "slotName": "C1" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.75, - "yDimension": 85.75, - "zDimension": 99 - }, - "gripForce": 16.0, - "gripHeightFromLabwareBottom": 23.9, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons Flex 96 Tip Rack 50 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_flex_96_tiprack_50ul", - "quirks": [], - "tipLength": 57.9, - "tipOverlap": 10.5 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": { - "opentrons_flex_96_tiprack_adapter": { - "x": 0, - "y": 0, - "z": 121 - } - }, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 74.38, - "z": 1.5 - }, - "A10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 74.38, - "z": 1.5 - }, - "A11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 74.38, - "z": 1.5 - }, - "A12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 74.38, - "z": 1.5 - }, - "A2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 74.38, - "z": 1.5 - }, - "A3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 74.38, - "z": 1.5 - }, - "A4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 74.38, - "z": 1.5 - }, - "A5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 74.38, - "z": 1.5 - }, - "A6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 74.38, - "z": 1.5 - }, - "A7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 74.38, - "z": 1.5 - }, - "A8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 74.38, - "z": 1.5 - }, - "A9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 74.38, - "z": 1.5 - }, - "B1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 65.38, - "z": 1.5 - }, - "B10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 65.38, - "z": 1.5 - }, - "B11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 65.38, - "z": 1.5 - }, - "B12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 65.38, - "z": 1.5 - }, - "B2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 65.38, - "z": 1.5 - }, - "B3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 65.38, - "z": 1.5 - }, - "B4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 65.38, - "z": 1.5 - }, - "B5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 65.38, - "z": 1.5 - }, - "B6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 65.38, - "z": 1.5 - }, - "B7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 65.38, - "z": 1.5 - }, - "B8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 65.38, - "z": 1.5 - }, - "B9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 65.38, - "z": 1.5 - }, - "C1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 56.38, - "z": 1.5 - }, - "C10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 56.38, - "z": 1.5 - }, - "C11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 56.38, - "z": 1.5 - }, - "C12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 56.38, - "z": 1.5 - }, - "C2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 56.38, - "z": 1.5 - }, - "C3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 56.38, - "z": 1.5 - }, - "C4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 56.38, - "z": 1.5 - }, - "C5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 56.38, - "z": 1.5 - }, - "C6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 56.38, - "z": 1.5 - }, - "C7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 56.38, - "z": 1.5 - }, - "C8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 56.38, - "z": 1.5 - }, - "C9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 56.38, - "z": 1.5 - }, - "D1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 47.38, - "z": 1.5 - }, - "D10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 47.38, - "z": 1.5 - }, - "D11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 47.38, - "z": 1.5 - }, - "D12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 47.38, - "z": 1.5 - }, - "D2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 47.38, - "z": 1.5 - }, - "D3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 47.38, - "z": 1.5 - }, - "D4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 47.38, - "z": 1.5 - }, - "D5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 47.38, - "z": 1.5 - }, - "D6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 47.38, - "z": 1.5 - }, - "D7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 47.38, - "z": 1.5 - }, - "D8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 47.38, - "z": 1.5 - }, - "D9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 47.38, - "z": 1.5 - }, - "E1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 38.38, - "z": 1.5 - }, - "E10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 38.38, - "z": 1.5 - }, - "E11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 38.38, - "z": 1.5 - }, - "E12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 38.38, - "z": 1.5 - }, - "E2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 38.38, - "z": 1.5 - }, - "E3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 38.38, - "z": 1.5 - }, - "E4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 38.38, - "z": 1.5 - }, - "E5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 38.38, - "z": 1.5 - }, - "E6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 38.38, - "z": 1.5 - }, - "E7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 38.38, - "z": 1.5 - }, - "E8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 38.38, - "z": 1.5 - }, - "E9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 38.38, - "z": 1.5 - }, - "F1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 29.38, - "z": 1.5 - }, - "F10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 29.38, - "z": 1.5 - }, - "F11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 29.38, - "z": 1.5 - }, - "F12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 29.38, - "z": 1.5 - }, - "F2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 29.38, - "z": 1.5 - }, - "F3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 29.38, - "z": 1.5 - }, - "F4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 29.38, - "z": 1.5 - }, - "F5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 29.38, - "z": 1.5 - }, - "F6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 29.38, - "z": 1.5 - }, - "F7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 29.38, - "z": 1.5 - }, - "F8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 29.38, - "z": 1.5 - }, - "F9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 29.38, - "z": 1.5 - }, - "G1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 20.38, - "z": 1.5 - }, - "G10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 20.38, - "z": 1.5 - }, - "G11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 20.38, - "z": 1.5 - }, - "G12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 20.38, - "z": 1.5 - }, - "G2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 20.38, - "z": 1.5 - }, - "G3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 20.38, - "z": 1.5 - }, - "G4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 20.38, - "z": 1.5 - }, - "G5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 20.38, - "z": 1.5 - }, - "G6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 20.38, - "z": 1.5 - }, - "G7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 20.38, - "z": 1.5 - }, - "G8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 20.38, - "z": 1.5 - }, - "G9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 20.38, - "z": 1.5 - }, - "H1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 11.38, - "z": 1.5 - }, - "H10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 11.38, - "z": 1.5 - }, - "H11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 11.38, - "z": 1.5 - }, - "H12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 11.38, - "z": 1.5 - }, - "H2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 11.38, - "z": 1.5 - }, - "H3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 11.38, - "z": 1.5 - }, - "H4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 11.38, - "z": 1.5 - }, - "H5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 11.38, - "z": 1.5 - }, - "H6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 11.38, - "z": 1.5 - }, - "H7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 11.38, - "z": 1.5 - }, - "H8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 11.38, - "z": 1.5 - }, - "H9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 11.38, - "z": 1.5 - } - } - }, - "labwareId": "UUID" - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "16e6802c3a90fa35fd3ad8570a56c95d", - "notes": [], - "params": { - "loadName": "opentrons_flex_96_tiprack_50ul", - "location": { - "slotName": "C2" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.75, - "yDimension": 85.75, - "zDimension": 99 - }, - "gripForce": 16.0, - "gripHeightFromLabwareBottom": 23.9, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons Flex 96 Tip Rack 50 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_flex_96_tiprack_50ul", - "quirks": [], - "tipLength": 57.9, - "tipOverlap": 10.5 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": { - "opentrons_flex_96_tiprack_adapter": { - "x": 0, - "y": 0, - "z": 121 - } - }, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 74.38, - "z": 1.5 - }, - "A10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 74.38, - "z": 1.5 - }, - "A11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 74.38, - "z": 1.5 - }, - "A12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 74.38, - "z": 1.5 - }, - "A2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 74.38, - "z": 1.5 - }, - "A3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 74.38, - "z": 1.5 - }, - "A4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 74.38, - "z": 1.5 - }, - "A5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 74.38, - "z": 1.5 - }, - "A6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 74.38, - "z": 1.5 - }, - "A7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 74.38, - "z": 1.5 - }, - "A8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 74.38, - "z": 1.5 - }, - "A9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 74.38, - "z": 1.5 - }, - "B1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 65.38, - "z": 1.5 - }, - "B10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 65.38, - "z": 1.5 - }, - "B11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 65.38, - "z": 1.5 - }, - "B12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 65.38, - "z": 1.5 - }, - "B2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 65.38, - "z": 1.5 - }, - "B3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 65.38, - "z": 1.5 - }, - "B4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 65.38, - "z": 1.5 - }, - "B5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 65.38, - "z": 1.5 - }, - "B6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 65.38, - "z": 1.5 - }, - "B7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 65.38, - "z": 1.5 - }, - "B8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 65.38, - "z": 1.5 - }, - "B9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 65.38, - "z": 1.5 - }, - "C1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 56.38, - "z": 1.5 - }, - "C10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 56.38, - "z": 1.5 - }, - "C11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 56.38, - "z": 1.5 - }, - "C12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 56.38, - "z": 1.5 - }, - "C2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 56.38, - "z": 1.5 - }, - "C3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 56.38, - "z": 1.5 - }, - "C4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 56.38, - "z": 1.5 - }, - "C5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 56.38, - "z": 1.5 - }, - "C6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 56.38, - "z": 1.5 - }, - "C7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 56.38, - "z": 1.5 - }, - "C8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 56.38, - "z": 1.5 - }, - "C9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 56.38, - "z": 1.5 - }, - "D1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 47.38, - "z": 1.5 - }, - "D10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 47.38, - "z": 1.5 - }, - "D11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 47.38, - "z": 1.5 - }, - "D12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 47.38, - "z": 1.5 - }, - "D2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 47.38, - "z": 1.5 - }, - "D3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 47.38, - "z": 1.5 - }, - "D4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 47.38, - "z": 1.5 - }, - "D5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 47.38, - "z": 1.5 - }, - "D6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 47.38, - "z": 1.5 - }, - "D7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 47.38, - "z": 1.5 - }, - "D8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 47.38, - "z": 1.5 - }, - "D9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 47.38, - "z": 1.5 - }, - "E1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 38.38, - "z": 1.5 - }, - "E10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 38.38, - "z": 1.5 - }, - "E11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 38.38, - "z": 1.5 - }, - "E12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 38.38, - "z": 1.5 - }, - "E2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 38.38, - "z": 1.5 - }, - "E3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 38.38, - "z": 1.5 - }, - "E4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 38.38, - "z": 1.5 - }, - "E5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 38.38, - "z": 1.5 - }, - "E6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 38.38, - "z": 1.5 - }, - "E7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 38.38, - "z": 1.5 - }, - "E8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 38.38, - "z": 1.5 - }, - "E9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 38.38, - "z": 1.5 - }, - "F1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 29.38, - "z": 1.5 - }, - "F10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 29.38, - "z": 1.5 - }, - "F11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 29.38, - "z": 1.5 - }, - "F12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 29.38, - "z": 1.5 - }, - "F2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 29.38, - "z": 1.5 - }, - "F3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 29.38, - "z": 1.5 - }, - "F4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 29.38, - "z": 1.5 - }, - "F5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 29.38, - "z": 1.5 - }, - "F6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 29.38, - "z": 1.5 - }, - "F7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 29.38, - "z": 1.5 - }, - "F8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 29.38, - "z": 1.5 - }, - "F9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 29.38, - "z": 1.5 - }, - "G1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 20.38, - "z": 1.5 - }, - "G10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 20.38, - "z": 1.5 - }, - "G11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 20.38, - "z": 1.5 - }, - "G12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 20.38, - "z": 1.5 - }, - "G2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 20.38, - "z": 1.5 - }, - "G3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 20.38, - "z": 1.5 - }, - "G4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 20.38, - "z": 1.5 - }, - "G5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 20.38, - "z": 1.5 - }, - "G6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 20.38, - "z": 1.5 - }, - "G7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 20.38, - "z": 1.5 - }, - "G8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 20.38, - "z": 1.5 - }, - "G9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 20.38, - "z": 1.5 - }, - "H1": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 14.38, - "y": 11.38, - "z": 1.5 - }, - "H10": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 95.38, - "y": 11.38, - "z": 1.5 - }, - "H11": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 104.38, - "y": 11.38, - "z": 1.5 - }, - "H12": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 113.38, - "y": 11.38, - "z": 1.5 - }, - "H2": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 23.38, - "y": 11.38, - "z": 1.5 - }, - "H3": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 32.38, - "y": 11.38, - "z": 1.5 - }, - "H4": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 41.38, - "y": 11.38, - "z": 1.5 - }, - "H5": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 50.38, - "y": 11.38, - "z": 1.5 - }, - "H6": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 59.38, - "y": 11.38, - "z": 1.5 - }, - "H7": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 68.38, - "y": 11.38, - "z": 1.5 - }, - "H8": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 77.38, - "y": 11.38, - "z": 1.5 - }, - "H9": { - "depth": 97.5, - "diameter": 5.58, - "shape": "circular", - "totalLiquidVolume": 50, - "x": 86.38, - "y": 11.38, - "z": 1.5 - } - } - }, - "labwareId": "UUID" - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e293d3a3d34ffc36672d4ad8587006b8", - "notes": [], - "params": { - "loadName": "opentrons_flex_96_tiprack_200ul", - "location": { - "slotName": "B2" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.75, - "yDimension": 85.75, - "zDimension": 99 - }, - "gripForce": 16.0, - "gripHeightFromLabwareBottom": 23.9, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons Flex 96 Tip Rack 200 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_flex_96_tiprack_200ul", - "quirks": [], - "tipLength": 58.35, - "tipOverlap": 10.5 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": { - "opentrons_flex_96_tiprack_adapter": { - "x": 0, - "y": 0, - "z": 121 - } - }, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 74.38, - "z": 1.5 - }, - "A10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 74.38, - "z": 1.5 - }, - "A11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 74.38, - "z": 1.5 - }, - "A12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 74.38, - "z": 1.5 - }, - "A2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 74.38, - "z": 1.5 - }, - "A3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 74.38, - "z": 1.5 - }, - "A4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 74.38, - "z": 1.5 - }, - "A5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 74.38, - "z": 1.5 - }, - "A6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 74.38, - "z": 1.5 - }, - "A7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 74.38, - "z": 1.5 - }, - "A8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 74.38, - "z": 1.5 - }, - "A9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 74.38, - "z": 1.5 - }, - "B1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 65.38, - "z": 1.5 - }, - "B10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 65.38, - "z": 1.5 - }, - "B11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 65.38, - "z": 1.5 - }, - "B12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 65.38, - "z": 1.5 - }, - "B2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 65.38, - "z": 1.5 - }, - "B3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 65.38, - "z": 1.5 - }, - "B4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 65.38, - "z": 1.5 - }, - "B5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 65.38, - "z": 1.5 - }, - "B6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 65.38, - "z": 1.5 - }, - "B7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 65.38, - "z": 1.5 - }, - "B8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 65.38, - "z": 1.5 - }, - "B9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 65.38, - "z": 1.5 - }, - "C1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 56.38, - "z": 1.5 - }, - "C10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 56.38, - "z": 1.5 - }, - "C11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 56.38, - "z": 1.5 - }, - "C12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 56.38, - "z": 1.5 - }, - "C2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 56.38, - "z": 1.5 - }, - "C3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 56.38, - "z": 1.5 - }, - "C4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 56.38, - "z": 1.5 - }, - "C5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 56.38, - "z": 1.5 - }, - "C6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 56.38, - "z": 1.5 - }, - "C7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 56.38, - "z": 1.5 - }, - "C8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 56.38, - "z": 1.5 - }, - "C9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 56.38, - "z": 1.5 - }, - "D1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 47.38, - "z": 1.5 - }, - "D10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 47.38, - "z": 1.5 - }, - "D11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 47.38, - "z": 1.5 - }, - "D12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 47.38, - "z": 1.5 - }, - "D2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 47.38, - "z": 1.5 - }, - "D3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 47.38, - "z": 1.5 - }, - "D4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 47.38, - "z": 1.5 - }, - "D5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 47.38, - "z": 1.5 - }, - "D6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 47.38, - "z": 1.5 - }, - "D7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 47.38, - "z": 1.5 - }, - "D8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 47.38, - "z": 1.5 - }, - "D9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 47.38, - "z": 1.5 - }, - "E1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 38.38, - "z": 1.5 - }, - "E10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 38.38, - "z": 1.5 - }, - "E11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 38.38, - "z": 1.5 - }, - "E12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 38.38, - "z": 1.5 - }, - "E2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 38.38, - "z": 1.5 - }, - "E3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 38.38, - "z": 1.5 - }, - "E4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 38.38, - "z": 1.5 - }, - "E5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 38.38, - "z": 1.5 - }, - "E6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 38.38, - "z": 1.5 - }, - "E7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 38.38, - "z": 1.5 - }, - "E8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 38.38, - "z": 1.5 - }, - "E9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 38.38, - "z": 1.5 - }, - "F1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 29.38, - "z": 1.5 - }, - "F10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 29.38, - "z": 1.5 - }, - "F11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 29.38, - "z": 1.5 - }, - "F12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 29.38, - "z": 1.5 - }, - "F2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 29.38, - "z": 1.5 - }, - "F3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 29.38, - "z": 1.5 - }, - "F4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 29.38, - "z": 1.5 - }, - "F5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 29.38, - "z": 1.5 - }, - "F6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 29.38, - "z": 1.5 - }, - "F7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 29.38, - "z": 1.5 - }, - "F8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 29.38, - "z": 1.5 - }, - "F9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 29.38, - "z": 1.5 - }, - "G1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 20.38, - "z": 1.5 - }, - "G10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 20.38, - "z": 1.5 - }, - "G11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 20.38, - "z": 1.5 - }, - "G12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 20.38, - "z": 1.5 - }, - "G2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 20.38, - "z": 1.5 - }, - "G3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 20.38, - "z": 1.5 - }, - "G4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 20.38, - "z": 1.5 - }, - "G5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 20.38, - "z": 1.5 - }, - "G6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 20.38, - "z": 1.5 - }, - "G7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 20.38, - "z": 1.5 - }, - "G8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 20.38, - "z": 1.5 - }, - "G9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 20.38, - "z": 1.5 - }, - "H1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 11.38, - "z": 1.5 - }, - "H10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 11.38, - "z": 1.5 - }, - "H11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 11.38, - "z": 1.5 - }, - "H12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 11.38, - "z": 1.5 - }, - "H2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 11.38, - "z": 1.5 - }, - "H3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 11.38, - "z": 1.5 - }, - "H4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 11.38, - "z": 1.5 - }, - "H5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 11.38, - "z": 1.5 - }, - "H6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 11.38, - "z": 1.5 - }, - "H7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 11.38, - "z": 1.5 - }, - "H8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 11.38, - "z": 1.5 - }, - "H9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 11.38, - "z": 1.5 - } - } - }, - "labwareId": "UUID" - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c9227d2a0882401c3eb6f1f2f96b8e67", - "notes": [], - "params": { - "loadName": "opentrons_flex_96_tiprack_200ul", - "location": { - "slotName": "B3" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.75, - "yDimension": 85.75, - "zDimension": 99 - }, - "gripForce": 16.0, - "gripHeightFromLabwareBottom": 23.9, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons Flex 96 Tip Rack 200 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_flex_96_tiprack_200ul", - "quirks": [], - "tipLength": 58.35, - "tipOverlap": 10.5 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": { - "opentrons_flex_96_tiprack_adapter": { - "x": 0, - "y": 0, - "z": 121 - } - }, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 74.38, - "z": 1.5 - }, - "A10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 74.38, - "z": 1.5 - }, - "A11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 74.38, - "z": 1.5 - }, - "A12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 74.38, - "z": 1.5 - }, - "A2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 74.38, - "z": 1.5 - }, - "A3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 74.38, - "z": 1.5 - }, - "A4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 74.38, - "z": 1.5 - }, - "A5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 74.38, - "z": 1.5 - }, - "A6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 74.38, - "z": 1.5 - }, - "A7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 74.38, - "z": 1.5 - }, - "A8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 74.38, - "z": 1.5 - }, - "A9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 74.38, - "z": 1.5 - }, - "B1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 65.38, - "z": 1.5 - }, - "B10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 65.38, - "z": 1.5 - }, - "B11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 65.38, - "z": 1.5 - }, - "B12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 65.38, - "z": 1.5 - }, - "B2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 65.38, - "z": 1.5 - }, - "B3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 65.38, - "z": 1.5 - }, - "B4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 65.38, - "z": 1.5 - }, - "B5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 65.38, - "z": 1.5 - }, - "B6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 65.38, - "z": 1.5 - }, - "B7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 65.38, - "z": 1.5 - }, - "B8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 65.38, - "z": 1.5 - }, - "B9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 65.38, - "z": 1.5 - }, - "C1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 56.38, - "z": 1.5 - }, - "C10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 56.38, - "z": 1.5 - }, - "C11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 56.38, - "z": 1.5 - }, - "C12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 56.38, - "z": 1.5 - }, - "C2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 56.38, - "z": 1.5 - }, - "C3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 56.38, - "z": 1.5 - }, - "C4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 56.38, - "z": 1.5 - }, - "C5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 56.38, - "z": 1.5 - }, - "C6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 56.38, - "z": 1.5 - }, - "C7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 56.38, - "z": 1.5 - }, - "C8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 56.38, - "z": 1.5 - }, - "C9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 56.38, - "z": 1.5 - }, - "D1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 47.38, - "z": 1.5 - }, - "D10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 47.38, - "z": 1.5 - }, - "D11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 47.38, - "z": 1.5 - }, - "D12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 47.38, - "z": 1.5 - }, - "D2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 47.38, - "z": 1.5 - }, - "D3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 47.38, - "z": 1.5 - }, - "D4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 47.38, - "z": 1.5 - }, - "D5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 47.38, - "z": 1.5 - }, - "D6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 47.38, - "z": 1.5 - }, - "D7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 47.38, - "z": 1.5 - }, - "D8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 47.38, - "z": 1.5 - }, - "D9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 47.38, - "z": 1.5 - }, - "E1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 38.38, - "z": 1.5 - }, - "E10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 38.38, - "z": 1.5 - }, - "E11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 38.38, - "z": 1.5 - }, - "E12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 38.38, - "z": 1.5 - }, - "E2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 38.38, - "z": 1.5 - }, - "E3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 38.38, - "z": 1.5 - }, - "E4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 38.38, - "z": 1.5 - }, - "E5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 38.38, - "z": 1.5 - }, - "E6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 38.38, - "z": 1.5 - }, - "E7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 38.38, - "z": 1.5 - }, - "E8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 38.38, - "z": 1.5 - }, - "E9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 38.38, - "z": 1.5 - }, - "F1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 29.38, - "z": 1.5 - }, - "F10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 29.38, - "z": 1.5 - }, - "F11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 29.38, - "z": 1.5 - }, - "F12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 29.38, - "z": 1.5 - }, - "F2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 29.38, - "z": 1.5 - }, - "F3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 29.38, - "z": 1.5 - }, - "F4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 29.38, - "z": 1.5 - }, - "F5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 29.38, - "z": 1.5 - }, - "F6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 29.38, - "z": 1.5 - }, - "F7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 29.38, - "z": 1.5 - }, - "F8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 29.38, - "z": 1.5 - }, - "F9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 29.38, - "z": 1.5 - }, - "G1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 20.38, - "z": 1.5 - }, - "G10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 20.38, - "z": 1.5 - }, - "G11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 20.38, - "z": 1.5 - }, - "G12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 20.38, - "z": 1.5 - }, - "G2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 20.38, - "z": 1.5 - }, - "G3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 20.38, - "z": 1.5 - }, - "G4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 20.38, - "z": 1.5 - }, - "G5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 20.38, - "z": 1.5 - }, - "G6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 20.38, - "z": 1.5 - }, - "G7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 20.38, - "z": 1.5 - }, - "G8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 20.38, - "z": 1.5 - }, - "G9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 20.38, - "z": 1.5 - }, - "H1": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 11.38, - "z": 1.5 - }, - "H10": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 11.38, - "z": 1.5 - }, - "H11": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 11.38, - "z": 1.5 - }, - "H12": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 11.38, - "z": 1.5 - }, - "H2": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 11.38, - "z": 1.5 - }, - "H3": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 11.38, - "z": 1.5 - }, - "H4": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 11.38, - "z": 1.5 - }, - "H5": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 11.38, - "z": 1.5 - }, - "H6": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 11.38, - "z": 1.5 - }, - "H7": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 11.38, - "z": 1.5 - }, - "H8": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 11.38, - "z": 1.5 - }, - "H9": { - "depth": 97.5, - "diameter": 5.59, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 11.38, - "z": 1.5 - } - } - }, - "labwareId": "UUID" - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadPipette", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "58bf66c06d4c9ef0133ceda2d3fcd0db", - "notes": [], - "params": { - "liquidPresenceDetection": false, - "mount": "left", - "pipetteName": "p50_multi_flex", - "tipOverlapNotAfterVersion": "v0" - }, - "result": { - "pipetteId": "UUID" - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadPipette", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f41b352a27113bc3a9f0595d3f285410", - "notes": [], - "params": { - "liquidPresenceDetection": false, - "mount": "right", - "pipetteName": "p1000_multi_flex", - "tipOverlapNotAfterVersion": "v0" - }, - "result": { - "pipetteId": "UUID" - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8f61100f29f0e3dae391082bcf9c4b33", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "aaa5a61f4a6a6c60e1d02ab560e8ed30", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2e9b37a4b76c8be219754992b50eac87", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ddd20b2c38d4938cfbebedc9e32a0f3a", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5c8c68d760474150e360b8ccb0614254", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f8b997229880175082181fc529ea3906", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9818ef02347426a4ef817c25ccd44b3c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d97431083e1366ed0a2b09b7195fae03", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "779b7b1760eb1092027a3b5813510a32", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5eb0bca7d2181db9880c8105f08fa8fd", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "008e8176fde7fd9caffd459f967acca1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b66801b6f296760e22f9e210a386b1b1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c8a1b0a4298bcec2592014f2bf37d576", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b693187f2934371da9b6eba9d20a3002", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e46b2068448ff0983a798cbef1a3cec0", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9f4f599a30f83a5420e5fb732ca2efc0", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4472cf6cf1f8e71cdd0be1633127c932", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "15d9492cab2583479a4f816ef17a46a1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7f4a24bd41db2e2f75e276418679944c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5e389eada4ee80880ce64d17356c0c81", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7ce70a99c5d3071241add86ec7a937a6", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2bb7f73d43103f0343484b7194519e4c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ef9fda0ac1ab209fe854ae7e7d7f4aa5", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "47674b8e252ba5e9349dd8dbc2e66a40", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "dcc8d9df462cd0c9a1b47ccd02f3eb2d", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2d70199bbce02415accfd10aa3c03c42", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "aa816105a34323703c3bb8cb06146be1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7e0516811ce65b3a61ec6786ea0219d9", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a8fd1948ecc0acbaae6cb41bb8e730de", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c6c5a01e13cc765533e432494ff7f07f", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a9c8d1c1d71ae30d2d011a21e5ffdb3e", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4bdb9bf5d751f40bb798826e2e676870", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5a73e1d4498d560d2951a9b0851d173c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4bedaaa098e7bccd2f2bfdfdd6ec0a2e", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "672d7bbe39d4d9fc5544a9075bfd1f79", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7efec2350ce946b98fbedca57bb2d546", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "96567efe8321030016f11223d404621f", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4b85144700c274e59a52004fe6667c25", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "60537125b393dbadfe94648248132f7c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "990dd741f3dcccafb23cc986b4088ad9", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d8ff455d6832a88e094daf9c9aa2eaa8", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "80fa3121956cee042c5d6dc137e3ca71", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "75bd4c7ef1588a67ea415705b2c8349c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3874e2785cec5c6baf3dff0d664d90ef", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bfdae27d79cc5953ddadab4a39c10466", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e231e7cc6a278ce42d86d6129b01453b", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9aebd50719d690f81b6385ed1533157e", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bfa8b077772ea67face5b5da8ce31feb", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9a3b06420819d013bdd36b9b2b4d2358", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5f5aa88961947babf39b10e37ee23421", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1d856d812464812151e1d5a8dd667237", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ebed53310e7b29d035f6f7a016fff0f8", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2fd7d9f9978f8381228cccb93245fc2d", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d7c19c35227a0340e67f2e0ed968d7d3", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9ac59c380e99317f35830b98fb80871d", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a443653eceb8acf82a3ff5594ec68825", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8c6d4cad0acca6032cee9ed68f3b7b77", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1947ab90ab78e871a5093646a8ad92d0", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0c22e06378cc0cd2d4064974f2fa408b", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4193cbdc63a59a75bcafbf4d97663b9d", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d1103b5929b1b7a0185f58a74468440d", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1b3f07e9f1477115b69ce6331c90d9f1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "303f4d143d7b69932fe4fd18127c81db", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "65f3615cb8230a6ddb6cf35b73c3c5aa", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d5e7c9ba1db7bf2b087d00ca46c472e9", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e01aa7bc7c31a8dffd23546b1945e675", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9247c62d2ead992011f223392961b7b2", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d293202097173e711d291e7259c65611", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "45bcdd313fe6186beac0fabca6a7dbdb", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b550a26ebfeb445caf3784c322b41089", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d1fe7ad1290317d754709b52721cf783", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2830f4f34d964ab48b8957fa864e0316", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "818860ae04707d24dc36e96743884690", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "43aa0a49ca4c34112a19b99640e21beb", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8c658cd713c0ac4f52bc9855b872130a", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "185a3fd2dbd29301fc7e92cb25f0e218", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8633954f726d96cb33537b14a848b4bc", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "620b4f47c73faf6e0265f8741d23dc8b", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2dcce3b03d36d221c7ce487bae928383", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "135d11296e5067afac8847f22d806e79", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d53f49d3f67df5cc18fb4547217e4da9", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "78298f5f0fa0e9043ab4df0549173ba2", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "84571d458086763fbd2d5e30f26a6d1b", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6fec441fec6751579035f49cb02fb651", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9774136549a3a20f61860acb85b83438", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cf2009489d7bcc50208d3cfec70bd176", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f8d7eeec9aabdf5a9e3e7e5f91046003", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5c26c2c63789e7307ea62537c48c1e42", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "466fa95ac331fbb920ab792a52078999", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "427f6c1570b503fcc1e04f26c2369aaf", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "44d529133defc8ddfe4995ce63c3f914", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "437671cc25e87718115772ec6ec66d57", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9fdddc1ec95caa85c91bab332d0af3e4", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f2d35b138c96e986cc8ca9d71bb9f6e8", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "56c24389b4ad55beb7ed6159c4ad00d3", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "120ece00f990ff4566b38892075fc007", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0bf90a90466930017162fadbea9477a6", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7d0d618d19cfbf3b537bed12e0f06f4d", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ffe0929eea2d196d78f265dd2e9926d3", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c8f5cc16090f48b1c5a31908c12e93a5", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4091b25131a60700b2e23a474cefb4f1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e908f3817c89489f66d8e675e0f10e14", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "afd0eadc7fd05676719741b36917d87c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6dfb35b2956e28a771a594758e46a714", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H1": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7ca6001ebb059fefc71631552f8af3d3", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3287ad9cac60f592ab3536068b0f40ec", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "aff52c45c3c1e93af130a41c8c80d19c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b263b9522566c1802676980e23209041", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c8516f441443ee0604fd1a2df54ad7e0", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0e0454a517248a99751a99fe1c08a2f6", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7ea7d18690ec3e20e8ed3535c1defbb9", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "511c7bf60e9439e100ce45ac967da49e", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H2": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "81a78fd07484e98039dafa397331454b", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cd8e8d0d5c7aaa5af541da01bb63f584", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b0e15451bf7b1644960e32675173dacf", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d10f1489d9c872506ebb31cd4b808540", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "43af4a7235622d22806f1be8ffd9519c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ebb3c328819a42ccc866bf0dbdfbae33", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2753b91f935a5083f07680673d6a9adc", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "33803f50aaecf245ec0655dc31be2eb8", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H3": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d982765564753512defadd4ee28cec77", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "511b2c79928728669da32ce6154bd1bc", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9a5cddb2e8602ec8fec98f7bf28918e5", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0328846c95fa6210972c3d45f8b54a74", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5ad886b1e0fdb9708d9c20c267e62220", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "927818362c3ea3c14823ccce4965f727", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1e50241cdb9fcd2bff1534b98ea618b1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8811f7a3c5a117e7f63f04b83de01698", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H4": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5760b7a67c17d86093f73c375bf61015", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f67583d0274c6ef9c3d762329f725f93", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b2ecfd404c288732c092ce69b7da8815", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2d899a259c3a91c64efdf675ed9a2d33", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fcf6ee9795c0a86091de90e908b372f4", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "73d5e752210cfb0d867e78215b598501", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9d289d19747f833f0aa03fbd1ec6a989", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8c5457ceac8bee1ce222d9547cd4d715", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H5": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4496f5d5a2f033bcfc803c3e6d47e8f7", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ca357881aa182f6f45bac132037803c2", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "26a1dc7b1ba51f89274dc8c24c519b5a", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "28533630621c4cb17a03486a46b030a5", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ad02948bafeaaa7d6fb5c0fd66d8c227", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2121bb825bc14b0ab45f167418dc4ad4", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2adb52e7ccd59d289b2a0d35cd314db9", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "40fae1aecd14139e9abcd6c26fa2c28d", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H6": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "38ea01a01df003b05f3e1cc4b045a10f", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A7": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "63beaa12dba5ecc8fad39b64c3852db1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B7": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c875efceaba3272710bc90e5a92c42f3", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C7": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7ca6e36ce75ba4acfcdb44922b69d484", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D7": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "124f2a131f81abeac9cbd0e9fcfcacb1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E7": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "da169522a77ef45b236cb685cc140252", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F7": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "386b7617e29115c4e2b6d4cb87185279", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G7": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e1d20d4c3166b98e92ab93717266d249", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H7": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "eb5db2ecd8e328db99b64db59e32ae09", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A8": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "92f6dc249826e5924338c0e1f80f5b65", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B8": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2b462a5f63f15b04d69c56da3ee88de3", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C8": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3b042a699af6be5f267567394035fe3b", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D8": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a45ffe349ff38d95744c4ef86fa0354f", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E8": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "26bd2430c3c4cc2408ad9a365f2c2891", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F8": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "df281882873d0e1445c2246c90c8a3c8", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G8": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b1ddf115c9e3f3fb1c3ef80e116749ac", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H8": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8e21511c6ffaf00d1bc58e527b893f9f", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A9": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7a8e561af25913e7702fe452cbf82920", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B9": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c5305a0cb530b54ebc46b676eb95f556", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C9": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5accdd553bd1bee18252a9ce7eea55b4", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D9": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0f61f84cea74148cf50b6f65cdf9d961", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E9": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e90e375e3c3ad3df214ffafe47b98111", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F9": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "14a072b4d5ef396d36986342c1c9bae8", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G9": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "06bfa9e5693709b0a2ac5d79a176296a", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H9": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "af95a8489936f9fef2c4925547f3ab1a", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A10": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d2664a413fb9dba6010006408dd2fa5c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B10": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "506ab0fee68596d670f6e284b19f4751", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C10": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "962a559444ed526d9dffa906045e8325", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D10": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c8cd0e9d4856a4d392b6ccab9a42d124", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E10": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f80d8d52b380ca2a2961237de98f7230", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F10": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3303870d02520796d5cab53d697ccbe1", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G10": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "203dc9ea7ded51bd40035af6e158d593", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H10": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b4f0749950b9c0a0fad2015aaac48a0c", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A11": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6f01f1aaa7ee5cc8a4c62144af4d0042", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B11": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "905c8fed115a922f2d89e2c02c27616d", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C11": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "875a960a9980be4f9dd1ba8745bc24cd", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D11": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6aeac56ee731a57aa81f33e3ff861d64", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E11": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2f4754434c34c2c99e5b1465af5c188e", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F11": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e8854207245788771690d1521b43c12f", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G11": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "811183ffe7c1a3ce615213e4e70d75e5", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H11": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2abee4fc1c9c31bd629912d9c8401687", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "A12": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7835e1234f735842daa4f61c575ce72f", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "B12": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "14ff231157b24c887d1ec0813b3c55f2", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "C12": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "858cd1cc7c5c762193c7e4fd67ebb8a9", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "D12": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a2cd720991fdbb2e317b7bada0952dc5", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "E12": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1fd4c6b672e6afe1a21e43ad7f412eb2", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "F12": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9ab95910878dd01da02ef13f3d4b1839", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "G12": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8f57d1b217457bcf0a4f4f17a828f1ab", - "notes": [], - "params": { - "labwareId": "UUID", - "liquidId": "UUID", - "volumeByWell": { - "H12": 200.0 - } - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "temperatureModule/setTargetTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d20affad4dcd31700fe9360291f7993d", - "notes": [], - "params": { - "celsius": 4.0, - "moduleId": "UUID" - }, - "result": { - "targetTemperature": 4.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "temperatureModule/waitForTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1cf4e0014a9e172647fc6f4fc603bb61", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetLidTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b6f197a28bfdd6061e504f34a2e2834f", - "notes": [], - "params": { - "celsius": 100.0, - "moduleId": "UUID" - }, - "result": { - "targetLidTemperature": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForLidTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c34383e8fe124015ee44b5838747baae", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "09d94a47b65ddbabfcf509b876834d52", - "notes": [], - "params": { - "message": "\n\n----------ADDING DB1----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "462ab3a580018a704b2f310fffed7dce", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "configureForVolume", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ab75b4de24840f7e2a2af5f5a66769d3", - "notes": [], - "params": { - "pipetteId": "UUID", - "tipOverlapNotAfterVersion": "v0", - "volume": 4.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "02e0185ec5df7ddbb734f5dc8bc35b02", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 4.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.3, - "y": 74.15, - "z": 13.0 - }, - "volume": 4.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "925dc71d217999516f0cb47e48fc7102", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 4.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 4.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bcf7ddbf19d9e5d8da7a913a3776a392", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1802acc6c262e1a9417bd185903c0d2b", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "80f028f4fd8345d9763b55de0afe11b5", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9fbb21cf3a09b3c3af84e8a5b16fd652", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "82da1bd1888beed5c0a18c149b949bde", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "08edda9fab95b7cff943521fcaf0f11b", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c4c1742d26de73b050a5b75444da155c", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "dfd81fde99a69c94a1a712d165467b14", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "da6f938d70af05383d7ca8dd87d0b3a8", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "412ed9d67777f23478129af556b697b7", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "952980a8bab99528215ea511050c1e3a", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2020916ffbf2b5ea23427b3e0becd1d0", - "notes": [], - "params": { - "seconds": 1.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "367507eeb74543f7aaf46d7edda50dd1", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "touchTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5a8cd45b5ca7727e55cb46681326b39e", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "radius": 1.0, - "speed": 60.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -1.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 15.260000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5f25a3b0bd5eb88b36b555b4bb9ca0d5", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 412.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/closeLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8c668c6ac45ac4c3c712ac78fe8974c4", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/runProfile", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "19578f9b13c86b6cff60ae975d2d35c9", - "notes": [], - "params": { - "blockMaxVolumeUl": 15.0, - "moduleId": "UUID", - "profile": [ - { - "celsius": 95.0, - "holdSeconds": 120.0 - } - ] - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "60f6af8e29ff815ea688504e3da56a0f", - "notes": [], - "params": { - "celsius": 95.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 95.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7f3dfa13f21157d4c962c9e8764dd2c0", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cf30e2a36a38713ab8f8b79bc22024d9", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2791a45241c4974df9a0da7f6e512271", - "notes": [], - "params": { - "celsius": 94.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 94.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "709dce4723e76f0601f01d77402c1e0c", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d408d344171dddc8537fd97153ae3d18", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3b9280d9bde865fb1f120ea09947ba66", - "notes": [], - "params": { - "celsius": 93.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 93.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4fdb2a6857f213443c61970e8715e8f3", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c2afc2d7ef6f7750be6f39f23fa230cd", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "af324abb8812f6243ce4f60b561269bc", - "notes": [], - "params": { - "celsius": 92.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 92.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4750d94adf39183b246d31ae65c4bf52", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2acf9066db8f856e48d442c2fd21ceef", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f31a756630eff63d94ada46abc00afb5", - "notes": [], - "params": { - "celsius": 91.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 91.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bc0220bac8ea6f4f6e7365dc26e096d6", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "70dd2e8f92a0eb7c71a4327f9cf14331", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a643f56b9157be084f5a664b564ce763", - "notes": [], - "params": { - "celsius": 90.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 90.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "55729ac300dbb44fb5562e4a4fe52fa9", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6fb71ad687b24fafd5c7375912be7aff", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9a613c7df1dcf551715f4770504606d6", - "notes": [], - "params": { - "celsius": 89.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 89.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "956fba3d0d41f707f022af95e8ea5b10", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "87032579d8ef9f40e333340126277ddc", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "48ec80ea228a99b4b087753fa2cf9cd2", - "notes": [], - "params": { - "celsius": 88.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 88.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a3d85e4e2bc7a287cf4b1fd04f3ad0e4", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d919231fdfc16990e8288543729e68df", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d5fce482cce5eb32f39e2e6e3612193b", - "notes": [], - "params": { - "celsius": 87.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 87.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f065fc7369167d7e8e2052b1d843d1c2", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bacadfeea17404f3e979abd903a22f7a", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2219cc1e8741ba80306cc6959eb4ef80", - "notes": [], - "params": { - "celsius": 86.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 86.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e7ec1b11ffd4865a59326a2557d7f0bb", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2013780df01a388f678df3e0e1ae266b", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7209d0484d7bfa189d1732a7bbbc3a59", - "notes": [], - "params": { - "celsius": 85.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 85.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "20d2514acdab3e3448618809c358ae7a", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ae4feb9d69016017a5b909c5643ce34a", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "885f0a614feac857c796bd6c25671d77", - "notes": [], - "params": { - "celsius": 84.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 84.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8ca2e0d8f75dad16c1d6fdc572333619", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "47b118048e54aef9c5cdf7b6b5c2d74b", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "18dbb0a1a3cc2a907f7b387d6697bf90", - "notes": [], - "params": { - "celsius": 83.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 83.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "766d87e7fe8f4eaa1cff13ab7b37b364", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "08e08d2948fdf31653040e6221e6b24c", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "91cca07b39ae72da34b8a6dbe7a4483c", - "notes": [], - "params": { - "celsius": 82.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 82.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7d662560e11e84d650900d67098731b9", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9bbdfb63c0ce8de6eb75f26e9d39f9e3", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "629fa6ae8b71abab25bbe66f9f393308", - "notes": [], - "params": { - "celsius": 81.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 81.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "99322871b0b7c6f13091d0df69b5f937", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0e3572550a02b0c1337971ff7798330e", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "732b29e7066c4f0600aab01d2d99c1f0", - "notes": [], - "params": { - "celsius": 80.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 80.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c60e07b6aed1e9c1642a0cd211384b96", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "35df839e4614f877bedec488e21f1d20", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5f98a478c5a31272f942cf085b9193e0", - "notes": [], - "params": { - "celsius": 79.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 79.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d9b3ede674c7069718215c83ce60dd28", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5287c6592db2bec6f737849c5e0dec53", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5abef8b61964fccdf8486fbd9ee83f1f", - "notes": [], - "params": { - "celsius": 78.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 78.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4e3c62782ec783f1c57dbd98a8796429", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b5da778f8177c0f33003547e07ac1590", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2172d3afb18d1ae61e017c32495eee0e", - "notes": [], - "params": { - "celsius": 77.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 77.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "06484f7d18a9b6445458cd2ad2f6f507", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "011eb9735c3f22751b5286eda84e986a", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c97542e9721ff61656d06228cdab2ddf", - "notes": [], - "params": { - "celsius": 76.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 76.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2907edf068ca4a350457ad05b9fcea66", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "38cde5b0b2b6be57808d0505452776f9", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7e260670d38ee78f3bf77dbca2222256", - "notes": [], - "params": { - "celsius": 75.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 75.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d3440f65cbee4d12fd1c819b29a5a944", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "62453517166a7f2c67b88512af37d922", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "071775894f0f17b1cd0da7f9bec77426", - "notes": [], - "params": { - "celsius": 74.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 74.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "84f1fed8949a865c2f8637b308b4d9e1", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "12b9cafebf04032b6172e122bb9fe0f3", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7f876f981c311529287bda518287cda8", - "notes": [], - "params": { - "celsius": 73.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 73.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8b7f9d4867e506d964a5d5d0e4308da7", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7e94578f552f97db94b4c8b010ff31e5", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5fdae4f3bb9d2f5a48957eb26f720a2e", - "notes": [], - "params": { - "celsius": 72.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 72.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f45c9fcb71e0f54d5b93d33ae8ead783", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3f31cb260adc9c9560280a4bfb01c414", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f7b42a96363bb86230ca6f85799f5a39", - "notes": [], - "params": { - "celsius": 71.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 71.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b8bc1d21e31bf72fa658f9bee0506704", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cfda1c125e8fc2b993bc6577e7c79302", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "51a35c65b72f8facc402983cee134cf1", - "notes": [], - "params": { - "celsius": 70.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2ba43999b435e4e381c66ad10f0b6849", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1fe5265fa866a637822ecac83c532662", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7f18d9073f427de54acb37b4e35434e9", - "notes": [], - "params": { - "celsius": 69.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 69.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "831ee6cfe31051b44a94fb3d2c6d441a", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2c56d24c082ef09de8874b653f2d6c31", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0b7f04a03a08371286139a202f2712a3", - "notes": [], - "params": { - "celsius": 68.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 68.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "161c4347857dd8598ce3dded3acdfa3c", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "af099f13af8744d459dd30809edebab8", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "31c5cd8831b441e14b342dc0318ffe9f", - "notes": [], - "params": { - "celsius": 67.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 67.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1a064b599037ddf4e4e7ea30c28b0aa1", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5de020e8575d5face143bcce12a9db58", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ae11b2fcf8ff20cc4c8b27805bc3764a", - "notes": [], - "params": { - "celsius": 66.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 66.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cebd72effd7bf193c520cac7e5925291", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "32fc1942a3c2eac289ababaf76b4d9a5", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9619f00c47abba041ad3f9746b80836d", - "notes": [], - "params": { - "celsius": 65.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 65.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "175f79a2dbc8fd5bd61e87d988a74239", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e05d8703343f5f263d7ea70dc1967221", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3ba5b9a01f55e59c95711d78c47a9f36", - "notes": [], - "params": { - "celsius": 64.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 64.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d5594dd1033606855033ef1ad41542f6", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "089a2feab8db04a58ef33c9066918f17", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "75d9121a8719b566ba0f0e5d9ffcdc74", - "notes": [], - "params": { - "celsius": 63.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 63.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d73623f356eb89cfe19ecd18d90cd985", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d636b95a32388ae938c8a332243fb5da", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1dcf255b9b80e01fdbdaeb37d32564de", - "notes": [], - "params": { - "celsius": 62.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 62.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5deb8c94c4f1b96cfc805108b40eedca", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e5feb25ff7197995390beb67cca092b0", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "548caab309c6e891029022781b4f7c72", - "notes": [], - "params": { - "celsius": 61.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 61.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b051a6dd705c10c0b5171576fb461135", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7df7995ccb04711873f7c88ce4f3b22d", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "626a331d3e0a18c6b40f4a2a9470eece", - "notes": [], - "params": { - "celsius": 60.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 60.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0a15ba28b7f16a96829f07c52f3ccd5e", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "03a6b5ea04e006f00320dbb47e31dc3e", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c660e95ac85702c6c7d5e5ac8ebf8094", - "notes": [], - "params": { - "celsius": 59.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 59.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "50ccd309e74a683fa9423c800e81a336", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5cb07049db96dd11130ded42d143ce50", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "206876e176f7bab12078fe5f8ba5bf99", - "notes": [], - "params": { - "celsius": 58.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 58.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "84e968aaca6cc5104f379b6e107d1f70", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "31fde73939cca3e88201d07cdabca09b", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "365d1e4f535103137b1a83ae21285135", - "notes": [], - "params": { - "celsius": 57.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 57.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0d45a7384b5bcc64aec5fea945fbcc05", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "33372e812c8e8be65ad1f5704aa7af28", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a82d40b62d22d6db9826410daf9cfdf0", - "notes": [], - "params": { - "celsius": 56.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 56.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a7257d111ac2c8a1aaec1f29e3c067cb", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cea7b98870afd782e0bc58ef2b906000", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b1029a72e746a925225221dd43d60a6b", - "notes": [], - "params": { - "celsius": 55.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 55.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "449c44fb4436c9d1ad65957a33c7b9de", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0b796c9b826b201f121c71d768c71b05", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c385ccb14390aba280ebcffd846da996", - "notes": [], - "params": { - "celsius": 54.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 54.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "260cd32bf3faa4a107a5d67b82ea947a", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "84b6c721649b947be32a2ecb31238de2", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "450ef1c606121c85f8fd0b546bff883f", - "notes": [], - "params": { - "celsius": 53.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 53.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "76eac448d9f0b9052c76d612b4e0f58f", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8a9f3dac77b1e0c2cb093b0ca8ce64bc", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "228773bdb653246dc79389d67ccddea7", - "notes": [], - "params": { - "celsius": 52.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 52.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8ffa3f17d4d4cf4931bb465b2ab1a655", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "30692ac27903508d3e3433863079b731", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "dc1cdca16de05f0011ff5351962af844", - "notes": [], - "params": { - "celsius": 51.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 51.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f78d14c896c5238880944e3d2745bb61", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "424273bdfd37282cd7225b949612ea5c", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "730e8c948918c889e9f66b4dc3cff123", - "notes": [], - "params": { - "celsius": 50.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e6b7ecbc818b48c811b7dd10382006ec", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4414bdaf007dc3ddc5d4235a713d50e8", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "27e30028dbd12744f9b6e78f8a7df7a3", - "notes": [], - "params": { - "celsius": 49.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 49.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "71139901ce04945ce2b73ba849e88520", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8431c3dea998a92b69fb1f3cc2767753", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5bec11762ff91cdded71fa33ea46b65a", - "notes": [], - "params": { - "celsius": 48.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 48.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a17cd184838f78893d476e0186ba4029", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2b082656959e967bc5c58cf0243ce1d9", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4b2941da4add362fb9eb8eb17c942d25", - "notes": [], - "params": { - "celsius": 47.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 47.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "338175f6bcbb9df6b2afbca596d62f8d", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "770b726c2a1101d3f84ff9be0f86a273", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c9d6d2a0cecd8f1fafd7de19920e634b", - "notes": [], - "params": { - "celsius": 46.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 46.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "25224b56b31f21d331bc7fea57f06eff", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "61fca62767e1fbc35a19e50fe5215f56", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e25db724d46f78376141eff3174266ac", - "notes": [], - "params": { - "celsius": 45.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 45.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cdc239bf1cceae10be83ba50b4eb32e8", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9f340b97951e0170b7c9b12addd11353", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a194b47da99405c0b99b81cb8ac1a90f", - "notes": [], - "params": { - "celsius": 44.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 44.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "aabdde51705e8fa92e5b2483c082510a", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0d8b069bfa036f96833adb4b4fd4e41d", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ca8d6a3d407c7bbc74530c5ac1a7b8a1", - "notes": [], - "params": { - "celsius": 43.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 43.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2e4d0e45c3eab9e8aeda4508ce715edc", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3e6f2d8e3a169b73e8fee74dbd3544f1", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "41a6dd957b991a602b58dd0565687a8f", - "notes": [], - "params": { - "celsius": 42.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 42.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5dbb3aa2977749901bf83f56a47269af", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "27e410b0b7b9d49face7717b6868f7dd", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4e04eba549e4a0fd1eac894e9aa2481d", - "notes": [], - "params": { - "celsius": 41.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 41.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f29e5c61e2a5a78a573d1d7034522573", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6b07572218f8fecff3825fac91e1eaf5", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c595de43769e39fe0e8c379642befc46", - "notes": [], - "params": { - "celsius": 40.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2a530d0e062a7a71d6a219738d801fb2", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ca807ab76984b49bdd7a4aefafcfb6b3", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9f13904fee725ea59eda60ccbb02c6ca", - "notes": [], - "params": { - "celsius": 39.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 39.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6b8b49d9c6502d5a84727f58e2d030ca", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e94bdb33e2e01e20bf87d4715804876d", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e47f9391e6ee5ac78a7c679316246b71", - "notes": [], - "params": { - "celsius": 38.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 38.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "dcb4796feeb12b68fa485a69b2016da7", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7de14b27f54084e4c5eb36098b04c04c", - "notes": [], - "params": { - "seconds": 10.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/openLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6a5013ed2f97714d3cbfd897c559e6fd", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "88f890408b39bf040605a23d06f7c983", - "notes": [], - "params": { - "message": "\n\n----------ADDING RDB----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "00677224c457c69ca08840b54601fa0f", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A2" - }, - "result": { - "position": { - "x": 23.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "configureForVolume", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "830e6f207fd56e9294fba38734d9df00", - "notes": [], - "params": { - "pipetteId": "UUID", - "tipOverlapNotAfterVersion": "v0", - "volume": 5.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "32df21b33f21b23b7250e4b145e9e4cd", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 5.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A2" - }, - "result": { - "position": { - "x": 351.3, - "y": 74.15, - "z": 13.0 - }, - "volume": 5.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ed91e0a804eeaf60876f2bacf6365ee4", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 5.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 5.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ede7c09ba888bf4583780b011f910519", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "69b2b49701561ded20dd7708b73f05cd", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7361d69000d89863baebe5a648b5c0ef", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "796026df1d808f79dd281efb7d87305e", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0c69dbf3f575d6810b555c6da10136ee", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d720aded9efb2b95abddc2cbfa5a0a22", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cc4c04a66bdb066b5722e47ddf845100", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "79ff88e8014131935040cab6ea3382c1", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e011fef8002fb189f1a676f45099df69", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b4778b46da0d23b3b96ffafec1a0d265", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "75e0f72bae3c26d8516056fb2dfa748c", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "aa7d6109f7ee2df4f13fa882503b6002", - "notes": [], - "params": { - "seconds": 1.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b8ab7b6b86fb6e8e07de27a93ee82eba", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "touchTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8ceffaa91c7327a61028b344b3190f2e", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "radius": 1.0, - "speed": 60.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -1.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 15.260000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c772791d372fbc5e453ceecc022ce28d", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 359.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/closeLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a121310b4027654d03d49fc3f61b0f16", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/runProfile", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c800fc18faaa550aa645015b51f5ed30", - "notes": [], - "params": { - "blockMaxVolumeUl": 20.0, - "moduleId": "UUID", - "profile": [ - { - "celsius": 37.0, - "holdSeconds": 900.0 - } - ] - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6be8a1b8d682bea9507b96d9687e7d50", - "notes": [], - "params": { - "celsius": 4.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 4.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c0842bfe516e54d06bf216f39e1f7feb", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/openLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5337f23583d7160c7bd3fb11be7ccdb7", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "45460103ce1c28279b31a9f9f0797a3f", - "notes": [], - "params": { - "message": "\n\n----------ADDING PRB----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4ec57e303dd4a19dab032dd2a031224a", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A3" - }, - "result": { - "position": { - "x": 32.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d240cb5e4c9aae5f378c25d2787a7dac", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A3" - }, - "result": { - "position": { - "x": 360.3, - "y": 74.15, - "z": 13.0 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8614b0539beeec0494fa8391960ddff7", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "afd5d367ed06b78b729d43f653b0d67d", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4248f46e4810d2b632eaa0b0faf9d7dc", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8c430d6585cd69d8322b9e28f7be02e1", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "58fd795fb77022bad31f9f85a2259829", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "14d00b88ebfa904eb28fdea883f7f20a", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "abccec97db2fa96f086ce79c3dcd9526", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ec8628678ddab77e94bd0db329c855d2", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1dbeb989c1418c1f1b41591f9256bd2c", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "61d6aef48803860526736dd654e18168", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b9383b900841cb7e1e8004ca09e8d98a", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 20.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "feb3786ebd0c0d587e1ef83536b20d70", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ab8317f307f5b5ae3c5dc1c2d51ad4ef", - "notes": [], - "params": { - "seconds": 1.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "812a72ab8e68ec0870c5af969fd673f2", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "touchTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6e3bad6ca7601812c99f71e758fbb4ee", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "radius": 1.0, - "speed": 60.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -1.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 15.260000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fc683ca797abaf2da486ca70b798d012", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 412.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/closeLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4c4e5bae16743ea62b1205bacff45893", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/runProfile", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c720a403f4196e3ba8db997f36bc8996", - "notes": [], - "params": { - "blockMaxVolumeUl": 30.0, - "moduleId": "UUID", - "profile": [ - { - "celsius": 37.0, - "holdSeconds": 900.0 - }, - { - "celsius": 70.0, - "holdSeconds": 900.0 - } - ] - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "85771372837a21e64e5272f105af8da8", - "notes": [], - "params": { - "celsius": 4.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 4.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f147f7cc9ad093b5a4ac9c7cdd80a9b1", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/openLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "eec3952968005fd92c62ad251d9765fb", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "853bada9386caea7f474f43b5b9942cc", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "slotName": "D2" - }, - "strategy": "usingGripper" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1c77c5644cb42239be59cf33ba420dcd", - "notes": [], - "params": { - "celsius": 21.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 21.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b23a4cdccd3f19e07bd7ecc8c9ec139c", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "dd6de2abb6148dc2577700d5e24ff06b", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "moduleId": "UUID" - }, - "strategy": "manualMoveWithPause" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0e8ab8e504563c90b6e712c2efd40eb7", - "notes": [], - "params": { - "message": "\n\n----------ADDING BEADS----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "368d2987166a287f15376baca3fdeb39", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 288.38, - "z": 99.0 - }, - "tipDiameter": 5.59, - "tipLength": 48.25, - "tipVolume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bfdbfbfe2e68f390eab027219030bd81", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "815b95c25828650f547a6b9af13ef9cc", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e3f66cb38bcd61ee1aba73adcaa202d2", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8c558f5aa78272ec1b161696b0ad56c4", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "269d5c8565bb1c5c434a42418f67b0d7", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cbd61ce6087bf9281211ab915e439ec2", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3c66ebd9863837e70126759d45c3acab", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "032af20af9ee8a5158ec1e187cb7f6ba", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a86d2a7c488f7fee4d773c789f355911", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bcbcf4bb60b057f39b3c55634a9e6d3a", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "32b0ab44a5c49dad8b216d4b5ce0fced", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "28123d12168fdc0f3bf245f6f10d0793", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "40715bf4fccfbbe911420e7d9abeb6c5", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5f79a39dadeba2f3514ffacbd60bba56", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7f68bbee78afe7f6b884e47efa2e1072", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "13ffd96786d1ceee4edc58d93d8f2b4d", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0818d997908d21ce9cee773882c3f58f", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d15279d8a3bf0d1a076f44c3e83a4fdc", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "032aa89e17bbfd09dcacf52a15ce18e0", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "30fa39e04a180e805ccf3bde812e4416", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bb468de0a0819c83de68c459d2bc2a3b", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "65fabe75fbb76b8ae64fbe095dbd2b3f", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "573b710f381645ce3be8001d3c236981", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "25d1f00e790d48a9dce31f3e088618e6", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7c1bbb04bafc14155df034c2f15da553", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "529af4dfcaa0c5d1f571bc1be9fb3d1c", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ed452939255d89a625ff82f96c65c52c", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9c9a02898278e87d7215b1c9e392490c", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c2bb1ddf7b51c0dbc497654d4f8c4dc1", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "67497cde9ed8faaf874e00dbf11eb43e", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "47b2201b41a49fdf972b02b2c43c3a3a", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7ad69f1477f0f7065240c3bf5b33ac35", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2fe9faf60fd27b27b0f5a1011f0fd554", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d552b62cebac83b58a3410feab357780", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ea5695819d50dee07e2c9218921f7cdb", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cca1372859c26b02f6746653b6ee3fc2", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9da7d58b925ad38b592bd304000b89b0", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0e355f0015602654601b36f3fe733c7c", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9fa0f5b1ce2cc7efc1afaeac0bc92572", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "395ee0029cbb60d9f36f5a4955a252e4", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7f92051293652d7e5b633281dad5de5d", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 60.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 60.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "494376b85c763d47e43c64a86a1af8d0", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 14.3, - "y": 74.15, - "z": 56.95 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7616f9e1448ab2aaf8444a22a0e5c309", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 60.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 60.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2a75bed14de91780767a2dba2fc63659", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a33188eb7c4689cbbbc5120fbcfc7c30", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4c04d4a332881f459e5b3b64f7dd35f6", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ef7294819777242eba8889672edb5e0a", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7f903dac68a209c04b9f7807783467f3", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "746f439bb4418e6fc7dbf0baa79818f3", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8e7fb9e6e6e9498092442eb6b0de80e5", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "42e1ff8e9bb0d10f536f38547dca4217", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f6ac2c0707b3dd297cfefccf2441b654", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e62d568ad177fb6f7b765a2c1f89bbde", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3c1a1246725e07da8cbf379c35ba374f", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "17c1e8a18b96c71d15bf365a791c3a7d", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "078072d91042c3399cc75c18749eb9a5", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4ea555ffe7f4ea8ec3c16c6d88be7c03", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "002c53f35b6556a3302128bd94c7951f", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0c735b1d5cc19e89268c81062ebf8e30", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "deeaf527616058731ddf81b63a7b4261", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1b082b45d6e92bdb566b26933a376376", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "490719174a027ee2f8ed33c33c375e69", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "800841f6da189a765d8e4c20455930f1", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 70.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 70.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8d2c9a496395a9a1ded71c6b76b65915", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 13.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d4ba58f8ff62e7ae41c88f29d03938bd", - "notes": [], - "params": { - "seconds": 2.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "757be6c16526883c8a48707f09591fad", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 13.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5a1213e3a9c70ead82d418fdd2a1b549", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 359.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7ed0688b2edae638d7f07384107a0117", - "notes": [], - "params": { - "seconds": 300.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5d0b7e3a34dccde14447e701edc94117", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "moduleId": "UUID" - }, - "strategy": "usingGripper" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4d311b4eff2d0b6db3959cb80a612a86", - "notes": [], - "params": { - "seconds": 180.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "244b0c4142617762011b5821edd2e5cb", - "notes": [], - "params": { - "message": "\n\n----------REMOVE SUPER----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "11e24eda4aaea17d19fe594f29cff94c", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A2" - }, - "result": { - "position": { - "x": 187.38, - "y": 288.38, - "z": 99.0 - }, - "tipDiameter": 5.59, - "tipLength": 48.25, - "tipVolume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e03e23625068b2fe01340f043fbcf7e6", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 90.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.949999999999996 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.510000000000005 - }, - "volume": 90.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "66746d07fdd08608be1343cfc9bee132", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.149999999999999 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.31 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a9a2748035ea5336157e177af0fd1625", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 47.459999999999994 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d7c0cecf7abee7221e56bf1562305413", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "02a1ad48dc99e7d22afe884c206ad3c0", - "notes": [], - "params": { - "seconds": 2.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d86a0db1fc9ac4641d8be7762d5a4a59", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "72c6a56b1237e317ea78c68fd44d1ec9", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 509.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f453352b591a769a121caaa4d699e97a", - "notes": [], - "params": { - "message": "\n\n----------TWO WASHES----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f9004be73e3f887db59400d4fec9612e", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A3" - }, - "result": { - "position": { - "x": 196.38, - "y": 288.38, - "z": 99.0 - }, - "tipDiameter": 5.59, - "tipLength": 48.25, - "tipVolume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "73d648448c42c3fe9f59ebee82a03bcf", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A2" - }, - "result": { - "position": { - "x": 23.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8c6870f661fd245f58e78cd630530cd2", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A2" - }, - "result": { - "position": { - "x": 23.3, - "y": 74.15, - "z": 56.95 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "22886609f80251648d4df31266899f92", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 50.459999999999994 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7bd0a6dc80fe6c5b937c1c62786dccb6", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 20.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 70.46 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "40328e27da7174b4bc692d61c929fca5", - "notes": [], - "params": { - "seconds": 30.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "84a9a8cda676dfc363d11e5236a637e8", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.949999999999996 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.510000000000005 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2b9c2e0a5bdbcb142a4c9b7ec03923ce", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.149999999999999 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.31 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8e1d29cdf6a90b3fbe469e54509b5a06", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 47.459999999999994 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1a2647fa45f954247dafedf43a81334a", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 160.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - }, - "volume": 160.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fd65fece18bfe42a335b896faba7164a", - "notes": [], - "params": { - "seconds": 2.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "13b220ee6e41cc137d2aa98490b4e537", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "674eee01810aa366e74e617ed3b99f5a", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 359.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d77fb0a118401dafaec8690ea33837e5", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A4" - }, - "result": { - "position": { - "x": 205.38, - "y": 288.38, - "z": 99.0 - }, - "tipDiameter": 5.59, - "tipLength": 48.25, - "tipVolume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bac23d746d550fbebf80bd28b859e0ff", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A2" - }, - "result": { - "position": { - "x": 23.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "331a6cfd64ef8957a1d5ec1223362fb3", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A2" - }, - "result": { - "position": { - "x": 23.3, - "y": 74.15, - "z": 56.95 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5337ce78a813c809f6bb00618c4fe20a", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 50.459999999999994 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "989ca5a87edf4643238fbc9a3364efc9", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 20.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 70.46 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5364401abcf4dc920adc9ab447efdc73", - "notes": [], - "params": { - "seconds": 30.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1ee8b5cfcf4165f39a0099b7bbeea54d", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.949999999999996 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.510000000000005 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "34e58fe0b2c459fbc3f06920d0769270", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.149999999999999 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.31 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3057863e0b46bc6d14cfddcaa0aacf84", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 47.459999999999994 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "495582e5fad7bd1901c08fb6e7eb50f5", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 160.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - }, - "volume": 160.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ccd5133c5c5d866132fe063c1ae22f9c", - "notes": [], - "params": { - "seconds": 2.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ab97584f3d517de829a20f13ff5791c0", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "21c4f328e8c27e5b8eeae02aa6e69a14", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 509.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bdc01a9029d0a64275e42cdd918ff509", - "notes": [], - "params": { - "seconds": 120.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "20a08a7ac1651a88eeff1c42d5a7fd83", - "notes": [], - "params": { - "message": "\n\n----------ADDING ELUTION BUFFER----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bcd6060410179a5511d523068e7aa8ca", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "slotName": "D2" - }, - "strategy": "usingGripper" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a4af1bda7fb80f69e2384d2636266568", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A4" - }, - "result": { - "position": { - "x": 41.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f5f746debed8dcac8a497a29b31cf186", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A4" - }, - "result": { - "position": { - "x": 41.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 10.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c65c363a455fb00b832481ddec027e5a", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 10.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e2d37a0b98bad9f18001accc5d48f2ec", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c93b23c1e0fc630e0602f22bf92771f4", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "560c787161a5b7b6bc1e4789f309c7eb", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "64468195bc0d12a28b7d33dd318ae9b7", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c1b170c37265b40564968626c228e40a", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5e77139a1eda8ea5a627879417e3412e", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cd2e6a14139282eb596cbe91b211df6f", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "aa01358ba5e110ec8e0ae314196f6ab8", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9658f3926f4e574c676dcb0556367cfe", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1a78c357fe1b8ac9d4cc5b6d3ad8889c", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9b09c58201ed7d85d177642432167b83", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "122379ae04201731c95128ecc84a8c53", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e6e1bdf34d0a30334e1498f9c8cb0162", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f0b7fc1d3b9f5df73fe8fbf36b73ee2d", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "73cb056bee8d98e0d185fb641ccf0730", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "31fc0701b0138e9d517802ce3dae49e8", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0d4e94c8be945d6ebfbde9a7ce5e43a5", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a808ea340d49477099ea1a71dd6f05ba", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "580660e11127c5dfdbcda68853a49ba0", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "23fad1294e92a433838e8d5b886cbaa0", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f60561ce4427bcef72abbbe058be0186", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "aa9a60b020a6368ec75a24dc20864c5e", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bb927ea6fd625099361703d6ab193a10", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9f2659860d0651d5084898e58f18db37", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 7.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 7.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ddc9614e29345c82acaff74cacac8bbc", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 16.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "141e8300f581875761e9dc308946e092", - "notes": [], - "params": { - "seconds": 1.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b22db511c943124628d5b9e12a5214fc", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 16.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "touchTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4fc79926d971451151d9871e600b7387", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "radius": 1.0, - "speed": 60.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -1.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 15.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cfc51d330ae4be9ed06dea079045b04c", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 359.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "642fd4b9b268619544cb12f55a88304c", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "moduleId": "UUID" - }, - "strategy": "usingGripper" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e95a1b9a129d8ccf78f7d6ffd4275c64", - "notes": [], - "params": { - "seconds": 90.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "88a37b605a7fd179714001e800e4d53a", - "notes": [], - "params": { - "message": "\n\n----------ADDING EPH3----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "128ade80924cb01a491759f7e15242cc", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "985b28047bc9bf85068fcd1cad7765a7", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 8.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A4" - }, - "result": { - "position": { - "x": 369.3, - "y": 74.15, - "z": 13.0 - }, - "volume": 8.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "773226e52da048d688c0e39ff7d205bd", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 8.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 8.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6acd32649b09ba4ee59c2e8230d1f1ba", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0bb89ce96ead87c396c38b105a1733b2", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b22f3f2d2723811944d129032a376005", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 412.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3a725551ff77626c661addc11c85e79c", - "notes": [], - "params": { - "message": "\n\n----------TRANSFERRING ELUTE----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "34064f6b319716e8d4bd456e74a85f67", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A6" - }, - "result": { - "position": { - "x": 59.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f1b5a1227acc8e0c996fac4a5b1eed5a", - "notes": [], - "params": { - "flowRate": 7.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 8.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.149999999999999 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.31 - }, - "volume": 8.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "389b353fee2a9932503c102689b31a7d", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 8.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 8.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f37014c13bbbdd7cf997d41b3e9f2555", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 50.459999999999994 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4f2926b08d8ff5716d3d388e5ff3aeda", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "199861e98b6784b606bc3a798cc21adc", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 359.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5e7ffb1e17edf90dd21bb6402f4e61cb", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": "offDeck", - "strategy": "manualMoveWithPause" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/closeLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f596cf492a4aa18c0a78962946317c9f", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/runProfile", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "13c1a4f2e91bd57161ee09096db29059", - "notes": [], - "params": { - "blockMaxVolumeUl": 17.0, - "moduleId": "UUID", - "profile": [ - { - "celsius": 94.0, - "holdSeconds": 60.0 - } - ] - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c4f468125fb7219cc751c069d3c67477", - "notes": [], - "params": { - "celsius": 4.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 4.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "da97683b7f34741bc65ff23fa048b830", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/openLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4221bd22c8a1eb22232ef8e6a7e7ff45", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0f091935a1a7399794f9581e659dcb0e", - "notes": [], - "params": { - "message": "\n\n----------ADDING FSA----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7a176bc03bbf77898f7ffa407ea492a5", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A7" - }, - "result": { - "position": { - "x": 68.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fdd4c037f72192630e23143203453fe6", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 8.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 378.3, - "y": 74.15, - "z": 13.0 - }, - "volume": 8.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c3748efc9cf7809283f676220c486f7c", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 8.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 8.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "12ff084c76776a7fc82b5bb240453304", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6b6f0aae318f1cb134fc40f53ba5c29b", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "79985b87ab70d2619333184824beb425", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d46fe87cae878bc66c847a0cbf663c5f", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d8d223bc3df2ffe1916a94b78c6f75d4", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "55236da67108ce78c1b2fd22b7f58cf5", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5013bedc495e54d9c994ca6ecb6a3304", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6a8b334c3c6dd89d77d727db4a2d0905", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d4697967048dec03f8379d91b2122941", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0e95bac1c6b7e126737543371150ebfd", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 19.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8b1193f8aad3d883df9b1236a7035a97", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8998c1ea61f8979eee45de54caa22fb7", - "notes": [], - "params": { - "seconds": 1.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5cbfa56632670eaa5d85c6dc55eeb9ea", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "touchTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0a798cd4aad04f049902c7b9f500d1c3", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "radius": 1.0, - "speed": 60.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -1.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 15.260000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "59b2e26b7244cb274df157ebedebc0a1", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 412.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/closeLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1caf8473424e9499f11a1c12ff240937", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/runProfile", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7d0b200036ec0bd09dcf980764dbd257", - "notes": [], - "params": { - "blockMaxVolumeUl": 25.0, - "moduleId": "UUID", - "profile": [ - { - "celsius": 25.0, - "holdSeconds": 600.0 - }, - { - "celsius": 42.0, - "holdSeconds": 900.0 - }, - { - "celsius": 70.0, - "holdSeconds": 900.0 - } - ] - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ce231cd2e87c00ca926aa296519bac6a", - "notes": [], - "params": { - "celsius": 4.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 4.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "dab2ad7a7aa227d17ae84bfe3ebe67f1", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/openLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3160b183c42da9abcdfd618d6b375807", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c7ca1b17d1348ed1dd69565e0ab6d559", - "notes": [], - "params": { - "message": "\n\n----------ADDING SMM----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cbf5f3ec41a0236af7ddf7292227da40", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A8" - }, - "result": { - "position": { - "x": 77.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d59a18a21f50aec382438feabac86b5d", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 25.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A6" - }, - "result": { - "position": { - "x": 387.3, - "y": 74.15, - "z": 13.0 - }, - "volume": 25.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fa2874da436a4ce1e1b518b5929a4b7d", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 25.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 25.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ed2888e9812d6ed5b579098d5f7dcadb", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6f984f796140a36b7e4b047af2580cad", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "056bf9604a87b6b7251a0dd7ee0a0533", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2dd228ae53cef058bed3795b223cbd9c", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "401120eb90da95947308e31b43dccb8d", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2f09e6ed15dd6a9c607537f22fd56482", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "57370e705965f5648df3898f2301cd9e", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "06c1334811158883f7c36da25a22e33e", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0fca0fa0c64f8503a2837c9006667146", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "48f33362c3c7f619223ac2cc8c337c38", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 40.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8799e4f3726c598289f8bd7b23f0abf3", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4da4535a7b8dbf796c7361ed841dc830", - "notes": [], - "params": { - "seconds": 1.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "09e205b3ec47cd7f5c507ef7f6f180e1", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "touchTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "86ab24cd106991df03153585488a6bd8", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "radius": 1.0, - "speed": 60.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -1.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 15.260000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c212e5981120f727c6decc1943c152ad", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 359.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetLidTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e842bc8a137ba1d36a17d3faf61e07b1", - "notes": [], - "params": { - "celsius": 40.0, - "moduleId": "UUID" - }, - "result": { - "targetLidTemperature": 40.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForLidTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3a91d0a6da70911cf187829fea8a1c6c", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/closeLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "60ac672f2f39611656b99757dd9bcf74", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/runProfile", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "12e135979be4e41816f8008d391ac2ff", - "notes": [], - "params": { - "blockMaxVolumeUl": 50.0, - "moduleId": "UUID", - "profile": [ - { - "celsius": 16.0, - "holdSeconds": 3600.0 - } - ] - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b719f4e921a8f757f7c4d993f3da43d9", - "notes": [], - "params": { - "celsius": 4.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 4.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8c75d278bb185b008e22212d155ef5dc", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/openLid", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b5f410ba45b213bd477900bef4951843", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b27ed28512232cb0551a5af34c2261e5", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "slotName": "D2" - }, - "strategy": "usingGripper" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/setTargetBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "094738334022c0efdb7d09feb70485a4", - "notes": [], - "params": { - "celsius": 21.0, - "holdTimeSeconds": 0.0, - "moduleId": "UUID" - }, - "result": { - "targetBlockTemperature": 21.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "thermocycler/waitForBlockTemperature", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f53679fa22cc21426034afb9166c4c09", - "notes": [], - "params": { - "moduleId": "UUID" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "16840a171c215462a28e2f4e1363f2c0", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "moduleId": "UUID" - }, - "strategy": "manualMoveWithPause" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e1a5efdc0f7ef98106e4306b5dd2e6b8", - "notes": [], - "params": { - "message": "\n\n----------ADDING BEADS----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "682b477a087dd92ac6159f900115fb35", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 214.38, - "y": 288.38, - "z": 99.0 - }, - "tipDiameter": 5.59, - "tipLength": 48.25, - "tipVolume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "43d5d251497da47db350309e9d0f34dd", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f49285a51e7d0e936653b2e5d52c3bea", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5d4d46d37afbd6ae16e079c02fb55bbc", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "65635c49da6868a4305fac7d5abf5425", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b71e5cacbf131d7daa8a13fb5dd1cf07", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fedf2d26f50dc893ce9ee6b0d7eb9fb6", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f1d932332dc990ca22ca874303e26873", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d25680d8647d4de548ebd009fab58608", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9cd005defed08a0daad0d5b1bd4d03e8", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bf755956d5e9addade84d0cef3331b6e", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d6786c7d0cd83c2509a9959f0f04a593", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a025fc0aa12c342b03016accb2973631", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b47dfd3ccbda1a5b28a165e301a5a0f9", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "216472b31cc3c3d454bbfd7d76b3b7ed", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a4a946ea27a345fbb7e85ad53a45ade1", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4e8f5cfcd829473d768d8cc759a5dac2", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3b94f21a0c88800073a4303564fc63b7", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1b4c2edaee80fe222e4a5b83472ddf1d", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8e03cc5452fe5bd73f794968e234d70b", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5cc98b1e554ad32ca80cb5951f8161d7", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c95e6f872df87081a47ea61603e9b4ca", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0ab71ffdb60d9e4794eb2a6deb883cf4", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "dc4eaa79925d9c73b6fbd25f5441dba9", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8da7cc1166fc139926f6c84baa8c70cc", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5b6f914bea0c4ffdc1f04b6de79ef05b", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4ce0076f932a86c0082742c8e5e7467c", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d928c7a3181f8a98f441585a86e9a972", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "712e51b617d0f48491ce05e0058d50c0", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "89f3ac0193b80bcd369e8ecb32ba1546", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2702670c323384ed41cdad11001069f0", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d0057ae136577bbd0ac88b74ef799412", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d83978b1ca8133a1bba1a15230260e3d", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cb4fd30824e9e428b29558d180c71b46", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3acbc3464821ecc3e7280c0b35081001", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9b8f8c48eae538d5ae472f988cd63797", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7be87f8236a14202c03d6e6252b17165", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "e9de57ce33c992b57fc0ca013dd166bf", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a78f8aa319c9395675cfdfd11d727ed2", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "48e844e531197d305f35b100f4222ec9", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "912ca45f89f86e458cb1415ae6926fe0", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 200.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "377e827673e4ed63668be12d0ccd5fd6", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 90.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 90.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f618f13c5e3cc165d6606d115ad97d83", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A5" - }, - "result": { - "position": { - "x": 50.3, - "y": 74.15, - "z": 56.95 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cd81a730a89ff4b52dcb40b50feb3ceb", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 90.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 90.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "75669bcf0b341326a1d77f0c00436a88", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9168388b37a91f3d345226ab465dc5ee", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "139f3e84c7e8105b637c0272055fe353", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1a6b6222ba580a3f05861298b380d650", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7633fe17308172238547ac37e87ed4ef", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d57db4e9aa442e5462704781bd4431bd", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ba85e92133639b1920fe10d9972440c4", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cf2afde9c174df0484ba43de9c07306b", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b496115ac86d35cea2168e5ad70548cd", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5eb6124ba5865aeede1f06c4e5744095", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1fe26400f63a02249e4c68b0d424e780", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "122fa7f2b2ac35027f935938ac50c8ab", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "05da1119ab89f4124a4b0566dee1ce0d", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0067c6aa4e4e4c88079d66322f1f414a", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8533c051c7c1c3d40baa81ce816a87ea", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "21796119f6ba48327ee82af43d70dedb", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b69b894ad8c8f464e7fa039124fdb44f", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "206d69df9193928f581d8049e9644896", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4bc1dd42516b721e81fe511e76c1bce8", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6e01eb7ee577e28580043089ccebffbf", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 100.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 100.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d70cf2f99fcfd1a78d2918c2a3640277", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 13.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b7ac87f3143a8e94167c971444ea082f", - "notes": [], - "params": { - "seconds": 2.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "74e0fde95013cef52a4b86aca1e31911", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 13.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2167c790163b647e1673430d8407acbe", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 509.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2fe1007571bb088ac9fddbe0e59b54aa", - "notes": [], - "params": { - "seconds": 300.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ef7903a646d62d50c9d0cfc39aa7c364", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "moduleId": "UUID" - }, - "strategy": "usingGripper" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d0001ee8a8bb6a3a3065465468162f92", - "notes": [], - "params": { - "seconds": 180.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1a990ae34fde9280ff36803d451ead8b", - "notes": [], - "params": { - "message": "\n\n----------REMOVE SUPER----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6d4d0312b5bfe8f4fdf1c50d16bcded9", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A6" - }, - "result": { - "position": { - "x": 223.38, - "y": 288.38, - "z": 99.0 - }, - "tipDiameter": 5.59, - "tipLength": 48.25, - "tipVolume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "35d5ea9b45c6e4fe04eaefbe07faa4ca", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 140.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.949999999999996 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.510000000000005 - }, - "volume": 140.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c83da5f07fe58aa4acf6e71a83840a1e", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.149999999999999 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.31 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "34f5ef829533277943b396863d2d3090", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 47.459999999999994 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "561ee6926eb74c52d372fe3bc0c2b891", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f4bea182967bfe77f477c8f134f6edd2", - "notes": [], - "params": { - "seconds": 2.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4d724015d6e939461f04f9b8d3bcf44a", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f7cf56fe34fc2fdea9799801b8399a0e", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 359.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fc1348cb1ac415a29f8f4f565aded186", - "notes": [], - "params": { - "message": "\n\n----------TWO WASHES----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "8017ae087c370713f8e84e54e27337da", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A7" - }, - "result": { - "position": { - "x": 232.38, - "y": 288.38, - "z": 99.0 - }, - "tipDiameter": 5.59, - "tipLength": 48.25, - "tipVolume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cda0933085243585cf946275be748ccd", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A3" - }, - "result": { - "position": { - "x": 32.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d9ca89370731eefd12eab9fd6077bc55", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A3" - }, - "result": { - "position": { - "x": 32.3, - "y": 74.15, - "z": 56.95 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d0652d79b21be209840a2a681e44ddc6", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 50.459999999999994 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "4a7e59dbe17b1adf900c5a6d9f2e7e45", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 20.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 70.46 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "36c3086a297b20a85ef8232b0c21b51a", - "notes": [], - "params": { - "seconds": 30.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7bbcfa08c751fdaba7d6d581370d2955", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.949999999999996 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.510000000000005 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b7308b04d29fd37cc9be1436c087d9b4", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.149999999999999 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.31 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "35d196d5fe5cabfd879b20a2c61cdb10", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 47.459999999999994 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5837f318dfb28b3436b919706eb936c3", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 160.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - }, - "volume": 160.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "bf173b3c58d4fb352e0372d47213119d", - "notes": [], - "params": { - "seconds": 2.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "02cd32879185c6bfb84a65d23807a880", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "15ea5c4abc794d6e7c634b6588a6e9c1", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 509.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3cf3b07d8998d888692eb223b05060df", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A8" - }, - "result": { - "position": { - "x": 241.38, - "y": 288.38, - "z": 99.0 - }, - "tipDiameter": 5.59, - "tipLength": 48.25, - "tipVolume": 200.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "04961eb23d9f6254142ee16ab14248a8", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A3" - }, - "result": { - "position": { - "x": 32.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d70bae5f325b508b99b8dd3e0138d96f", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A3" - }, - "result": { - "position": { - "x": 32.3, - "y": 74.15, - "z": 56.95 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "672debfdee77318ffff1b2cff21ccab7", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 50.459999999999994 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "66093f66f5aa96e91c39f0e3c01e46cd", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 20.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 70.46 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "347c5121278c2810e041c94cff7db2e3", - "notes": [], - "params": { - "seconds": 30.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cee3f5ea84293d86b1ba85b9e338813b", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 150.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.949999999999996 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.510000000000005 - }, - "volume": 150.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fac47a9fd8d07b04483f636217bf69d1", - "notes": [], - "params": { - "flowRate": 107.39999999999999, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.149999999999999 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.31 - }, - "volume": 10.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9d8ac359ccb52841dfb3e4df5a1f4a18", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 47.459999999999994 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "585038ade3637a88d64e4608c4bb5ee4", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 160.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - }, - "volume": 160.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ba28d9ce128a5b4b3489322a661b3651", - "notes": [], - "params": { - "seconds": 2.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3d2f711f065ca932e8230b8aa3aae811", - "notes": [], - "params": { - "flowRate": 716.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -3.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 363.78, - "z": 28.400000000000002 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9e9947e94d00cd7af2fbd93da9f0a80b", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 359.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "aceac2839f511dd95c277edef67d8fb7", - "notes": [], - "params": { - "seconds": 120.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ca67c1c88c455a5aba1959cd1caf8f2a", - "notes": [], - "params": { - "message": "\n\n----------ADDING ELUTION BUFFER----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5eca5b4fc517fd179f00584d01536884", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "slotName": "D2" - }, - "strategy": "usingGripper" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "32bbdbea3b7c9013fa48ade4fe3324fb", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A9" - }, - "result": { - "position": { - "x": 86.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "5a315c4cd14cb77926724b952a7fbead", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -37.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A6" - }, - "result": { - "position": { - "x": 59.3, - "y": 74.15, - "z": 22.95 - }, - "volume": 19.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "17ec51833aa27af96c25ee6505183966", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 19.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 2.05 - }, - "volume": 19.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "9f24e834779a37078144cf3156cd3db8", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f33cf695ecd2531478a68d2802e148f7", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c429821867b899d5c77969f6fbaacc9f", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "74b9adbac35a2a3a642e07a860b1c426", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "24733fb2d4d18cf9508abd39983f3d38", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a3ec8da86c6e0a867d6969d1297611a9", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "404694e8951bb51adca17738330711d3", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "11d60469d4437e94279c257149f593da", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fdf47b41ab2d95b5f5814f29947d2a3e", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "a7ba68c365c32dd9f9bf5efa42268ead", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7d92a9f1e96414b17520cfc4d0a39df4", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c01967532b5744a89d4ae61978d6e3f3", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ea1d41201d32add509fd9ec69cce92a4", - "notes": [], - "params": { - "flowRate": 35.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.15 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.849999999999999 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "87f5ad959bf21caa837f7be34cb2acbc", - "notes": [], - "params": { - "flowRate": 114.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 15.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -8.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 7.05 - }, - "volume": 15.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "53644c8767ea650bb4a2978c1694951f", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "3a1e1283bc33c1ffc45046a245e7deff", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "613dc6176dd81f519d7271bb1af5bc5a", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "2ea46cbed07c4b44ee476894708bc003", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c3aa22272f7134a79ddffd9136359c37", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6a81677c234f3abe6904d8aa3abab446", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "705582b79c3d98faa603533ac103d651", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f25fb64699eac468c88e4806f5bb3916", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "b9b463d95c4eefeb5814e9982affce67", - "notes": [], - "params": { - "flowRate": 52.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "7d467408fd88a0136fb6c7456c7cc94a", - "notes": [], - "params": { - "flowRate": 85.5, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 14.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.25 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 1.7499999999999993 - }, - "volume": 14.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fea7c6fb5de7e3dcd4bf4957de66f05e", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 16.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "cc92fcbd002554e2ce0855f343a3a68e", - "notes": [], - "params": { - "seconds": 1.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "017af87721e992b5157fb78be01033b2", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 16.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "touchTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "d61eb6e9d9b3183f747f70ce29828ff7", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "radius": 1.0, - "speed": 60.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -1.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 178.38, - "y": 74.24, - "z": 15.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "ddda43ec173555ea3b16b98ad6d2c39e", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 412.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveLabware", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "0367269519dab3d917ff70e4c2eb3ac5", - "notes": [], - "params": { - "labwareId": "UUID", - "newLocation": { - "moduleId": "UUID" - }, - "strategy": "usingGripper" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "waitForDuration", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "c92eb88b6abd64aee972dffe5e25327a", - "notes": [], - "params": { - "seconds": 120.0 - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "comment", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "fff71392918a3b8f2f00bdefa4a53134", - "notes": [], - "params": { - "message": "\n\n----------TRANSFERRING ELUTE----------\n" - }, - "result": {}, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "1211dc66481f76a8e1dd9cc3a16fc306", - "notes": [], - "params": { - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A10" - }, - "result": { - "position": { - "x": 95.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.849999999999994, - "tipVolume": 50.0 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "aspirate", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "02042c1eb009e7757551c7d6a5e2493f", - "notes": [], - "params": { - "flowRate": 7.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 17.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -14.149999999999999 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 36.31 - }, - "volume": 17.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dispense", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "f88f2a7423ac5f5070ba46bd9989126c", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "volume": 17.5, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -13.95 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 2.3100000000000014 - }, - "volume": 17.5 - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "moveToWell", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "03a1b309d898cee327e0b3dd131a7507", - "notes": [], - "params": { - "forceDirect": false, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 342.38, - "y": 181.24, - "z": 50.459999999999994 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "blowout", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "674540c74c2dc67ded15c1b937ef28fb", - "notes": [], - "params": { - "flowRate": 57.0, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top", - "volumeOffset": 0.0 - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": -5.624999999999998, - "y": 356.2, - "z": 16.26 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" - }, - { - "commandType": "dropTip", - "completedAt": "TIMESTAMP", - "createdAt": "TIMESTAMP", - "id": "UUID", - "key": "6498d67c1416ebe7d0b8c12d8b8d3c87", - "notes": [], - "params": { - "alternateDropLocation": true, - "labwareId": "UUID", - "pipetteId": "UUID", - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "default" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 359.25, - "y": 364.0, - "z": 40.0 - } - }, - "startedAt": "TIMESTAMP", - "status": "succeeded" } ], "config": { @@ -31721,7 +5968,34 @@ "protocolType": "python" }, "createdAt": "TIMESTAMP", - "errors": [], + "errors": [ + { + "createdAt": "TIMESTAMP", + "detail": "ValidationError [line 54]: 2 validation errors for LoadLabwareParams\ndisplayName.str\n Input should be a valid string [type=string_type, input_value=8, input_type=int]\n For further information visit https://errors.pydantic.dev/2.10/v/string_type\ndisplayName.none\n Input should be None [type=none_required, input_value=8, input_type=int]\n For further information visit https://errors.pydantic.dev/2.10/v/none_required", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "id": "UUID", + "isDefined": false, + "wrappedErrors": [ + { + "createdAt": "TIMESTAMP", + "detail": "pydantic_core._pydantic_core.ValidationError: 2 validation errors for LoadLabwareParams\ndisplayName.str\n Input should be a valid string [type=string_type, input_value=8, input_type=int]\n For further information visit https://errors.pydantic.dev/2.10/v/string_type\ndisplayName.none\n Input should be None [type=none_required, input_value=8, input_type=int]\n For further information visit https://errors.pydantic.dev/2.10/v/none_required", + "errorCode": "4000", + "errorInfo": { + "args": "()", + "class": "ValidationError", + "title": "LoadLabwareParams", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"\", line N, in \n\n File \"pl_langone_ribo_pt1_ramp.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/module_contexts.py\", line N, in load_labware\n labware_core = self._protocol_core.load_labware(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line N, in load_labware\n cmd.LoadLabwareParams(\n\n File \"/usr/local/lib/python3.10/site-packages/pydantic/main.py\", line N, in __init__\n validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)\n" + }, + "errorType": "PythonException", + "id": "UUID", + "isDefined": false, + "wrappedErrors": [] + } + ] + } + ], "files": [ { "name": "pl_langone_ribo_pt1_ramp.py", @@ -31737,12 +6011,6 @@ "slotName": "A3" } }, - { - "definitionUri": "opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2", - "id": "UUID", - "loadName": "opentrons_96_wellplate_200ul_pcr_full_skirt", - "location": "offDeck" - }, { "definitionUri": "opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2", "id": "UUID", @@ -31755,155 +6023,25 @@ "definitionUri": "opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2", "id": "UUID", "loadName": "opentrons_96_wellplate_200ul_pcr_full_skirt", - "location": { - "moduleId": "UUID" - } + "location": "offDeck" }, { - "definitionUri": "opentrons/nest_96_wellplate_2ml_deep/2", + "definitionUri": "opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2", "id": "UUID", - "loadName": "nest_96_wellplate_2ml_deep", - "location": { - "moduleId": "UUID" - } + "loadName": "opentrons_96_wellplate_200ul_pcr_full_skirt", + "location": "offDeck" }, { "definitionUri": "opentrons/nest_96_wellplate_2ml_deep/2", - "displayName": "8", "id": "UUID", "loadName": "nest_96_wellplate_2ml_deep", "location": { "moduleId": "UUID" } - }, - { - "definitionUri": "opentrons/nest_12_reservoir_15ml/1", - "id": "UUID", - "loadName": "nest_12_reservoir_15ml", - "location": { - "slotName": "A2" - } - }, - { - "definitionUri": "opentrons/opentrons_flex_96_tiprack_50ul/1", - "id": "UUID", - "loadName": "opentrons_flex_96_tiprack_50ul", - "location": { - "slotName": "C1" - } - }, - { - "definitionUri": "opentrons/opentrons_flex_96_tiprack_50ul/1", - "id": "UUID", - "loadName": "opentrons_flex_96_tiprack_50ul", - "location": { - "slotName": "C2" - } - }, - { - "definitionUri": "opentrons/opentrons_flex_96_tiprack_200ul/1", - "id": "UUID", - "loadName": "opentrons_flex_96_tiprack_200ul", - "location": { - "slotName": "B2" - } - }, - { - "definitionUri": "opentrons/opentrons_flex_96_tiprack_200ul/1", - "id": "UUID", - "loadName": "opentrons_flex_96_tiprack_200ul", - "location": { - "slotName": "B3" - } } ], "liquidClasses": [], - "liquids": [ - { - "description": "DB1/DP1", - "displayColor": "#7EFF42", - "displayName": "DB1/DP1", - "id": "UUID" - }, - { - "description": "RDB/RDE", - "displayColor": "#50D5FF", - "displayName": "RDB/RDE", - "id": "UUID" - }, - { - "description": "PRB/PRE", - "displayColor": "#FF4F4F", - "displayName": "PRB/PRE", - "id": "UUID" - }, - { - "description": "EPH3", - "displayColor": "#B925FF", - "displayName": "EPH3", - "id": "UUID" - }, - { - "description": "FSA/RVT", - "displayColor": "#FF9900", - "displayName": "FSA/RVT", - "id": "UUID" - }, - { - "description": "SMM", - "displayColor": "#0019FF", - "displayName": "SMM", - "id": "UUID" - }, - { - "description": "BEADS", - "displayColor": "#007AFF", - "displayName": "BEADS", - "id": "UUID" - }, - { - "description": "ETHANOL", - "displayColor": "#FF0076", - "displayName": "ETHANOL", - "id": "UUID" - }, - { - "description": "ELUTION BUFFER", - "displayColor": "#00FFBC", - "displayName": "ELUTION BUFFER", - "id": "UUID" - }, - { - "description": "RSB", - "displayColor": "#00AAFF", - "displayName": "RSB", - "id": "UUID" - }, - { - "description": "Sample", - "displayColor": "#008000", - "displayName": "Sample", - "id": "UUID" - }, - { - "description": "Mastermix", - "displayColor": "#008000", - "displayName": "Mastermix", - "id": "UUID" - }, - { - "description": "Water", - "displayColor": "#A52A2A", - "displayName": "Water", - "id": "UUID" - }, - { - "description": "DNA", - "displayColor": "#A52A2A", - "displayName": "DNA", - "id": "UUID" - } - ], + "liquids": [], "metadata": { "author": "Rami Farawi = '3.8'", "version": "==0.3.1" }, + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "anyio": { "hashes": [ "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780", @@ -32,11 +41,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "click": { "hashes": [ @@ -48,19 +57,19 @@ }, "exceptiongroup": { "hashes": [ - "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", - "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.1" + "version": "==1.2.2" }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "jsonschema": { "hashes": [ @@ -179,63 +188,129 @@ }, "packaging": { "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3", + "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3" ], "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==21.3" + "markers": "python_version >= '3.7'", + "version": "==22.0" + }, + "performance-metrics": { + "editable": true, + "file": "../performance-metrics" }, "pydantic": { "hashes": [ - "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303", - "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe", - "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47", - "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494", - "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33", - "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86", - "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d", - "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c", - "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a", - "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565", - "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb", - "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62", - "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62", - "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0", - "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523", - "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d", - "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405", - "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f", - "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b", - "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718", - "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed", - "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb", - "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5", - "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc", - "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942", - "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe", - "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246", - "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350", - "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303", - "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09", - "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33", - "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8", - "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a", - "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1", - "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6", - "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d" + "sha256:c7a8a9fdf7d100afa49647eae340e2d23efa382466a8d177efcd1381e9be5598", + "sha256:f66a7073abd93214a20c5f7b32d56843137a7a2e70d02111f3be287035c45370" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.10.12" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" + }, + "pydantic-core": { + "hashes": [ + "sha256:0102e49ac7d2df3379ef8d658d3bc59d3d769b0bdb17da189b75efa861fc07b4", + "sha256:0123655fedacf035ab10c23450163c2f65a4174f2bb034b188240a6cf06bb123", + "sha256:043ef8469f72609c4c3a5e06a07a1f713d53df4d53112c6d49207c0bd3c3bd9b", + "sha256:0448b81c3dfcde439551bb04a9f41d7627f676b12701865c8a2574bcea034437", + "sha256:05b366fb8fe3d8683b11ac35fa08947d7b92be78ec64e3277d03bd7f9b7cda79", + "sha256:07049ec9306ec64e955b2e7c40c8d77dd78ea89adb97a2013d0b6e055c5ee4c5", + "sha256:084414ffe9a85a52940b49631321d636dadf3576c30259607b75516d131fecd0", + "sha256:086c5db95157dc84c63ff9d96ebb8856f47ce113c86b61065a066f8efbe80acf", + "sha256:12625e69b1199e94b0ae1c9a95d000484ce9f0182f9965a26572f054b1537e44", + "sha256:16b25a4a120a2bb7dab51b81e3d9f3cde4f9a4456566c403ed29ac81bf49744f", + "sha256:19f1352fe4b248cae22a89268720fc74e83f008057a652894f08fa931e77dced", + "sha256:1a2ab4f410f4b886de53b6bddf5dd6f337915a29dd9f22f20f3099659536b2f6", + "sha256:1c7b81beaf7c7ebde978377dc53679c6cba0e946426fc7ade54251dfe24a7604", + "sha256:1cf842265a3a820ebc6388b963ead065f5ce8f2068ac4e1c713ef77a67b71f7c", + "sha256:1eb37f7d6a8001c0f86dc8ff2ee8d08291a536d76e49e78cda8587bb54d8b329", + "sha256:23af245b8f2f4ee9e2c99cb3f93d0e22fb5c16df3f2f643f5a8da5caff12a653", + "sha256:257d6a410a0d8aeb50b4283dea39bb79b14303e0fab0f2b9d617701331ed1515", + "sha256:276ae78153a94b664e700ac362587c73b84399bd1145e135287513442e7dfbc7", + "sha256:2b1a195efd347ede8bcf723e932300292eb13a9d2a3c1f84eb8f37cbbc905b7f", + "sha256:329a721253c7e4cbd7aad4a377745fbcc0607f9d72a3cc2102dd40519be75ed2", + "sha256:358331e21a897151e54d58e08d0219acf98ebb14c567267a87e971f3d2a3be59", + "sha256:3649bd3ae6a8ebea7dc381afb7f3c6db237fc7cebd05c8ac36ca8a4187b03b30", + "sha256:3713dc093d5048bfaedbba7a8dbc53e74c44a140d45ede020dc347dda18daf3f", + "sha256:3ef71ec876fcc4d3bbf2ae81961959e8d62f8d74a83d116668409c224012e3af", + "sha256:41ae8537ad371ec018e3c5da0eb3f3e40ee1011eb9be1da7f965357c4623c501", + "sha256:4a801c5e1e13272e0909c520708122496647d1279d252c9e6e07dac216accc41", + "sha256:4c83c64d05ffbbe12d4e8498ab72bdb05bcc1026340a4a597dc647a13c1605ec", + "sha256:4cebb9794f67266d65e7e4cbe5dcf063e29fc7b81c79dc9475bd476d9534150e", + "sha256:5668b3173bb0b2e65020b60d83f5910a7224027232c9f5dc05a71a1deac9f960", + "sha256:56e6a12ec8d7679f41b3750ffa426d22b44ef97be226a9bab00a03365f217b2b", + "sha256:582871902e1902b3c8e9b2c347f32a792a07094110c1bca6c2ea89b90150caac", + "sha256:5c8aa40f6ca803f95b1c1c5aeaee6237b9e879e4dfb46ad713229a63651a95fb", + "sha256:5d813fd871b3d5c3005157622ee102e8908ad6011ec915a18bd8fde673c4360e", + "sha256:5dd0ec5f514ed40e49bf961d49cf1bc2c72e9b50f29a163b2cc9030c6742aa73", + "sha256:5f3cf3721eaf8741cffaf092487f1ca80831202ce91672776b02b875580e174a", + "sha256:6294907eaaccf71c076abdd1c7954e272efa39bb043161b4b8aa1cd76a16ce43", + "sha256:64d094ea1aa97c6ded4748d40886076a931a8bf6f61b6e43e4a1041769c39dd2", + "sha256:6650a7bbe17a2717167e3e23c186849bae5cef35d38949549f1c116031b2b3aa", + "sha256:67b6655311b00581914aba481729971b88bb8bc7996206590700a3ac85e457b8", + "sha256:6b06c5d4e8701ac2ba99a2ef835e4e1b187d41095a9c619c5b185c9068ed2a49", + "sha256:6ce883906810b4c3bd90e0ada1f9e808d9ecf1c5f0b60c6b8831d6100bcc7dd6", + "sha256:6db09153d8438425e98cdc9a289c5fade04a5d2128faff8f227c459da21b9703", + "sha256:6f80fba4af0cb1d2344869d56430e304a51396b70d46b91a55ed4959993c0589", + "sha256:743e5811b0c377eb830150d675b0847a74a44d4ad5ab8845923d5b3a756d8100", + "sha256:753294d42fb072aa1775bfe1a2ba1012427376718fa4c72de52005a3d2a22178", + "sha256:7568f682c06f10f30ef643a1e8eec4afeecdafde5c4af1b574c6df079e96f96c", + "sha256:7706e15cdbf42f8fab1e6425247dfa98f4a6f8c63746c995d6a2017f78e619ae", + "sha256:785e7f517ebb9890813d31cb5d328fa5eda825bb205065cde760b3150e4de1f7", + "sha256:7a05c0240f6c711eb381ac392de987ee974fa9336071fb697768dfdb151345ce", + "sha256:7ce7eaf9a98680b4312b7cebcdd9352531c43db00fca586115845df388f3c465", + "sha256:7ce8e26b86a91e305858e018afc7a6e932f17428b1eaa60154bd1f7ee888b5f8", + "sha256:7d0324a35ab436c9d768753cbc3c47a865a2cbc0757066cb864747baa61f6ece", + "sha256:7e9b24cca4037a561422bf5dc52b38d390fb61f7bfff64053ce1b72f6938e6b2", + "sha256:810ca06cca91de9107718dc83d9ac4d2e86efd6c02cba49a190abcaf33fb0472", + "sha256:820f6ee5c06bc868335e3b6e42d7ef41f50dfb3ea32fbd523ab679d10d8741c0", + "sha256:82764c0bd697159fe9947ad59b6db6d7329e88505c8f98990eb07e84cc0a5d81", + "sha256:8ae65fdfb8a841556b52935dfd4c3f79132dc5253b12c0061b96415208f4d622", + "sha256:8d5b0ff3218858859910295df6953d7bafac3a48d5cd18f4e3ed9999efd2245f", + "sha256:95d6bf449a1ac81de562d65d180af5d8c19672793c81877a2eda8fde5d08f2fd", + "sha256:964c7aa318da542cdcc60d4a648377ffe1a2ef0eb1e996026c7f74507b720a78", + "sha256:96ef39add33ff58cd4c112cbac076726b96b98bb8f1e7f7595288dcfb2f10b57", + "sha256:a6612c2a844043e4d10a8324c54cdff0042c558eef30bd705770793d70b224aa", + "sha256:a8031074a397a5925d06b590121f8339d34a5a74cfe6970f8a1124eb8b83f4ac", + "sha256:aab9e522efff3993a9e98ab14263d4e20211e62da088298089a03056980a3e69", + "sha256:ae579143826c6f05a361d9546446c432a165ecf1c0b720bbfd81152645cb897d", + "sha256:ae90b9e50fe1bd115b24785e962b51130340408156d34d67b5f8f3fa6540938e", + "sha256:b18cf68255a476b927910c6873d9ed00da692bb293c5b10b282bd48a0afe3ae2", + "sha256:b7efb12e5071ad8d5b547487bdad489fbd4a5a35a0fc36a1941517a6ad7f23e0", + "sha256:c4d9f15ffe68bcd3898b0ad7233af01b15c57d91cd1667f8d868e0eacbfe3f87", + "sha256:c53100c8ee5a1e102766abde2158077d8c374bee0639201f11d3032e3555dfbc", + "sha256:c57e493a0faea1e4c38f860d6862ba6832723396c884fbf938ff5e9b224200e2", + "sha256:c8319e0bd6a7b45ad76166cc3d5d6a36c97d0c82a196f478c3ee5346566eebfd", + "sha256:caffda619099cfd4f63d48462f6aadbecee3ad9603b4b88b60cb821c1b258576", + "sha256:cc0c316fba3ce72ac3ab7902a888b9dc4979162d320823679da270c2d9ad0cad", + "sha256:cdd02a08205dc90238669f082747612cb3c82bd2c717adc60f9b9ecadb540f80", + "sha256:d50ac34835c6a4a0d456b5db559b82047403c4317b3bc73b3455fefdbdc54b0a", + "sha256:d6b9dd6aa03c812017411734e496c44fef29b43dba1e3dd1fa7361bbacfc1354", + "sha256:da3131ef2b940b99106f29dfbc30d9505643f766704e14c5d5e504e6a480c35e", + "sha256:da43cbe593e3c87d07108d0ebd73771dc414488f1f91ed2e204b0370b94b37ac", + "sha256:dd59638025160056687d598b054b64a79183f8065eae0d3f5ca523cde9943940", + "sha256:e1895e949f8849bc2757c0dbac28422a04be031204df46a56ab34bcf98507342", + "sha256:e1a79ad49f346aa1a2921f31e8dbbab4d64484823e813a002679eaa46cba39e1", + "sha256:e460475719721d59cd54a350c1f71c797c763212c836bf48585478c5514d2854", + "sha256:e64ffaf8f6e17ca15eb48344d86a7a741454526f3a3fa56bc493ad9d7ec63936", + "sha256:e6e3ccebdbd6e53474b0bb7ab8b88e83c0cfe91484b25e058e581348ee5a01a5", + "sha256:e758d271ed0286d146cf7c04c539a5169a888dd0b57026be621547e756af55bc", + "sha256:f087879f1ffde024dd2788a30d55acd67959dcf6c431e9d3682d1c491a0eb474", + "sha256:f477d26183e94eaafc60b983ab25af2a809a1b48ce4debb57b343f671b7a90b6", + "sha256:fc535cb898ef88333cf317777ecdfe0faac1c2a3187ef7eb061b6f7ecf7e6bae" + ], + "markers": "python_version >= '3.8'", + "version": "==2.23.2" }, - "pyparsing": { + "pydantic-settings": { "hashes": [ - "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad", - "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742" + "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315", + "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88" ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.2" + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.4.0" }, "pyrsistent": { "hashes": [ @@ -290,6 +365,14 @@ "markers": "python_version >= '3.7'", "version": "==4.2.2" }, + "python-dotenv": { + "hashes": [ + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" + ], + "markers": "python_version >= '3.8'", + "version": "==1.0.1" + }, "pyusb": { "hashes": [ "sha256:2b4c7cb86dbadf044dfb9d3a4ff69fd217013dbe78a792177a3feb172449ea36", @@ -301,11 +384,11 @@ }, "setuptools": { "hashes": [ - "sha256:937a48c7cdb7a21eb53cd7f9b59e525503aa8abaf3584c730dc5f7a5bec3a650", - "sha256:a58a8fde0541dab0419750bcc521fbdf8585f6e5cb41909df3a472ef7b81ca95" + "sha256:5f4c08aa4d3ebcb57a50c33b1b07e94315d7fc7230f7115e47fc99776c8ce308", + "sha256:95b40ed940a1c67eb70fc099094bd6e99c6ee7c23aa2306f4d2697ba7916f9c6" ], "markers": "python_version >= '3.8'", - "version": "==70.1.1" + "version": "==74.1.2" }, "sniffio": { "hashes": [ @@ -320,9 +403,17 @@ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version >= '3.8'", + "markers": "python_version < '3.13'", "version": "==4.12.2" }, + "tzdata": { + "hashes": [ + "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", + "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.1" + }, "wrapt": { "hashes": [ "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc", @@ -419,19 +510,19 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "babel": { "hashes": [ - "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb", - "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413" + "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", + "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316" ], "markers": "python_version >= '3.8'", - "version": "==2.15.0" + "version": "==2.16.0" }, "backports.tarfile": { "hashes": [ @@ -473,11 +564,11 @@ }, "certifi": { "hashes": [ - "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", - "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.6.2" + "version": "==2024.8.30" }, "charset-normalizer": { "hashes": [ @@ -730,11 +821,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", - "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.1" + "version": "==1.2.2" }, "execnet": { "hashes": [ @@ -782,51 +873,51 @@ }, "fonttools": { "hashes": [ - "sha256:099634631b9dd271d4a835d2b2a9e042ccc94ecdf7e2dd9f7f34f7daf333358d", - "sha256:0c555e039d268445172b909b1b6bdcba42ada1cf4a60e367d68702e3f87e5f64", - "sha256:1e677bfb2b4bd0e5e99e0f7283e65e47a9814b0486cb64a41adf9ef110e078f2", - "sha256:2367d47816cc9783a28645bc1dac07f8ffc93e0f015e8c9fc674a5b76a6da6e4", - "sha256:28d072169fe8275fb1a0d35e3233f6df36a7e8474e56cb790a7258ad822b6fd6", - "sha256:31f0e3147375002aae30696dd1dc596636abbd22fca09d2e730ecde0baad1d6b", - "sha256:3e0ad3c6ea4bd6a289d958a1eb922767233f00982cf0fe42b177657c86c80a8f", - "sha256:45b4afb069039f0366a43a5d454bc54eea942bfb66b3fc3e9a2c07ef4d617380", - "sha256:4a2a6ba400d386e904fd05db81f73bee0008af37799a7586deaa4aef8cd5971e", - "sha256:4f520d9ac5b938e6494f58a25c77564beca7d0199ecf726e1bd3d56872c59749", - "sha256:52a6e0a7a0bf611c19bc8ec8f7592bdae79c8296c70eb05917fd831354699b20", - "sha256:5a4788036201c908079e89ae3f5399b33bf45b9ea4514913f4dbbe4fac08efe0", - "sha256:6b4f04b1fbc01a3569d63359f2227c89ab294550de277fd09d8fca6185669fa4", - "sha256:715b41c3e231f7334cbe79dfc698213dcb7211520ec7a3bc2ba20c8515e8a3b5", - "sha256:73121a9b7ff93ada888aaee3985a88495489cc027894458cb1a736660bdfb206", - "sha256:74ae2441731a05b44d5988d3ac2cf784d3ee0a535dbed257cbfff4be8bb49eb9", - "sha256:7d6166192dcd925c78a91d599b48960e0a46fe565391c79fe6de481ac44d20ac", - "sha256:7f193f060391a455920d61684a70017ef5284ccbe6023bb056e15e5ac3de11d1", - "sha256:907fa0b662dd8fc1d7c661b90782ce81afb510fc4b7aa6ae7304d6c094b27bce", - "sha256:93156dd7f90ae0a1b0e8871032a07ef3178f553f0c70c386025a808f3a63b1f4", - "sha256:93bc9e5aaa06ff928d751dc6be889ff3e7d2aa393ab873bc7f6396a99f6fbb12", - "sha256:95db0c6581a54b47c30860d013977b8a14febc206c8b5ff562f9fe32738a8aca", - "sha256:973d030180eca8255b1bce6ffc09ef38a05dcec0e8320cc9b7bcaa65346f341d", - "sha256:9cd7a6beec6495d1dffb1033d50a3f82dfece23e9eb3c20cd3c2444d27514068", - "sha256:9fe9096a60113e1d755e9e6bda15ef7e03391ee0554d22829aa506cdf946f796", - "sha256:a209d2e624ba492df4f3bfad5996d1f76f03069c6133c60cd04f9a9e715595ec", - "sha256:a239afa1126b6a619130909c8404070e2b473dd2b7fc4aacacd2e763f8597fea", - "sha256:ba9f09ff17f947392a855e3455a846f9855f6cf6bec33e9a427d3c1d254c712f", - "sha256:bb7273789f69b565d88e97e9e1da602b4ee7ba733caf35a6c2affd4334d4f005", - "sha256:bd5bc124fae781a4422f61b98d1d7faa47985f663a64770b78f13d2c072410c2", - "sha256:bff98816cb144fb7b85e4b5ba3888a33b56ecef075b0e95b95bcd0a5fbf20f06", - "sha256:c4ee5a24e281fbd8261c6ab29faa7fd9a87a12e8c0eed485b705236c65999109", - "sha256:c93ed66d32de1559b6fc348838c7572d5c0ac1e4a258e76763a5caddd8944002", - "sha256:d1a24f51a3305362b94681120c508758a88f207fa0a681c16b5a4172e9e6c7a9", - "sha256:d8f191a17369bd53a5557a5ee4bab91d5330ca3aefcdf17fab9a497b0e7cff7a", - "sha256:daaef7390e632283051e3cf3e16aff2b68b247e99aea916f64e578c0449c9c68", - "sha256:e40013572bfb843d6794a3ce076c29ef4efd15937ab833f520117f8eccc84fd6", - "sha256:eceef49f457253000e6a2d0f7bd08ff4e9fe96ec4ffce2dbcb32e34d9c1b8161", - "sha256:ee595d7ba9bba130b2bec555a40aafa60c26ce68ed0cf509983e0f12d88674fd", - "sha256:ef50ec31649fbc3acf6afd261ed89d09eb909b97cc289d80476166df8438524d", - "sha256:fa1f3e34373aa16045484b4d9d352d4c6b5f9f77ac77a178252ccbc851e8b2ee", - "sha256:fca66d9ff2ac89b03f5aa17e0b21a97c21f3491c46b583bb131eb32c7bab33af" + "sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122", + "sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397", + "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f", + "sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d", + "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60", + "sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169", + "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8", + "sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31", + "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923", + "sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2", + "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb", + "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab", + "sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb", + "sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a", + "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670", + "sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8", + "sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407", + "sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671", + "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88", + "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f", + "sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f", + "sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0", + "sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb", + "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2", + "sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d", + "sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c", + "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3", + "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719", + "sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749", + "sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4", + "sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f", + "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02", + "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58", + "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1", + "sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41", + "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4", + "sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb", + "sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb", + "sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3", + "sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d", + "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d", + "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2" ], "markers": "python_version >= '3.8'", - "version": "==4.53.0" + "version": "==4.53.1" }, "gprof2dot": { "hashes": [ @@ -847,11 +938,11 @@ }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "imagesize": { "hashes": [ @@ -863,11 +954,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:509ecb2ab77071db5137c655e24ceb3eee66e7bbc6574165d0d114d9fc4bbe68", - "sha256:ffef94b0b66046dd8ea2d619b701fe978d9264d38f3998bc4c27ec3b146a87c8" + "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1", + "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5" ], "markers": "python_version >= '3.8'", - "version": "==7.2.1" + "version": "==8.4.0" }, "iniconfig": { "hashes": [ @@ -887,19 +978,19 @@ }, "jaraco.context": { "hashes": [ - "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266", - "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2" + "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", + "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4" ], "markers": "python_version >= '3.8'", - "version": "==5.3.0" + "version": "==6.0.1" }, "jaraco.functools": { "hashes": [ - "sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664", - "sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8" + "sha256:3460c74cd0d32bf82b9576bbb3527c4364d5b27a21f5158a62aed6c4b42e23f5", + "sha256:c9d16a3ed4ccb5a889ad8e0b7a343401ee5b2a71cee6ed192d3f68bc351e94e3" ], "markers": "python_version >= '3.8'", - "version": "==4.0.1" + "version": "==4.0.2" }, "jinja2": { "hashes": [ @@ -910,132 +1001,133 @@ "markers": "python_version >= '3.6'", "version": "==3.0.3" }, - "jsonschema": { - "hashes": [ - "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d", - "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==4.17.3" - }, "keyring": { "hashes": [ - "sha256:2458681cdefc0dbc0b7eb6cf75d0b98e59f9ad9b2d4edd319d18f68bdca95e50", - "sha256:daaffd42dbda25ddafb1ad5fec4024e5bbcfe424597ca1ca452b299861e49f1b" + "sha256:8d85a1ea5d6db8515b59e1c5d1d1678b03cf7fc8b8dcfb1651e8c4a524eb42ef", + "sha256:8d963da00ccdf06e356acd9bf3b743208878751032d8599c6cc89eb51310ffae" ], "markers": "python_version >= '3.8'", - "version": "==25.2.1" + "version": "==25.3.0" }, "kiwisolver": { "hashes": [ - "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf", - "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e", - "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af", - "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f", - "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046", - "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3", - "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5", - "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71", - "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee", - "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3", - "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9", - "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b", - "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985", - "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea", - "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16", - "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89", - "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c", - "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9", - "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712", - "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342", - "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a", - "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958", - "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d", - "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a", - "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130", - "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff", - "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898", - "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b", - "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f", - "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265", - "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93", - "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929", - "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635", - "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709", - "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b", - "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb", - "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a", - "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920", - "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e", - "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544", - "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45", - "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390", - "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77", - "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355", - "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff", - "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4", - "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7", - "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20", - "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c", - "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162", - "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228", - "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437", - "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc", - "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a", - "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901", - "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4", - "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770", - "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525", - "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad", - "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a", - "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29", - "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90", - "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250", - "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d", - "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3", - "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54", - "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f", - "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1", - "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da", - "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238", - "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa", - "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523", - "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0", - "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205", - "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3", - "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4", - "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac", - "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9", - "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb", - "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced", - "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd", - "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0", - "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da", - "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18", - "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9", - "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276", - "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333", - "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b", - "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db", - "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126", - "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9", - "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09", - "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0", - "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec", - "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7", - "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff", - "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9", - "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192", - "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8", - "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d", - "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6", - "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797", - "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892", - "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f" + "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a", + "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95", + "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5", + "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0", + "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d", + "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18", + "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b", + "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258", + "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95", + "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e", + "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383", + "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02", + "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b", + "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523", + "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee", + "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88", + "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd", + "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb", + "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4", + "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e", + "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c", + "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935", + "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee", + "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e", + "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038", + "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d", + "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b", + "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5", + "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107", + "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f", + "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2", + "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17", + "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb", + "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674", + "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706", + "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327", + "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3", + "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a", + "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2", + "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f", + "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948", + "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3", + "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e", + "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545", + "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc", + "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f", + "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650", + "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a", + "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8", + "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750", + "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b", + "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34", + "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225", + "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51", + "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c", + "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3", + "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde", + "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599", + "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c", + "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76", + "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6", + "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39", + "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9", + "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933", + "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad", + "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520", + "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1", + "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503", + "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b", + "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36", + "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a", + "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643", + "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60", + "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483", + "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf", + "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d", + "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6", + "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644", + "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2", + "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9", + "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2", + "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640", + "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade", + "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a", + "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c", + "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6", + "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00", + "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27", + "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2", + "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4", + "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379", + "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54", + "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09", + "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a", + "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c", + "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89", + "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407", + "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904", + "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376", + "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583", + "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278", + "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a", + "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d", + "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935", + "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb", + "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895", + "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b", + "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417", + "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608", + "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07", + "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05", + "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a", + "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d", + "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052" ], - "markers": "python_version >= '3.7'", - "version": "==1.4.5" + "markers": "python_version >= '3.8'", + "version": "==1.4.7" }, "markdown-it-py": { "hashes": [ @@ -1172,45 +1264,45 @@ }, "more-itertools": { "hashes": [ - "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463", - "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320" + "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", + "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6" ], "markers": "python_version >= '3.8'", - "version": "==10.3.0" + "version": "==10.5.0" }, "mypy": { "hashes": [ - "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6", - "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d", - "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02", - "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d", - "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3", - "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3", - "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", - "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66", - "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259", - "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", - "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd", - "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", - "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8", - "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", - "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b", - "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e", - "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6", - "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", - "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9", - "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", - "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a", - "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592", - "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218", - "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", - "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4", - "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410", - "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" + "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", + "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095", + "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac", + "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6", + "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", + "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", + "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00", + "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", + "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7", + "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13", + "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be", + "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", + "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850", + "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287", + "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", + "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229", + "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", + "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c", + "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac", + "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", + "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", + "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", + "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9", + "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", + "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf", + "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe", + "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.8.0" + "version": "==1.11.0" }, "mypy-extensions": { "hashes": [ @@ -1222,24 +1314,24 @@ }, "nh3": { "hashes": [ - "sha256:0316c25b76289cf23be6b66c77d3608a4fdf537b35426280032f432f14291b9a", - "sha256:1a814dd7bba1cb0aba5bcb9bebcc88fd801b63e21e2450ae6c52d3b3336bc911", - "sha256:1aa52a7def528297f256de0844e8dd680ee279e79583c76d6fa73a978186ddfb", - "sha256:22c26e20acbb253a5bdd33d432a326d18508a910e4dcf9a3316179860d53345a", - "sha256:40015514022af31975c0b3bca4014634fa13cb5dc4dbcbc00570acc781316dcc", - "sha256:40d0741a19c3d645e54efba71cb0d8c475b59135c1e3c580f879ad5514cbf028", - "sha256:551672fd71d06cd828e282abdb810d1be24e1abb7ae2543a8fa36a71c1006fe9", - "sha256:66f17d78826096291bd264f260213d2b3905e3c7fae6dfc5337d49429f1dc9f3", - "sha256:85cdbcca8ef10733bd31f931956f7fbb85145a4d11ab9e6742bbf44d88b7e351", - "sha256:a3f55fabe29164ba6026b5ad5c3151c314d136fd67415a17660b4aaddacf1b10", - "sha256:b4427ef0d2dfdec10b641ed0bdaf17957eb625b2ec0ea9329b3d28806c153d71", - "sha256:ba73a2f8d3a1b966e9cdba7b211779ad8a2561d2dba9674b8a19ed817923f65f", - "sha256:c21bac1a7245cbd88c0b0e4a420221b7bfa838a2814ee5bb924e9c2f10a1120b", - "sha256:c551eb2a3876e8ff2ac63dff1585236ed5dfec5ffd82216a7a174f7c5082a78a", - "sha256:c790769152308421283679a142dbdb3d1c46c79c823008ecea8e8141db1a2062", - "sha256:d7a25fd8c86657f5d9d576268e3b3767c5cd4f42867c9383618be8517f0f022a" - ], - "version": "==0.2.17" + "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164", + "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86", + "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b", + "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad", + "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204", + "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a", + "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200", + "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189", + "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f", + "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811", + "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844", + "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4", + "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be", + "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50", + "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307", + "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe" + ], + "version": "==0.2.18" }, "numpy": { "hashes": [ @@ -1275,19 +1367,14 @@ "index": "pypi", "version": "==0.9.1" }, - "opentrons-shared-data": { - "editable": true, - "markers": "python_version >= '3.10'", - "path": "../shared-data/python" - }, "packaging": { "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3", + "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3" ], "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==21.3" + "markers": "python_version >= '3.7'", + "version": "==22.0" }, "pathspec": { "hashes": [ @@ -1297,84 +1384,91 @@ "markers": "python_version >= '3.8'", "version": "==0.12.1" }, - "performance-metrics": { - "editable": true, - "file": "../performance-metrics" - }, "pillow": { "hashes": [ - "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c", - "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2", - "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb", - "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d", - "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa", - "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3", - "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1", - "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a", - "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd", - "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8", - "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999", - "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599", - "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936", - "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375", - "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d", - "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b", - "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60", - "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572", - "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3", - "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced", - "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f", - "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b", - "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19", - "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f", - "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d", - "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383", - "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795", - "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355", - "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57", - "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09", - "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b", - "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462", - "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf", - "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f", - "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a", - "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad", - "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9", - "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d", - "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45", - "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994", - "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d", - "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338", - "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463", - "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451", - "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591", - "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c", - "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd", - "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32", - "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9", - "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf", - "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5", - "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828", - "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3", - "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5", - "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2", - "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b", - "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2", - "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475", - "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3", - "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb", - "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef", - "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015", - "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002", - "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170", - "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84", - "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57", - "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f", - "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27", - "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a" + "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", + "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", + "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df", + "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", + "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c", + "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d", + "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd", + "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", + "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908", + "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", + "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be", + "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0", + "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b", + "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80", + "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a", + "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e", + "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9", + "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696", + "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b", + "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309", + "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", + "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab", + "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", + "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", + "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d", + "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", + "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", + "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3", + "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6", + "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb", + "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94", + "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", + "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496", + "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0", + "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319", + "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b", + "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", + "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef", + "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680", + "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b", + "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", + "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", + "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597", + "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", + "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8", + "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3", + "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736", + "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", + "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126", + "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd", + "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5", + "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b", + "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", + "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b", + "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", + "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", + "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2", + "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c", + "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe", + "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", + "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a", + "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70", + "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca", + "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b", + "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91", + "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3", + "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84", + "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1", + "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", + "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be", + "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", + "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc", + "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", + "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e", + "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", + "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef", + "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22", + "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27", + "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", + "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1" ], "markers": "python_version >= '3.8'", - "version": "==10.3.0" + "version": "==10.4.0" }, "pkginfo": { "hashes": [ @@ -1416,49 +1510,6 @@ "markers": "python_version >= '3.8'", "version": "==2.11.1" }, - "pydantic": { - "hashes": [ - "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303", - "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe", - "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47", - "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494", - "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33", - "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86", - "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d", - "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c", - "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a", - "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565", - "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb", - "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62", - "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62", - "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0", - "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523", - "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d", - "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405", - "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f", - "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b", - "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718", - "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed", - "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb", - "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5", - "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc", - "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942", - "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe", - "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246", - "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350", - "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303", - "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09", - "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33", - "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8", - "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a", - "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1", - "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6", - "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.10.12" - }, "pydocstyle": { "hashes": [ "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", @@ -1485,49 +1536,11 @@ }, "pyparsing": { "hashes": [ - "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad", - "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742" + "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c", + "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032" ], "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.2" - }, - "pyrsistent": { - "hashes": [ - "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", - "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", - "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", - "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", - "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca", - "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", - "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", - "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", - "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714", - "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf", - "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", - "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", - "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", - "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d", - "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054", - "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", - "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", - "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423", - "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", - "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", - "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", - "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0", - "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", - "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", - "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce", - "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", - "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", - "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86", - "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f", - "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", - "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98", - "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022" - ], - "markers": "python_version >= '3.8'", - "version": "==0.20.0" + "version": "==3.1.4" }, "pytest": { "hashes": [ @@ -1540,12 +1553,12 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b", - "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268" + "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", + "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.23.7" + "version": "==0.23.8" }, "pytest-cov": { "hashes": [ @@ -1596,7 +1609,7 @@ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.9.0.post0" }, "readme-renderer": { @@ -1633,18 +1646,18 @@ }, "rich": { "hashes": [ - "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", - "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432" + "sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc", + "sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4" ], "markers": "python_full_version >= '3.7.0'", - "version": "==13.7.1" + "version": "==13.8.0" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "snowballstemmer": { @@ -1695,27 +1708,27 @@ }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619", - "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4" + "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", + "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5" ], "markers": "python_version >= '3.9'", - "version": "==1.0.8" + "version": "==2.0.0" }, "sphinxcontrib-devhelp": { "hashes": [ - "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f", - "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3" + "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", + "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2" ], "markers": "python_version >= '3.9'", - "version": "==1.0.6" + "version": "==2.0.0" }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015", - "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04" + "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", + "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9" ], "markers": "python_version >= '3.9'", - "version": "==2.0.5" + "version": "==2.1.0" }, "sphinxcontrib-jsmath": { "hashes": [ @@ -1727,19 +1740,19 @@ }, "sphinxcontrib-qthelp": { "hashes": [ - "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6", - "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182" + "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", + "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb" ], "markers": "python_version >= '3.9'", - "version": "==1.0.7" + "version": "==2.0.0" }, "sphinxcontrib-serializinghtml": { "hashes": [ - "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7", - "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f" + "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", + "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d" ], "markers": "python_version >= '3.9'", - "version": "==1.1.10" + "version": "==2.0.0" }, "sphinxext-opengraph": { "hashes": [ @@ -1798,7 +1811,7 @@ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version >= '3.8'", + "markers": "python_version < '3.13'", "version": "==4.12.2" }, "urllib3": { @@ -1820,11 +1833,11 @@ }, "zipp": { "hashes": [ - "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19", - "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c" + "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064", + "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b" ], "markers": "python_version >= '3.8'", - "version": "==3.19.2" + "version": "==3.20.1" } } } diff --git a/api/setup.py b/api/setup.py index 92f06b49bef..a85fc83f114 100755 --- a/api/setup.py +++ b/api/setup.py @@ -59,9 +59,11 @@ def get_version(): f"opentrons-shared-data=={VERSION}", "aionotify==0.3.1", "anyio>=3.6.1,<4.0.0", + # todo(mm, 2024-12-14): investigate ref resolution problems caused by jsonschema>=4.18.1. "jsonschema>=3.0.1,<4.18.0", "numpy>=1.20.0,<2", - "pydantic>=1.10.9,<2.0.0", + "pydantic>=2.0.0,<3", + "pydantic-settings>=2,<3", "pyserial>=3.5", "typing-extensions>=4.0.0,<5", "click>=8.0.0,<9", diff --git a/api/src/opentrons/calibration_storage/deck_configuration.py b/api/src/opentrons/calibration_storage/deck_configuration.py index a627fce73c9..5c97ab37f25 100644 --- a/api/src/opentrons/calibration_storage/deck_configuration.py +++ b/api/src/opentrons/calibration_storage/deck_configuration.py @@ -10,7 +10,7 @@ class _CutoutFixturePlacementModel(pydantic.BaseModel): cutoutId: str cutoutFixtureId: str - opentronsModuleSerialNumber: Optional[str] + opentronsModuleSerialNumber: Optional[str] = None class _DeckConfigurationModel(pydantic.BaseModel): diff --git a/api/src/opentrons/calibration_storage/file_operators.py b/api/src/opentrons/calibration_storage/file_operators.py index 70c16297ecd..ddc046fd828 100644 --- a/api/src/opentrons/calibration_storage/file_operators.py +++ b/api/src/opentrons/calibration_storage/file_operators.py @@ -133,7 +133,7 @@ def deserialize_pydantic_model( Returns `None` if the file is missing or corrupt. """ try: - return model.parse_raw(serialized) + return model.model_validate_json(serialized) except json.JSONDecodeError: _log.warning("Data is not valid JSON.", exc_info=True) return None diff --git a/api/src/opentrons/calibration_storage/helpers.py b/api/src/opentrons/calibration_storage/helpers.py index 1d271add9dd..db11dac3453 100644 --- a/api/src/opentrons/calibration_storage/helpers.py +++ b/api/src/opentrons/calibration_storage/helpers.py @@ -31,7 +31,9 @@ def convert_to_dict(obj: Any) -> Dict[str, Any]: # https://github.com/python/mypy/issues/6568 # Unfortunately, since it's not currently supported I have an # assert check instead. - assert is_dataclass(obj), "This function is intended for dataclasses only" + assert is_dataclass(obj) and not isinstance( + obj, type + ), "This function is intended for dataclasses only" return asdict(obj, dict_factory=dict_filter_none) diff --git a/api/src/opentrons/calibration_storage/ot2/models/v1.py b/api/src/opentrons/calibration_storage/ot2/models/v1.py index 922922415c8..23836e67c98 100644 --- a/api/src/opentrons/calibration_storage/ot2/models/v1.py +++ b/api/src/opentrons/calibration_storage/ot2/models/v1.py @@ -1,7 +1,7 @@ import typing from typing_extensions import Literal -from pydantic import BaseModel, Field, validator +from pydantic import field_validator, BaseModel, Field, PlainSerializer from datetime import datetime from opentrons_shared_data.pipette.types import LabwareUri @@ -9,11 +9,16 @@ from opentrons.types import Point from opentrons.calibration_storage import types +DatetimeType = typing.Annotated[ + datetime, + PlainSerializer(lambda x: x.isoformat(), when_used="json"), +] + class CalibrationStatus(BaseModel): markedBad: bool = False source: typing.Optional[types.SourceType] = None - markedAt: typing.Optional[datetime] = None + markedAt: typing.Optional[DatetimeType] = None # Schemas used to store the data types @@ -22,7 +27,7 @@ class CalibrationStatus(BaseModel): # they are currently saved in on the OT-2 to avoid a large migration. class TipLengthModel(BaseModel): tipLength: float = Field(..., description="Tip length data found from calibration.") - lastModified: datetime = Field( + lastModified: DatetimeType = Field( ..., description="The last time this tip length was calibrated." ) source: types.SourceType = Field( @@ -40,22 +45,19 @@ class TipLengthModel(BaseModel): ..., description="The tiprack hash associated with the tip length data." ) - @validator("tipLength") + @field_validator("tipLength") + @classmethod def ensure_tip_length_positive(cls, tipLength: float) -> float: if tipLength < 0.0: raise ValueError("Tip Length must be a positive number") return tipLength - class Config: - json_encoders = {datetime: lambda obj: obj.isoformat()} - json_decoders = {datetime: lambda obj: datetime.fromisoformat(obj)} - class DeckCalibrationModel(BaseModel): attitude: types.AttitudeMatrix = Field( ..., description="Attitude matrix for deck found from calibration." ) - last_modified: typing.Optional[datetime] = Field( + last_modified: typing.Optional[DatetimeType] = Field( default=None, description="The last time this deck was calibrated." ) source: types.SourceType = Field( @@ -72,10 +74,6 @@ class DeckCalibrationModel(BaseModel): description="The status of the calibration data.", ) - class Config: - json_encoders = {datetime: lambda obj: obj.isoformat()} - json_decoders = {datetime: lambda obj: datetime.fromisoformat(obj)} - class InstrumentOffsetModel(BaseModel): offset: Point = Field(..., description="Instrument offset found from calibration.") @@ -83,7 +81,7 @@ class InstrumentOffsetModel(BaseModel): uri: str = Field( ..., description="The URI of the labware used for instrument offset" ) - last_modified: datetime = Field( + last_modified: DatetimeType = Field( ..., description="The last time this instrument was calibrated." ) source: types.SourceType = Field( @@ -94,10 +92,6 @@ class InstrumentOffsetModel(BaseModel): description="The status of the calibration data.", ) - class Config: - json_encoders = {datetime: lambda obj: obj.isoformat()} - json_decoders = {datetime: lambda obj: datetime.fromisoformat(obj)} - # TODO(lc 09-19-2022) We need to refactor the calibration endpoints # so that we only need to use one data model schema. This model is a @@ -112,7 +106,7 @@ class PipetteOffsetCalibration(BaseModel): uri: str = Field( ..., description="The URI of the labware used for instrument offset" ) - last_modified: datetime = Field( + last_modified: DatetimeType = Field( ..., description="The last time this instrument was calibrated." ) source: types.SourceType = Field( @@ -123,10 +117,6 @@ class PipetteOffsetCalibration(BaseModel): description="The status of the calibration data.", ) - class Config: - json_encoders = {datetime: lambda obj: obj.isoformat()} - json_decoders = {datetime: lambda obj: datetime.fromisoformat(obj)} - # TODO(lc 09-19-2022) We need to refactor the calibration endpoints # so that we only need to use one data model schema. This model is a @@ -137,7 +127,7 @@ class TipLengthCalibration(BaseModel): ..., description="The tiprack hash associated with this tip length data." ) tipLength: float = Field(..., description="Tip length data found from calibration.") - lastModified: datetime = Field( + lastModified: DatetimeType = Field( ..., description="The last time this tip length was calibrated." ) source: types.SourceType = Field( @@ -151,12 +141,9 @@ class TipLengthCalibration(BaseModel): ..., description="The tiprack URI associated with the tip length data." ) - @validator("tipLength") + @field_validator("tipLength") + @classmethod def ensure_tip_length_positive(cls, tipLength: float) -> float: if tipLength < 0.0: raise ValueError("Tip Length must be a positive number") return tipLength - - class Config: - json_encoders = {datetime: lambda obj: obj.isoformat()} - json_decoders = {datetime: lambda obj: datetime.fromisoformat(obj)} diff --git a/api/src/opentrons/calibration_storage/ot2/tip_length.py b/api/src/opentrons/calibration_storage/ot2/tip_length.py index a0bcdcabf9d..a63472c9cea 100644 --- a/api/src/opentrons/calibration_storage/ot2/tip_length.py +++ b/api/src/opentrons/calibration_storage/ot2/tip_length.py @@ -24,8 +24,9 @@ def _convert_tip_length_model_to_dict( - to_dict: typing.Dict[LabwareUri, v1.TipLengthModel] + to_dict: typing.Dict[LabwareUri, v1.TipLengthModel], ) -> typing.Dict[LabwareUri, typing.Any]: + # TODO[pydantic]: supported in Pydantic V2 # This is a workaround since pydantic doesn't have a nice way to # add encoders when converting to a dict. dict_of_tip_lengths = {} diff --git a/api/src/opentrons/calibration_storage/ot3/models/v1.py b/api/src/opentrons/calibration_storage/ot3/models/v1.py index 55e028465c7..b895eac4c89 100644 --- a/api/src/opentrons/calibration_storage/ot3/models/v1.py +++ b/api/src/opentrons/calibration_storage/ot3/models/v1.py @@ -3,7 +3,7 @@ from typing_extensions import Literal from opentrons.hardware_control.modules.types import ModuleType from opentrons.hardware_control.types import OT3Mount -from pydantic import BaseModel, Field, validator +from pydantic import field_validator, BaseModel, Field, PlainSerializer from datetime import datetime from opentrons_shared_data.pipette.types import LabwareUri @@ -12,15 +12,21 @@ from opentrons.calibration_storage import types +DatetimeType = typing.Annotated[ + datetime, + PlainSerializer(lambda x: x.isoformat(), when_used="json"), +] + + class CalibrationStatus(BaseModel): markedBad: bool = False source: typing.Optional[types.SourceType] = None - markedAt: typing.Optional[datetime] = None + markedAt: typing.Optional[DatetimeType] = None class TipLengthModel(BaseModel): tipLength: float = Field(..., description="Tip length data found from calibration.") - lastModified: datetime = Field( + lastModified: DatetimeType = Field( ..., description="The last time this tip length was calibrated." ) uri: typing.Union[LabwareUri, Literal[""]] = Field( @@ -34,22 +40,19 @@ class TipLengthModel(BaseModel): description="The status of the calibration data.", ) - @validator("tipLength") + @field_validator("tipLength") + @classmethod def ensure_tip_length_positive(cls, tipLength: float) -> float: if tipLength < 0.0: raise ValueError("Tip Length must be a positive number") return tipLength - class Config: - json_encoders = {datetime: lambda obj: obj.isoformat()} - json_decoders = {datetime: lambda obj: datetime.fromisoformat(obj)} - class BeltCalibrationModel(BaseModel): attitude: types.AttitudeMatrix = Field( ..., description="Attitude matrix for belts found from calibration." ) - lastModified: datetime = Field( + lastModified: DatetimeType = Field( ..., description="The last time this deck was calibrated." ) source: types.SourceType = Field( @@ -63,14 +66,10 @@ class BeltCalibrationModel(BaseModel): description="The status of the calibration data.", ) - class Config: - json_encoders = {datetime: lambda obj: obj.isoformat()} - json_decoders = {datetime: lambda obj: datetime.fromisoformat(obj)} - class InstrumentOffsetModel(BaseModel): offset: Point = Field(..., description="Instrument offset found from calibration.") - lastModified: datetime = Field( + lastModified: DatetimeType = Field( ..., description="The last time this instrument was calibrated." ) source: types.SourceType = Field( @@ -81,10 +80,6 @@ class InstrumentOffsetModel(BaseModel): description="The status of the calibration data.", ) - class Config: - json_encoders = {datetime: lambda obj: obj.isoformat()} - json_decoders = {datetime: lambda obj: datetime.fromisoformat(obj)} - class ModuleOffsetModel(BaseModel): offset: Point = Field(..., description="Module offset found from calibration.") @@ -99,7 +94,7 @@ class ModuleOffsetModel(BaseModel): ..., description="The unique id of the instrument used to calibrate this module.", ) - lastModified: datetime = Field( + lastModified: DatetimeType = Field( ..., description="The last time this module was calibrated." ) source: types.SourceType = Field( @@ -109,7 +104,3 @@ class ModuleOffsetModel(BaseModel): default_factory=CalibrationStatus, description="The status of the calibration data.", ) - - class Config: - json_encoders = {datetime: lambda obj: obj.isoformat()} - json_decoders = {datetime: lambda obj: datetime.fromisoformat(obj)} diff --git a/api/src/opentrons/cli/analyze.py b/api/src/opentrons/cli/analyze.py index e98f3e807d7..1ce161a96a7 100644 --- a/api/src/opentrons/cli/analyze.py +++ b/api/src/opentrons/cli/analyze.py @@ -382,16 +382,20 @@ async def _analyze( else: result = AnalysisResult.OK - results = AnalyzeResults.construct( + results = AnalyzeResults.model_construct( createdAt=datetime.now(tz=timezone.utc), files=[ - ProtocolFile.construct(name=f.path.name, role=f.role) + ProtocolFile.model_construct(name=f.path.name, role=f.role) for f in protocol_source.files ], config=( - JsonConfig.construct(schemaVersion=protocol_source.config.schema_version) + JsonConfig.model_construct( + schemaVersion=protocol_source.config.schema_version + ) if isinstance(protocol_source.config, JsonProtocolConfig) - else PythonConfig.construct(apiVersion=protocol_source.config.api_version) + else PythonConfig.model_construct( + apiVersion=protocol_source.config.api_version + ) ), result=result, metadata=protocol_source.metadata, @@ -411,14 +415,14 @@ async def _analyze( "json", outputs, lambda to_file: to_file.write( - results.json(exclude_none=True).encode("utf-8"), + results.model_dump_json(exclude_none=True).encode("utf-8"), ), ) _call_for_output_of_kind( "human-json", outputs, lambda to_file: to_file.write( - results.json(exclude_none=True, indent=2).encode("utf-8") + results.model_dump_json(exclude_none=True, indent=2).encode("utf-8") ), ) if check: diff --git a/api/src/opentrons/hardware_control/__init__.py b/api/src/opentrons/hardware_control/__init__.py index d575a2eada5..b49f1462249 100644 --- a/api/src/opentrons/hardware_control/__init__.py +++ b/api/src/opentrons/hardware_control/__init__.py @@ -38,8 +38,7 @@ ] HardwareControlAPI = Union[OT2HardwareControlAPI, OT3HardwareControlAPI] -# this type ignore is because of https://github.com/python/mypy/issues/13437 -ThreadManagedHardware = ThreadManager[HardwareControlAPI] # type: ignore[misc] +ThreadManagedHardware = ThreadManager[HardwareControlAPI] SyncHardwareAPI = SynchronousAdapter[HardwareControlAPI] __all__ = [ diff --git a/api/src/opentrons/hardware_control/emulation/settings.py b/api/src/opentrons/hardware_control/emulation/settings.py index 538b0281808..dd4da4dfc54 100644 --- a/api/src/opentrons/hardware_control/emulation/settings.py +++ b/api/src/opentrons/hardware_control/emulation/settings.py @@ -1,7 +1,8 @@ from typing import List from opentrons.hardware_control.emulation.types import ModuleType from opentrons.hardware_control.emulation.util import TEMPERATURE_ROOM -from pydantic import BaseSettings, BaseModel +from pydantic import BaseModel +from pydantic_settings import BaseSettings, SettingsConfigDict class PipetteSettings(BaseModel): @@ -113,8 +114,6 @@ class Settings(BaseSettings): emulator_port=9003, driver_port=9998 ) magdeck_proxy: ProxySettings = ProxySettings(emulator_port=9004, driver_port=9999) - - class Config: - env_prefix = "OT_EMULATOR_" + model_config = SettingsConfigDict(env_prefix="OT_EMULATOR_") module_server: ModuleServerSettings = ModuleServerSettings() diff --git a/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py b/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py index 7bd41e02e74..9da14196d52 100644 --- a/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py +++ b/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py @@ -230,7 +230,7 @@ def get_attached_instrument(self, mount: MountType) -> PipetteDict: result["current_nozzle_map"] = instr.nozzle_manager.current_configuration result["min_volume"] = instr.liquid_class.min_volume result["max_volume"] = instr.liquid_class.max_volume - result["channels"] = instr.channels + result["channels"] = instr._max_channels.value result["has_tip"] = instr.has_tip result["tip_length"] = instr.current_tip_length result["aspirate_speed"] = self.plunger_speed( diff --git a/api/src/opentrons/hardware_control/instruments/ot3/pipette_handler.py b/api/src/opentrons/hardware_control/instruments/ot3/pipette_handler.py index dda5031a8a3..8e4975b3b5b 100644 --- a/api/src/opentrons/hardware_control/instruments/ot3/pipette_handler.py +++ b/api/src/opentrons/hardware_control/instruments/ot3/pipette_handler.py @@ -248,7 +248,7 @@ def get_attached_instrument(self, mount: OT3Mount) -> PipetteDict: result["current_nozzle_map"] = instr.nozzle_manager.current_configuration result["min_volume"] = instr.liquid_class.min_volume result["max_volume"] = instr.liquid_class.max_volume - result["channels"] = instr._max_channels + result["channels"] = instr._max_channels.value result["has_tip"] = instr.has_tip result["tip_length"] = instr.current_tip_length result["aspirate_speed"] = self.plunger_speed( diff --git a/api/src/opentrons/hardware_control/modules/mod_abc.py b/api/src/opentrons/hardware_control/modules/mod_abc.py index b07c6156a88..ebc0da2fa13 100644 --- a/api/src/opentrons/hardware_control/modules/mod_abc.py +++ b/api/src/opentrons/hardware_control/modules/mod_abc.py @@ -2,7 +2,7 @@ import asyncio import logging import re -from typing import ClassVar, Mapping, Optional, TypeVar, cast +from typing import ClassVar, Mapping, Optional, TypeVar from packaging.version import InvalidVersion, parse, Version from opentrons.config import IS_ROBOT, ROBOT_FIRMWARE_DIR from opentrons.drivers.rpi_drivers.types import USBPort @@ -31,7 +31,7 @@ def parse_fw_version(version: str) -> Version: raise InvalidVersion() except InvalidVersion: device_version = parse("v0.0.0") - return cast(Version, device_version) + return device_version class AbstractModule(abc.ABC): diff --git a/api/src/opentrons/protocol_api/core/engine/protocol.py b/api/src/opentrons/protocol_api/core/engine/protocol.py index d43fc9a2058..cf0a8e1dfd7 100644 --- a/api/src/opentrons/protocol_api/core/engine/protocol.py +++ b/api/src/opentrons/protocol_api/core/engine/protocol.py @@ -6,6 +6,7 @@ from opentrons.protocol_engine import commands as cmd from opentrons.protocol_engine.commands import LoadModuleResult + from opentrons_shared_data.deck.types import DeckDefinitionV5, SlotDefV3 from opentrons_shared_data.labware.labware_definition import LabwareDefinition from opentrons_shared_data.labware.types import LabwareDefinition as LabwareDefDict @@ -736,9 +737,7 @@ def define_liquid( _id=liquid.id, name=liquid.displayName, description=liquid.description, - display_color=( - liquid.displayColor.__root__ if liquid.displayColor else None - ), + display_color=(liquid.displayColor.root if liquid.displayColor else None), ) def define_liquid_class(self, name: str) -> LiquidClass: diff --git a/api/src/opentrons/protocol_engine/commands/__init__.py b/api/src/opentrons/protocol_engine/commands/__init__.py index 4774a45c475..b5edda52397 100644 --- a/api/src/opentrons/protocol_engine/commands/__init__.py +++ b/api/src/opentrons/protocol_engine/commands/__init__.py @@ -35,8 +35,10 @@ from .command_unions import ( Command, + CommandAdapter, CommandParams, CommandCreate, + CommandCreateAdapter, CommandResult, CommandType, CommandDefinedErrorData, @@ -365,8 +367,10 @@ __all__ = [ # command type unions "Command", + "CommandAdapter", "CommandParams", "CommandCreate", + "CommandCreateAdapter", "CommandResult", "CommandType", "CommandPrivateResult", diff --git a/api/src/opentrons/protocol_engine/commands/absorbance_reader/initialize.py b/api/src/opentrons/protocol_engine/commands/absorbance_reader/initialize.py index 458225ad1bb..43937c07ab2 100644 --- a/api/src/opentrons/protocol_engine/commands/absorbance_reader/initialize.py +++ b/api/src/opentrons/protocol_engine/commands/absorbance_reader/initialize.py @@ -1,9 +1,10 @@ """Command models to initialize an Absorbance Reader.""" from __future__ import annotations -from typing import List, Optional, Literal, TYPE_CHECKING +from typing import List, Optional, Literal, TYPE_CHECKING, Any from typing_extensions import Type from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from opentrons.drivers.types import ABSMeasurementMode from opentrons.protocol_engine.types import ABSMeasureMode @@ -20,6 +21,10 @@ InitializeCommandType = Literal["absorbanceReader/initialize"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class InitializeParams(BaseModel): """Input parameters to initialize an absorbance reading.""" @@ -28,8 +33,10 @@ class InitializeParams(BaseModel): ..., description="Initialize single or multi measurement mode." ) sampleWavelengths: List[int] = Field(..., description="Sample wavelengths in nm.") - referenceWavelength: Optional[int] = Field( - None, description="Optional reference wavelength in nm." + referenceWavelength: int | SkipJsonSchema[None] = Field( + None, + description="Optional reference wavelength in nm.", + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py b/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py index 556db619cb5..c557028c283 100644 --- a/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py +++ b/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py @@ -1,10 +1,11 @@ """Command models to read absorbance.""" from __future__ import annotations from datetime import datetime -from typing import Optional, Dict, TYPE_CHECKING, List -from typing_extensions import Literal, Type +from typing import Optional, Dict, TYPE_CHECKING, List, Any +from typing_extensions import Literal, Type from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ...errors import CannotPerformModuleAction, StorageLimitReachedError @@ -23,6 +24,10 @@ from opentrons.protocol_engine.execution import EquipmentHandler +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + ReadAbsorbanceCommandType = Literal["absorbanceReader/read"] @@ -30,9 +35,10 @@ class ReadAbsorbanceParams(BaseModel): """Input parameters for an absorbance reading.""" moduleId: str = Field(..., description="Unique ID of the Absorbance Reader.") - fileName: Optional[str] = Field( + fileName: str | SkipJsonSchema[None] = Field( None, description="Optional file name to use when storing the results of a measurement.", + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/aspirate.py b/api/src/opentrons/protocol_engine/commands/aspirate.py index fa84afbde8c..9664d733b8a 100644 --- a/api/src/opentrons/protocol_engine/commands/aspirate.py +++ b/api/src/opentrons/protocol_engine/commands/aspirate.py @@ -226,7 +226,7 @@ class Aspirate( commandType: AspirateCommandType = "aspirate" params: AspirateParams - result: Optional[AspirateResult] + result: Optional[AspirateResult] = None _ImplementationCls: Type[AspirateImplementation] = AspirateImplementation diff --git a/api/src/opentrons/protocol_engine/commands/aspirate_in_place.py b/api/src/opentrons/protocol_engine/commands/aspirate_in_place.py index 1f89c9c5d74..434924928d7 100644 --- a/api/src/opentrons/protocol_engine/commands/aspirate_in_place.py +++ b/api/src/opentrons/protocol_engine/commands/aspirate_in_place.py @@ -165,7 +165,7 @@ class AspirateInPlace( commandType: AspirateInPlaceCommandType = "aspirateInPlace" params: AspirateInPlaceParams - result: Optional[AspirateInPlaceResult] + result: Optional[AspirateInPlaceResult] = None _ImplementationCls: Type[ AspirateInPlaceImplementation diff --git a/api/src/opentrons/protocol_engine/commands/blow_out.py b/api/src/opentrons/protocol_engine/commands/blow_out.py index b2e8765b4a1..07582781a3a 100644 --- a/api/src/opentrons/protocol_engine/commands/blow_out.py +++ b/api/src/opentrons/protocol_engine/commands/blow_out.py @@ -130,7 +130,7 @@ class BlowOut( commandType: BlowOutCommandType = "blowout" params: BlowOutParams - result: Optional[BlowOutResult] + result: Optional[BlowOutResult] = None _ImplementationCls: Type[BlowOutImplementation] = BlowOutImplementation diff --git a/api/src/opentrons/protocol_engine/commands/blow_out_in_place.py b/api/src/opentrons/protocol_engine/commands/blow_out_in_place.py index f5f648bcec8..527c921e499 100644 --- a/api/src/opentrons/protocol_engine/commands/blow_out_in_place.py +++ b/api/src/opentrons/protocol_engine/commands/blow_out_in_place.py @@ -100,7 +100,7 @@ class BlowOutInPlace( commandType: BlowOutInPlaceCommandType = "blowOutInPlace" params: BlowOutInPlaceParams - result: Optional[BlowOutInPlaceResult] + result: Optional[BlowOutInPlaceResult] = None _ImplementationCls: Type[ BlowOutInPlaceImplementation diff --git a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_gripper.py b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_gripper.py index 0333a171077..2dac135c4f5 100644 --- a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +++ b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_gripper.py @@ -1,10 +1,11 @@ """Models and implementation for the calibrateGripper command.""" from enum import Enum -from typing import Optional, Type +from typing import Optional, Type, Any from typing_extensions import Literal from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from opentrons.types import Point from opentrons.hardware_control import HardwareControlAPI @@ -22,6 +23,10 @@ CalibrateGripperCommandType = Literal["calibration/calibrateGripper"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class CalibrateGripperParamsJaw(Enum): # noqa: D101 FRONT = "front" REAR = "rear" @@ -39,7 +44,7 @@ class CalibrateGripperParams(BaseModel): ), ) - otherJawOffset: Optional[Vec3f] = Field( + otherJawOffset: Vec3f | SkipJsonSchema[None] = Field( None, description=( "If an offset for the other probe is already found, then specifying it here" @@ -48,6 +53,7 @@ class CalibrateGripperParams(BaseModel): " If this param is not specified then the command will only find and return" " the offset for the specified probe." ), + json_schema_extra=_remove_default, ) @@ -62,11 +68,12 @@ class CalibrateGripperResult(BaseModel): ), ) - savedCalibration: Optional[GripperCalibrationOffset] = Field( + savedCalibration: GripperCalibrationOffset | SkipJsonSchema[None] = Field( None, description=( "Gripper calibration result data, when `otherJawOffset` is provided." ), + json_schema_extra=_remove_default, ) @@ -143,7 +150,7 @@ class CalibrateGripper( commandType: CalibrateGripperCommandType = "calibration/calibrateGripper" params: CalibrateGripperParams - result: Optional[CalibrateGripperResult] + result: Optional[CalibrateGripperResult] = None _ImplementationCls: Type[ CalibrateGripperImplementation diff --git a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_module.py b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_module.py index f488e8eab97..e203dcc19be 100644 --- a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_module.py +++ b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_module.py @@ -101,7 +101,7 @@ class CalibrateModule( commandType: CalibrateModuleCommandType = "calibration/calibrateModule" params: CalibrateModuleParams - result: Optional[CalibrateModuleResult] + result: Optional[CalibrateModuleResult] = None _ImplementationCls: Type[ CalibrateModuleImplementation diff --git a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_pipette.py b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_pipette.py index fbe754f6389..70daeecb6d6 100644 --- a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +++ b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_pipette.py @@ -80,7 +80,7 @@ class CalibratePipette( commandType: CalibratePipetteCommandType = "calibration/calibratePipette" params: CalibratePipetteParams - result: Optional[CalibratePipetteResult] + result: Optional[CalibratePipetteResult] = None _ImplementationCls: Type[ CalibratePipetteImplementation diff --git a/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py b/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py index afb178cae99..ca18d70a265 100644 --- a/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +++ b/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py @@ -136,7 +136,7 @@ class MoveToMaintenancePosition( "calibration/moveToMaintenancePosition" ) params: MoveToMaintenancePositionParams - result: Optional[MoveToMaintenancePositionResult] + result: Optional[MoveToMaintenancePositionResult] = None _ImplementationCls: Type[ MoveToMaintenancePositionImplementation diff --git a/api/src/opentrons/protocol_engine/commands/command.py b/api/src/opentrons/protocol_engine/commands/command.py index c009f314afb..38d1512905e 100644 --- a/api/src/opentrons/protocol_engine/commands/command.py +++ b/api/src/opentrons/protocol_engine/commands/command.py @@ -14,10 +14,12 @@ List, Type, Union, + Any, + Dict, ) from pydantic import BaseModel, Field -from pydantic.generics import GenericModel +from pydantic.json_schema import SkipJsonSchema from opentrons.hardware_control import HardwareControlAPI from opentrons.protocol_engine.state.update_types import StateUpdate @@ -62,8 +64,12 @@ class CommandIntent(str, enum.Enum): FIXIT = "fixit" +def _pop_default(s: Dict[str, Any]) -> None: + s.pop("default", None) + + class BaseCommandCreate( - GenericModel, + BaseModel, # These type parameters need to be invariant because our fields are mutable. Generic[_ParamsT], ): @@ -81,7 +87,7 @@ class BaseCommandCreate( ), ) params: _ParamsT = Field(..., description="Command execution data payload") - intent: Optional[CommandIntent] = Field( + intent: CommandIntent | SkipJsonSchema[None] = Field( None, description=( "The reason the command was added. If not specified or `protocol`," @@ -94,14 +100,16 @@ class BaseCommandCreate( "Use setup commands for activities like pre-run calibration checks" " and module setup, like pre-heating." ), + json_schema_extra=_pop_default, ) - key: Optional[str] = Field( + key: str | SkipJsonSchema[None] = Field( None, description=( "A key value, unique in this run, that can be used to track" " the same logical command across multiple runs of the same protocol." " If a value is not provided, one will be generated." ), + json_schema_extra=_pop_default, ) @@ -143,8 +151,65 @@ class DefinedErrorData(Generic[_ErrorT_co]): ) +_ExecuteReturnT_co = TypeVar( + "_ExecuteReturnT_co", + bound=Union[ + SuccessData[BaseModel], + DefinedErrorData[ErrorOccurrence], + ], + covariant=True, +) + + +class AbstractCommandImpl( + ABC, + Generic[_ParamsT_contra, _ExecuteReturnT_co], +): + """Abstract command creation and execution implementation. + + A given command request should map to a specific command implementation, + which defines how to execute the command and map data from execution into the + result model. + """ + + def __init__( + self, + state_view: StateView, + hardware_api: HardwareControlAPI, + equipment: execution.EquipmentHandler, + file_provider: execution.FileProvider, + movement: execution.MovementHandler, + gantry_mover: execution.GantryMover, + labware_movement: execution.LabwareMovementHandler, + pipetting: execution.PipettingHandler, + tip_handler: execution.TipHandler, + run_control: execution.RunControlHandler, + rail_lights: execution.RailLightsHandler, + model_utils: ModelUtils, + status_bar: execution.StatusBarHandler, + command_note_adder: CommandNoteAdder, + ) -> None: + """Initialize the command implementation with execution handlers.""" + pass + + @abstractmethod + async def execute(self, params: _ParamsT_contra) -> _ExecuteReturnT_co: + """Execute the command, mapping data from execution into a response model. + + This should either: + + - Return a `SuccessData`, if the command completed normally. + - Return a `DefinedErrorData`, if the command failed with a "defined error." + Defined errors are errors that are documented as part of the robot's public + API. + - Raise an exception, if the command failed with any other error + (in other words, an undefined error). + """ + ... + + class BaseCommand( - GenericModel, + BaseModel, # These type parameters need to be invariant because our fields are mutable. Generic[_ParamsT, _ResultT, _ErrorT], ): @@ -241,60 +306,3 @@ class BaseCommand( ], ] ] - - -_ExecuteReturnT_co = TypeVar( - "_ExecuteReturnT_co", - bound=Union[ - SuccessData[BaseModel], - DefinedErrorData[ErrorOccurrence], - ], - covariant=True, -) - - -class AbstractCommandImpl( - ABC, - Generic[_ParamsT_contra, _ExecuteReturnT_co], -): - """Abstract command creation and execution implementation. - - A given command request should map to a specific command implementation, - which defines how to execute the command and map data from execution into the - result model. - """ - - def __init__( - self, - state_view: StateView, - hardware_api: HardwareControlAPI, - equipment: execution.EquipmentHandler, - file_provider: execution.FileProvider, - movement: execution.MovementHandler, - gantry_mover: execution.GantryMover, - labware_movement: execution.LabwareMovementHandler, - pipetting: execution.PipettingHandler, - tip_handler: execution.TipHandler, - run_control: execution.RunControlHandler, - rail_lights: execution.RailLightsHandler, - model_utils: ModelUtils, - status_bar: execution.StatusBarHandler, - command_note_adder: CommandNoteAdder, - ) -> None: - """Initialize the command implementation with execution handlers.""" - pass - - @abstractmethod - async def execute(self, params: _ParamsT_contra) -> _ExecuteReturnT_co: - """Execute the command, mapping data from execution into a response model. - - This should either: - - - Return a `SuccessData`, if the command completed normally. - - Return a `DefinedErrorData`, if the command failed with a "defined error." - Defined errors are errors that are documented as part of the robot's public - API. - - Raise an exception, if the command failed with any other error - (in other words, an undefined error). - """ - ... diff --git a/api/src/opentrons/protocol_engine/commands/command_unions.py b/api/src/opentrons/protocol_engine/commands/command_unions.py index 16663bf6df6..3f5bb09e510 100644 --- a/api/src/opentrons/protocol_engine/commands/command_unions.py +++ b/api/src/opentrons/protocol_engine/commands/command_unions.py @@ -3,7 +3,7 @@ from collections.abc import Collection from typing import Annotated, Type, Union, get_type_hints -from pydantic import Field +from pydantic import Field, TypeAdapter from opentrons.util.get_union_elements import get_union_elements @@ -686,6 +686,13 @@ Field(discriminator="commandType"), ] +# Each time a TypeAdapter is instantiated, it will construct a new validator and +# serializer. To improve performance, TypeAdapters are instantiated once. +# See https://docs.pydantic.dev/latest/concepts/performance/#typeadapter-instantiated-once +CommandCreateAdapter: TypeAdapter[CommandCreate] = TypeAdapter(CommandCreate) + +CommandAdapter: TypeAdapter[Command] = TypeAdapter(Command) + CommandResult = Union[ AirGapInPlaceResult, AspirateResult, diff --git a/api/src/opentrons/protocol_engine/commands/comment.py b/api/src/opentrons/protocol_engine/commands/comment.py index 5cd0b0c3113..f14a9a9992c 100644 --- a/api/src/opentrons/protocol_engine/commands/comment.py +++ b/api/src/opentrons/protocol_engine/commands/comment.py @@ -43,7 +43,7 @@ class Comment(BaseCommand[CommentParams, CommentResult, ErrorOccurrence]): commandType: CommentCommandType = "comment" params: CommentParams - result: Optional[CommentResult] + result: Optional[CommentResult] = None _ImplementationCls: Type[CommentImplementation] = CommentImplementation diff --git a/api/src/opentrons/protocol_engine/commands/configure_for_volume.py b/api/src/opentrons/protocol_engine/commands/configure_for_volume.py index 1c8aa21f491..50e1e7546bc 100644 --- a/api/src/opentrons/protocol_engine/commands/configure_for_volume.py +++ b/api/src/opentrons/protocol_engine/commands/configure_for_volume.py @@ -1,7 +1,9 @@ """Configure for volume command request, result, and implementation models.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Type, Any + from pydantic import BaseModel, Field -from typing import TYPE_CHECKING, Optional, Type +from pydantic.json_schema import SkipJsonSchema from typing_extensions import Literal from .pipetting_common import PipetteIdMixin @@ -16,6 +18,10 @@ ConfigureForVolumeCommandType = Literal["configureForVolume"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class ConfigureForVolumeParams(PipetteIdMixin): """Parameters required to configure volume for a specific pipette.""" @@ -25,12 +31,13 @@ class ConfigureForVolumeParams(PipetteIdMixin): "than a pipette-specific maximum volume.", ge=0, ) - tipOverlapNotAfterVersion: Optional[str] = Field( + tipOverlapNotAfterVersion: str | SkipJsonSchema[None] = Field( None, description="A version of tip overlap data to not exceed. The highest-versioned " "tip overlap data that does not exceed this version will be used. Versions are " "expressed as vN where N is an integer, counting up from v0. If None, the current " "highest version will be used.", + json_schema_extra=_remove_default, ) @@ -81,7 +88,7 @@ class ConfigureForVolume( commandType: ConfigureForVolumeCommandType = "configureForVolume" params: ConfigureForVolumeParams - result: Optional[ConfigureForVolumeResult] + result: Optional[ConfigureForVolumeResult] = None _ImplementationCls: Type[ ConfigureForVolumeImplementation diff --git a/api/src/opentrons/protocol_engine/commands/configure_nozzle_layout.py b/api/src/opentrons/protocol_engine/commands/configure_nozzle_layout.py index f78839773ec..db06491ab14 100644 --- a/api/src/opentrons/protocol_engine/commands/configure_nozzle_layout.py +++ b/api/src/opentrons/protocol_engine/commands/configure_nozzle_layout.py @@ -97,7 +97,7 @@ class ConfigureNozzleLayout( commandType: ConfigureNozzleLayoutCommandType = "configureNozzleLayout" params: ConfigureNozzleLayoutParams - result: Optional[ConfigureNozzleLayoutResult] + result: Optional[ConfigureNozzleLayoutResult] = None _ImplementationCls: Type[ ConfigureNozzleLayoutImplementation diff --git a/api/src/opentrons/protocol_engine/commands/custom.py b/api/src/opentrons/protocol_engine/commands/custom.py index 1bdf07084be..3190385f2d2 100644 --- a/api/src/opentrons/protocol_engine/commands/custom.py +++ b/api/src/opentrons/protocol_engine/commands/custom.py @@ -10,7 +10,7 @@ If you are implementing a custom command, you should probably put your own disambiguation identifier in the payload. """ -from pydantic import BaseModel, Extra +from pydantic import ConfigDict, BaseModel, SerializeAsAny from typing import Optional, Type from typing_extensions import Literal @@ -24,19 +24,13 @@ class CustomParams(BaseModel): """Payload used by a custom command.""" - class Config: - """Allow arbitrary fields.""" - - extra = Extra.allow + model_config = ConfigDict(extra="allow") class CustomResult(BaseModel): """Result data from a custom command.""" - class Config: - """Allow arbitrary fields.""" - - extra = Extra.allow + model_config = ConfigDict(extra="allow") class CustomImplementation( @@ -58,8 +52,8 @@ class Custom(BaseCommand[CustomParams, CustomResult, ErrorOccurrence]): """Custom command model.""" commandType: CustomCommandType = "custom" - params: CustomParams - result: Optional[CustomResult] + params: SerializeAsAny[CustomParams] + result: Optional[CustomResult] = None _ImplementationCls: Type[CustomImplementation] = CustomImplementation diff --git a/api/src/opentrons/protocol_engine/commands/dispense.py b/api/src/opentrons/protocol_engine/commands/dispense.py index 18f157934d4..8ad2365ccb5 100644 --- a/api/src/opentrons/protocol_engine/commands/dispense.py +++ b/api/src/opentrons/protocol_engine/commands/dispense.py @@ -1,11 +1,12 @@ """Dispense command request, result, and implementation models.""" from __future__ import annotations -from typing import TYPE_CHECKING, Optional, Type, Union +from typing import TYPE_CHECKING, Optional, Type, Union, Any from typing_extensions import Literal from pydantic import Field +from pydantic.json_schema import SkipJsonSchema from ..state.update_types import StateUpdate, CLEAR from .pipetting_common import ( @@ -39,14 +40,19 @@ DispenseCommandType = Literal["dispense"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class DispenseParams( PipetteIdMixin, DispenseVolumeMixin, FlowRateMixin, LiquidHandlingWellLocationMixin ): """Payload required to dispense to a specific well.""" - pushOut: Optional[float] = Field( + pushOut: float | SkipJsonSchema[None] = Field( None, description="push the plunger a small amount farther than necessary for accurate low-volume dispensing", + json_schema_extra=_remove_default, ) @@ -172,7 +178,7 @@ class Dispense( commandType: DispenseCommandType = "dispense" params: DispenseParams - result: Optional[DispenseResult] + result: Optional[DispenseResult] = None _ImplementationCls: Type[DispenseImplementation] = DispenseImplementation diff --git a/api/src/opentrons/protocol_engine/commands/dispense_in_place.py b/api/src/opentrons/protocol_engine/commands/dispense_in_place.py index fc1f9e19610..117aa011a84 100644 --- a/api/src/opentrons/protocol_engine/commands/dispense_in_place.py +++ b/api/src/opentrons/protocol_engine/commands/dispense_in_place.py @@ -1,9 +1,10 @@ """Dispense-in-place command request, result, and implementation models.""" from __future__ import annotations -from typing import TYPE_CHECKING, Optional, Type, Union +from typing import TYPE_CHECKING, Optional, Type, Union, Any from typing_extensions import Literal from pydantic import Field +from pydantic.json_schema import SkipJsonSchema from .pipetting_common import ( PipetteIdMixin, @@ -32,12 +33,17 @@ DispenseInPlaceCommandType = Literal["dispenseInPlace"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class DispenseInPlaceParams(PipetteIdMixin, DispenseVolumeMixin, FlowRateMixin): """Payload required to dispense in place.""" - pushOut: Optional[float] = Field( + pushOut: float | SkipJsonSchema[None] = Field( None, description="push the plunger a small amount farther than necessary for accurate low-volume dispensing", + json_schema_extra=_remove_default, ) @@ -154,7 +160,7 @@ class DispenseInPlace( commandType: DispenseInPlaceCommandType = "dispenseInPlace" params: DispenseInPlaceParams - result: Optional[DispenseInPlaceResult] + result: Optional[DispenseInPlaceResult] = None _ImplementationCls: Type[ DispenseInPlaceImplementation diff --git a/api/src/opentrons/protocol_engine/commands/drop_tip.py b/api/src/opentrons/protocol_engine/commands/drop_tip.py index 4faee3d5e2f..2c393064eb6 100644 --- a/api/src/opentrons/protocol_engine/commands/drop_tip.py +++ b/api/src/opentrons/protocol_engine/commands/drop_tip.py @@ -1,9 +1,11 @@ """Drop tip command request, result, and implementation models.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Type, Any from pydantic import Field -from typing import TYPE_CHECKING, Optional, Type +from pydantic.json_schema import SkipJsonSchema + from typing_extensions import Literal from opentrons.protocol_engine.errors.exceptions import TipAttachedError @@ -37,6 +39,10 @@ DropTipCommandType = Literal["dropTip"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class DropTipParams(PipetteIdMixin): """Payload required to drop a tip in a specific well.""" @@ -46,15 +52,16 @@ class DropTipParams(PipetteIdMixin): default_factory=DropTipWellLocation, description="Relative well location at which to drop the tip.", ) - homeAfter: Optional[bool] = Field( + homeAfter: bool | SkipJsonSchema[None] = Field( None, description=( "Whether to home this pipette's plunger after dropping the tip." " You should normally leave this unspecified to let the robot choose" " a safe default depending on its hardware." ), + json_schema_extra=_remove_default, ) - alternateDropLocation: Optional[bool] = Field( + alternateDropLocation: bool | SkipJsonSchema[None] = Field( False, description=( "Whether to alternate location where tip is dropped within the labware." @@ -63,6 +70,7 @@ class DropTipParams(PipetteIdMixin): " labware well." " If False, the tip will be dropped at the top center of the well." ), + json_schema_extra=_remove_default, ) @@ -184,7 +192,7 @@ class DropTip( commandType: DropTipCommandType = "dropTip" params: DropTipParams - result: Optional[DropTipResult] + result: Optional[DropTipResult] = None _ImplementationCls: Type[DropTipImplementation] = DropTipImplementation diff --git a/api/src/opentrons/protocol_engine/commands/drop_tip_in_place.py b/api/src/opentrons/protocol_engine/commands/drop_tip_in_place.py index 8687382b53f..09bd73b8bb1 100644 --- a/api/src/opentrons/protocol_engine/commands/drop_tip_in_place.py +++ b/api/src/opentrons/protocol_engine/commands/drop_tip_in_place.py @@ -1,7 +1,10 @@ """Drop tip in place command request, result, and implementation models.""" from __future__ import annotations + +from typing import TYPE_CHECKING, Optional, Type, Any + from pydantic import Field, BaseModel -from typing import TYPE_CHECKING, Optional, Type +from pydantic.json_schema import SkipJsonSchema from typing_extensions import Literal from .command import ( @@ -24,16 +27,21 @@ DropTipInPlaceCommandType = Literal["dropTipInPlace"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class DropTipInPlaceParams(PipetteIdMixin): """Payload required to drop a tip in place.""" - homeAfter: Optional[bool] = Field( + homeAfter: bool | SkipJsonSchema[None] = Field( None, description=( "Whether to home this pipette's plunger after dropping the tip." " You should normally leave this unspecified to let the robot choose" " a safe default depending on its hardware." ), + json_schema_extra=_remove_default, ) @@ -112,7 +120,7 @@ class DropTipInPlace( commandType: DropTipInPlaceCommandType = "dropTipInPlace" params: DropTipInPlaceParams - result: Optional[DropTipInPlaceResult] + result: Optional[DropTipInPlaceResult] = None _ImplementationCls: Type[ DropTipInPlaceImplementation diff --git a/api/src/opentrons/protocol_engine/commands/generate_command_schema.py b/api/src/opentrons/protocol_engine/commands/generate_command_schema.py index acc0923bcdf..938244b74e8 100644 --- a/api/src/opentrons/protocol_engine/commands/generate_command_schema.py +++ b/api/src/opentrons/protocol_engine/commands/generate_command_schema.py @@ -1,24 +1,17 @@ """Generate a JSON schema against which all create commands statically validate.""" + import json -import pydantic import argparse import sys -from opentrons.protocol_engine.commands.command_unions import CommandCreate - - -class CreateCommandUnion(pydantic.BaseModel): - """Model that validates a union of all CommandCreate models.""" - - __root__: CommandCreate +from opentrons.protocol_engine.commands.command_unions import CommandCreateAdapter def generate_command_schema(version: str) -> str: """Generate a JSON Schema that all valid create commands can validate against.""" - raw_json_schema = CreateCommandUnion.schema_json() - schema_as_dict = json.loads(raw_json_schema) + schema_as_dict = CommandCreateAdapter.json_schema(mode="validation") schema_as_dict["$id"] = f"opentronsCommandSchemaV{version}" schema_as_dict["$schema"] = "http://json-schema.org/draft-07/schema#" - return json.dumps(schema_as_dict, indent=2) + return json.dumps(schema_as_dict, indent=2, sort_keys=True) if __name__ == "__main__": diff --git a/api/src/opentrons/protocol_engine/commands/get_next_tip.py b/api/src/opentrons/protocol_engine/commands/get_next_tip.py index 7ff10681bfb..f9f2cb8ba61 100644 --- a/api/src/opentrons/protocol_engine/commands/get_next_tip.py +++ b/api/src/opentrons/protocol_engine/commands/get_next_tip.py @@ -2,7 +2,9 @@ from __future__ import annotations from pydantic import BaseModel, Field -from typing import TYPE_CHECKING, Optional, Type, List, Literal, Union +from typing import TYPE_CHECKING, Any, Optional, Type, List, Literal, Union + +from pydantic.json_schema import SkipJsonSchema from opentrons.types import NozzleConfigurationType @@ -21,6 +23,10 @@ from ..state.state import StateView +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + GetNextTipCommandType = Literal["getNextTip"] @@ -32,10 +38,11 @@ class GetNextTipParams(PipetteIdMixin): description="Labware ID(s) of tip racks to resolve next available tip(s) from" " Labware IDs will be resolved sequentially", ) - startingTipWell: Optional[str] = Field( + startingTipWell: str | SkipJsonSchema[None] = Field( None, description="Name of starting tip rack 'well'." " This only applies to the first tip rack in the list provided in labwareIDs", + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/get_tip_presence.py b/api/src/opentrons/protocol_engine/commands/get_tip_presence.py index 6bbe5fa2fe3..05f9e1052c1 100644 --- a/api/src/opentrons/protocol_engine/commands/get_tip_presence.py +++ b/api/src/opentrons/protocol_engine/commands/get_tip_presence.py @@ -71,7 +71,7 @@ class GetTipPresence( commandType: GetTipPresenceCommandType = "getTipPresence" params: GetTipPresenceParams - result: Optional[GetTipPresenceResult] + result: Optional[GetTipPresenceResult] = None _ImplementationCls: Type[ GetTipPresenceImplementation diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py index 2151fb05877..211b374be7e 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py @@ -69,7 +69,7 @@ class CloseLabwareLatch( commandType: CloseLabwareLatchCommandType = "heaterShaker/closeLabwareLatch" params: CloseLabwareLatchParams - result: Optional[CloseLabwareLatchResult] + result: Optional[CloseLabwareLatchResult] = None _ImplementationCls: Type[CloseLabwareLatchImpl] = CloseLabwareLatchImpl diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py index 3932f1d6490..6ac76f020d3 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py @@ -68,7 +68,7 @@ class DeactivateHeater( commandType: DeactivateHeaterCommandType = "heaterShaker/deactivateHeater" params: DeactivateHeaterParams - result: Optional[DeactivateHeaterResult] + result: Optional[DeactivateHeaterResult] = None _ImplementationCls: Type[DeactivateHeaterImpl] = DeactivateHeaterImpl diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py index b259745ea3d..e7e50b07fee 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py @@ -70,7 +70,7 @@ class DeactivateShaker( commandType: DeactivateShakerCommandType = "heaterShaker/deactivateShaker" params: DeactivateShakerParams - result: Optional[DeactivateShakerResult] + result: Optional[DeactivateShakerResult] = None _ImplementationCls: Type[DeactivateShakerImpl] = DeactivateShakerImpl diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py index 9c3a9d8ae7d..8bb869c47ee 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py @@ -96,7 +96,7 @@ class OpenLabwareLatch( commandType: OpenLabwareLatchCommandType = "heaterShaker/openLabwareLatch" params: OpenLabwareLatchParams - result: Optional[OpenLabwareLatchResult] + result: Optional[OpenLabwareLatchResult] = None _ImplementationCls: Type[OpenLabwareLatchImpl] = OpenLabwareLatchImpl diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py index 8828195c658..2bcf1d48ba3 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py @@ -109,7 +109,7 @@ class SetAndWaitForShakeSpeed( "heaterShaker/setAndWaitForShakeSpeed" ) params: SetAndWaitForShakeSpeedParams - result: Optional[SetAndWaitForShakeSpeedResult] + result: Optional[SetAndWaitForShakeSpeedResult] = None _ImplementationCls: Type[SetAndWaitForShakeSpeedImpl] = SetAndWaitForShakeSpeedImpl diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py index fa29390b910..f0b0533aca3 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py @@ -76,7 +76,7 @@ class SetTargetTemperature( commandType: SetTargetTemperatureCommandType = "heaterShaker/setTargetTemperature" params: SetTargetTemperatureParams - result: Optional[SetTargetTemperatureResult] + result: Optional[SetTargetTemperatureResult] = None _ImplementationCls: Type[SetTargetTemperatureImpl] = SetTargetTemperatureImpl diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py index bb440a2674c..676fbcd4bfb 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py @@ -1,9 +1,10 @@ """Command models to wait for a Heater-Shaker Module's target temperature.""" from __future__ import annotations -from typing import Optional, TYPE_CHECKING -from typing_extensions import Literal, Type +from typing import Optional, TYPE_CHECKING, Any +from typing_extensions import Literal, Type from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ...errors.error_occurrence import ErrorOccurrence @@ -16,11 +17,15 @@ WaitForTemperatureCommandType = Literal["heaterShaker/waitForTemperature"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class WaitForTemperatureParams(BaseModel): """Input parameters to wait for a Heater-Shaker's target temperature.""" moduleId: str = Field(..., description="Unique ID of the Heater-Shaker Module.") - celsius: Optional[float] = Field( + celsius: float | SkipJsonSchema[None] = Field( None, description="Target temperature in °C. If not specified, will " "default to the module's target temperature. " @@ -28,6 +33,7 @@ class WaitForTemperatureParams(BaseModel): "could lead to unpredictable behavior and hence is not " "recommended for use. This parameter can be removed in a " "future version without prior notice.", + json_schema_extra=_remove_default, ) @@ -82,7 +88,7 @@ class WaitForTemperature( commandType: WaitForTemperatureCommandType = "heaterShaker/waitForTemperature" params: WaitForTemperatureParams - result: Optional[WaitForTemperatureResult] + result: Optional[WaitForTemperatureResult] = None _ImplementationCls: Type[WaitForTemperatureImpl] = WaitForTemperatureImpl diff --git a/api/src/opentrons/protocol_engine/commands/home.py b/api/src/opentrons/protocol_engine/commands/home.py index 7b82f90e1fd..f096740958f 100644 --- a/api/src/opentrons/protocol_engine/commands/home.py +++ b/api/src/opentrons/protocol_engine/commands/home.py @@ -1,7 +1,10 @@ """Home command payload, result, and implementation models.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, List, Type, Any + from pydantic import BaseModel, Field -from typing import TYPE_CHECKING, Optional, List, Type +from pydantic.json_schema import SkipJsonSchema + from typing_extensions import Literal from opentrons.types import MountType @@ -17,24 +20,30 @@ HomeCommandType = Literal["home"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class HomeParams(BaseModel): """Payload required for a Home command.""" - axes: Optional[List[MotorAxis]] = Field( + axes: List[MotorAxis] | SkipJsonSchema[None] = Field( None, description=( "Axes to return to their home positions. If omitted," " will home all motors. Extra axes may be implicitly homed" " to ensure accurate homing of the explicitly specified axes." ), + json_schema_extra=_remove_default, ) - skipIfMountPositionOk: Optional[MountType] = Field( + skipIfMountPositionOk: MountType | SkipJsonSchema[None] = Field( None, description=( "If this parameter is provided, the gantry will only be homed if the" " specified mount has an invalid position. If omitted, the homing action" " will be executed unconditionally." ), + json_schema_extra=_remove_default, ) @@ -77,7 +86,7 @@ class Home(BaseCommand[HomeParams, HomeResult, ErrorOccurrence]): commandType: HomeCommandType = "home" params: HomeParams - result: Optional[HomeResult] + result: Optional[HomeResult] = None _ImplementationCls: Type[HomeImplementation] = HomeImplementation diff --git a/api/src/opentrons/protocol_engine/commands/liquid_probe.py b/api/src/opentrons/protocol_engine/commands/liquid_probe.py index 1bf58e8be26..a0418d53c9a 100644 --- a/api/src/opentrons/protocol_engine/commands/liquid_probe.py +++ b/api/src/opentrons/protocol_engine/commands/liquid_probe.py @@ -1,10 +1,11 @@ """The liquidProbe and tryLiquidProbe commands.""" from __future__ import annotations -from typing import TYPE_CHECKING, NamedTuple, Optional, Type, Union -from typing_extensions import Literal +from typing import TYPE_CHECKING, NamedTuple, Optional, Type, Union, Any +from typing_extensions import Literal from pydantic import Field +from pydantic.json_schema import SkipJsonSchema from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.errors.exceptions import ( @@ -47,6 +48,10 @@ from ..state.state import StateView +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + LiquidProbeCommandType = Literal["liquidProbe"] TryLiquidProbeCommandType = Literal["tryLiquidProbe"] @@ -82,12 +87,13 @@ class LiquidProbeResult(DestinationPositionResult): class TryLiquidProbeResult(DestinationPositionResult): """Result data from the execution of a `tryLiquidProbe` command.""" - z_position: Optional[float] = Field( + z_position: float | SkipJsonSchema[None] = Field( ..., description=( "The Z coordinate, in mm, of the found liquid in deck space." " If no liquid was found, `null` or omitted." ), + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/load_labware.py b/api/src/opentrons/protocol_engine/commands/load_labware.py index 2d8b8c3df78..6b65fe239e4 100644 --- a/api/src/opentrons/protocol_engine/commands/load_labware.py +++ b/api/src/opentrons/protocol_engine/commands/load_labware.py @@ -1,7 +1,9 @@ """Load labware command request, result, and implementation models.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Type, Any + from pydantic import BaseModel, Field -from typing import TYPE_CHECKING, Optional, Type +from pydantic.json_schema import SkipJsonSchema from typing_extensions import Literal from opentrons_shared_data.labware.labware_definition import LabwareDefinition @@ -29,6 +31,10 @@ LoadLabwareCommandType = Literal["loadLabware"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class LoadLabwareParams(BaseModel): """Payload required to load a labware into a slot.""" @@ -48,18 +54,20 @@ class LoadLabwareParams(BaseModel): ..., description="The labware definition version.", ) - labwareId: Optional[str] = Field( + labwareId: str | SkipJsonSchema[None] = Field( None, description="An optional ID to assign to this labware. If None, an ID " "will be generated.", + json_schema_extra=_remove_default, ) - displayName: Optional[str] = Field( + displayName: str | SkipJsonSchema[None] = Field( None, description="An optional user-specified display name " "or label for this labware.", # NOTE: v4/5 JSON protocols will always have a displayName which will be the # user-specified label OR the displayName property of the labware's definition. # TODO: Make sure v6 JSON protocols don't do that. + json_schema_extra=_remove_default, ) @@ -187,7 +195,7 @@ class LoadLabware(BaseCommand[LoadLabwareParams, LoadLabwareResult, ErrorOccurre commandType: LoadLabwareCommandType = "loadLabware" params: LoadLabwareParams - result: Optional[LoadLabwareResult] + result: Optional[LoadLabwareResult] = None _ImplementationCls: Type[LoadLabwareImplementation] = LoadLabwareImplementation diff --git a/api/src/opentrons/protocol_engine/commands/load_liquid.py b/api/src/opentrons/protocol_engine/commands/load_liquid.py index f6aa037fa01..a1ed1e8401c 100644 --- a/api/src/opentrons/protocol_engine/commands/load_liquid.py +++ b/api/src/opentrons/protocol_engine/commands/load_liquid.py @@ -81,7 +81,7 @@ class LoadLiquid(BaseCommand[LoadLiquidParams, LoadLiquidResult, ErrorOccurrence commandType: LoadLiquidCommandType = "loadLiquid" params: LoadLiquidParams - result: Optional[LoadLiquidResult] + result: Optional[LoadLiquidResult] = None _ImplementationCls: Type[LoadLiquidImplementation] = LoadLiquidImplementation diff --git a/api/src/opentrons/protocol_engine/commands/load_liquid_class.py b/api/src/opentrons/protocol_engine/commands/load_liquid_class.py index bd267abe567..8cb3d4a06fb 100644 --- a/api/src/opentrons/protocol_engine/commands/load_liquid_class.py +++ b/api/src/opentrons/protocol_engine/commands/load_liquid_class.py @@ -1,9 +1,11 @@ """LoadLiquidClass stores the liquid class settings used for a transfer into the Protocol Engine.""" from __future__ import annotations -from typing import Optional, Type, TYPE_CHECKING +from typing import Optional, Type, TYPE_CHECKING, Any + from typing_extensions import Literal from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ..errors import LiquidClassDoesNotExistError @@ -19,13 +21,18 @@ LoadLiquidClassCommandType = Literal["loadLiquidClass"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class LoadLiquidClassParams(BaseModel): """The liquid class transfer properties to store.""" - liquidClassId: Optional[str] = Field( + liquidClassId: str | SkipJsonSchema[None] = Field( None, description="Unique identifier for the liquid class to store. " "If you do not supply a liquidClassId, we will generate one.", + json_schema_extra=_remove_default, ) liquidClassRecord: LiquidClassRecord = Field( ..., diff --git a/api/src/opentrons/protocol_engine/commands/load_module.py b/api/src/opentrons/protocol_engine/commands/load_module.py index f8b88e08814..a0f4736a3a4 100644 --- a/api/src/opentrons/protocol_engine/commands/load_module.py +++ b/api/src/opentrons/protocol_engine/commands/load_module.py @@ -1,8 +1,9 @@ """Implementation, request models, and response models for the load module command.""" from __future__ import annotations -from typing import TYPE_CHECKING, Optional, Type +from typing import TYPE_CHECKING, Optional, Type, Any from typing_extensions import Literal from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from opentrons.protocol_engine.state.update_types import StateUpdate @@ -27,6 +28,10 @@ LoadModuleCommandType = Literal["loadModule"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class LoadModuleParams(BaseModel): """Payload required to load a module.""" @@ -59,12 +64,13 @@ class LoadModuleParams(BaseModel): ), ) - moduleId: Optional[str] = Field( + moduleId: str | SkipJsonSchema[None] = Field( None, description=( "An optional ID to assign to this module." " If None, an ID will be generated." ), + json_schema_extra=_remove_default, ) @@ -77,7 +83,7 @@ class LoadModuleResult(BaseModel): # TODO(mm, 2023-04-13): Remove this field. Jira RSS-221. definition: ModuleDefinition = Field( - deprecated=True, + json_schema_extra={"deprecated": True}, description=( "The definition of the connected module." " This field is an implementation detail. We might change or remove it without warning." @@ -204,7 +210,7 @@ class LoadModule(BaseCommand[LoadModuleParams, LoadModuleResult, ErrorOccurrence commandType: LoadModuleCommandType = "loadModule" params: LoadModuleParams - result: Optional[LoadModuleResult] + result: Optional[LoadModuleResult] = None _ImplementationCls: Type[LoadModuleImplementation] = LoadModuleImplementation diff --git a/api/src/opentrons/protocol_engine/commands/load_pipette.py b/api/src/opentrons/protocol_engine/commands/load_pipette.py index 6d8d74b4fa2..812299a6da1 100644 --- a/api/src/opentrons/protocol_engine/commands/load_pipette.py +++ b/api/src/opentrons/protocol_engine/commands/load_pipette.py @@ -1,20 +1,23 @@ """Load pipette command request, result, and implementation models.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Type, Any + +from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema +from typing_extensions import Literal -from opentrons.protocol_engine.state.update_types import StateUpdate from opentrons_shared_data.pipette.pipette_load_name_conversions import ( convert_to_pipette_name_type, ) from opentrons_shared_data.pipette.types import PipetteGenerationType from opentrons_shared_data.robot import user_facing_robot_type from opentrons_shared_data.robot.types import RobotTypeEnum -from pydantic import BaseModel, Field -from typing import TYPE_CHECKING, Optional, Type -from typing_extensions import Literal + from opentrons_shared_data.pipette.types import PipetteNameType from opentrons.types import MountType +from opentrons.protocol_engine.state.update_types import StateUpdate from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ..errors.error_occurrence import ErrorOccurrence from ..errors import InvalidSpecificationForRobotTypeError, InvalidLoadPipetteSpecsError @@ -27,6 +30,10 @@ LoadPipetteCommandType = Literal["loadPipette"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class LoadPipetteParams(BaseModel): """Payload needed to load a pipette on to a mount.""" @@ -38,21 +45,24 @@ class LoadPipetteParams(BaseModel): ..., description="The mount the pipette should be present on.", ) - pipetteId: Optional[str] = Field( + pipetteId: str | SkipJsonSchema[None] = Field( None, description="An optional ID to assign to this pipette. If None, an ID " "will be generated.", + json_schema_extra=_remove_default, ) - tipOverlapNotAfterVersion: Optional[str] = Field( + tipOverlapNotAfterVersion: str | SkipJsonSchema[None] = Field( None, description="A version of tip overlap data to not exceed. The highest-versioned " "tip overlap data that does not exceed this version will be used. Versions are " "expressed as vN where N is an integer, counting up from v0. If None, the current " "highest version will be used.", + json_schema_extra=_remove_default, ) - liquidPresenceDetection: Optional[bool] = Field( + liquidPresenceDetection: bool | SkipJsonSchema[None] = Field( None, description="Enable liquid presence detection for this pipette. Defaults to False.", + json_schema_extra=_remove_default, ) @@ -140,7 +150,7 @@ class LoadPipette(BaseCommand[LoadPipetteParams, LoadPipetteResult, ErrorOccurre commandType: LoadPipetteCommandType = "loadPipette" params: LoadPipetteParams - result: Optional[LoadPipetteResult] + result: Optional[LoadPipetteResult] = None _ImplementationCls: Type[LoadPipetteImplementation] = LoadPipetteImplementation diff --git a/api/src/opentrons/protocol_engine/commands/magnetic_module/disengage.py b/api/src/opentrons/protocol_engine/commands/magnetic_module/disengage.py index c20b18e481d..d0c7abef5a4 100644 --- a/api/src/opentrons/protocol_engine/commands/magnetic_module/disengage.py +++ b/api/src/opentrons/protocol_engine/commands/magnetic_module/disengage.py @@ -83,7 +83,7 @@ class Disengage(BaseCommand[DisengageParams, DisengageResult, ErrorOccurrence]): commandType: DisengageCommandType = "magneticModule/disengage" params: DisengageParams - result: Optional[DisengageResult] + result: Optional[DisengageResult] = None _ImplementationCls: Type[DisengageImplementation] = DisengageImplementation diff --git a/api/src/opentrons/protocol_engine/commands/magnetic_module/engage.py b/api/src/opentrons/protocol_engine/commands/magnetic_module/engage.py index 62f4e24eef4..6686d88edba 100644 --- a/api/src/opentrons/protocol_engine/commands/magnetic_module/engage.py +++ b/api/src/opentrons/protocol_engine/commands/magnetic_module/engage.py @@ -105,7 +105,7 @@ class Engage(BaseCommand[EngageParams, EngageResult, ErrorOccurrence]): commandType: EngageCommandType = "magneticModule/engage" params: EngageParams - result: Optional[EngageResult] + result: Optional[EngageResult] = None _ImplementationCls: Type[EngageImplementation] = EngageImplementation diff --git a/api/src/opentrons/protocol_engine/commands/move_labware.py b/api/src/opentrons/protocol_engine/commands/move_labware.py index b64491f5192..8eb93ce9217 100644 --- a/api/src/opentrons/protocol_engine/commands/move_labware.py +++ b/api/src/opentrons/protocol_engine/commands/move_labware.py @@ -1,14 +1,17 @@ """Models and implementation for the ``moveLabware`` command.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Type, Any + +from pydantic.json_schema import SkipJsonSchema +from pydantic import BaseModel, Field +from typing_extensions import Literal + from opentrons_shared_data.errors.exceptions import ( FailedGripperPickupError, LabwareDroppedError, StallOrCollisionDetectedError, ) -from pydantic import BaseModel, Field -from typing import TYPE_CHECKING, Optional, Type -from typing_extensions import Literal from opentrons.protocol_engine.resources.model_utils import ModelUtils from opentrons.types import Point @@ -49,6 +52,10 @@ MoveLabwareCommandType = Literal["moveLabware"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + # Extra buffer on top of minimum distance to move to the right _TRASH_CHUTE_DROP_BUFFER_MM = 8 @@ -63,15 +70,17 @@ class MoveLabwareParams(BaseModel): description="Whether to use the gripper to perform the labware movement" " or to perform a manual movement with an option to pause.", ) - pickUpOffset: Optional[LabwareOffsetVector] = Field( + pickUpOffset: LabwareOffsetVector | SkipJsonSchema[None] = Field( None, description="Offset to use when picking up labware. " "Experimental param, subject to change", + json_schema_extra=_remove_default, ) - dropOffset: Optional[LabwareOffsetVector] = Field( + dropOffset: LabwareOffsetVector | SkipJsonSchema[None] = Field( None, description="Offset to use when dropping off labware. " "Experimental param, subject to change", + json_schema_extra=_remove_default, ) @@ -359,7 +368,7 @@ class MoveLabware( commandType: MoveLabwareCommandType = "moveLabware" params: MoveLabwareParams - result: Optional[MoveLabwareResult] + result: Optional[MoveLabwareResult] = None _ImplementationCls: Type[MoveLabwareImplementation] = MoveLabwareImplementation diff --git a/api/src/opentrons/protocol_engine/commands/move_relative.py b/api/src/opentrons/protocol_engine/commands/move_relative.py index 54c877a3693..d54f9470184 100644 --- a/api/src/opentrons/protocol_engine/commands/move_relative.py +++ b/api/src/opentrons/protocol_engine/commands/move_relative.py @@ -88,7 +88,7 @@ class MoveRelative( commandType: MoveRelativeCommandType = "moveRelative" params: MoveRelativeParams - result: Optional[MoveRelativeResult] + result: Optional[MoveRelativeResult] = None _ImplementationCls: Type[MoveRelativeImplementation] = MoveRelativeImplementation diff --git a/api/src/opentrons/protocol_engine/commands/move_to_addressable_area.py b/api/src/opentrons/protocol_engine/commands/move_to_addressable_area.py index 7380a01951a..2ac788b33cf 100644 --- a/api/src/opentrons/protocol_engine/commands/move_to_addressable_area.py +++ b/api/src/opentrons/protocol_engine/commands/move_to_addressable_area.py @@ -160,7 +160,7 @@ class MoveToAddressableArea( commandType: MoveToAddressableAreaCommandType = "moveToAddressableArea" params: MoveToAddressableAreaParams - result: Optional[MoveToAddressableAreaResult] + result: Optional[MoveToAddressableAreaResult] = None _ImplementationCls: Type[ MoveToAddressableAreaImplementation diff --git a/api/src/opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py b/api/src/opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py index 679e769cc2e..f4afcd5d1ff 100644 --- a/api/src/opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +++ b/api/src/opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py @@ -1,9 +1,11 @@ """Move to addressable area for drop tip command request, result, and implementation models.""" from __future__ import annotations -from pydantic import Field -from typing import TYPE_CHECKING, Optional, Type +from typing import TYPE_CHECKING, Optional, Type, Any from typing_extensions import Literal +from pydantic import Field +from pydantic.json_schema import SkipJsonSchema + from ..errors import LocationNotAccessibleByPipetteError from ..types import AddressableOffsetVector from ..resources import fixture_validation @@ -32,6 +34,10 @@ MoveToAddressableAreaForDropTipCommandType = Literal["moveToAddressableAreaForDropTip"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class MoveToAddressableAreaForDropTipParams(PipetteIdMixin, MovementMixin): """Payload required to move a pipette to a specific addressable area. @@ -65,7 +71,7 @@ class MoveToAddressableAreaForDropTipParams(PipetteIdMixin, MovementMixin): AddressableOffsetVector(x=0, y=0, z=0), description="Relative offset of addressable area to move pipette's critical point.", ) - alternateDropLocation: Optional[bool] = Field( + alternateDropLocation: bool | SkipJsonSchema[None] = Field( False, description=( "Whether to alternate location where tip is dropped within the addressable area." @@ -74,8 +80,9 @@ class MoveToAddressableAreaForDropTipParams(PipetteIdMixin, MovementMixin): " labware well." " If False, the tip will be dropped at the top center of the area." ), + json_schema_extra=_remove_default, ) - ignoreTipConfiguration: Optional[bool] = Field( + ignoreTipConfiguration: bool | SkipJsonSchema[None] = Field( True, description=( "Whether to utilize the critical point of the tip configuraiton when moving to an addressable area." @@ -83,6 +90,7 @@ class MoveToAddressableAreaForDropTipParams(PipetteIdMixin, MovementMixin): " as the critical point for movement." " If False, this command will use the critical point provided by the current tip configuration." ), + json_schema_extra=_remove_default, ) @@ -170,7 +178,7 @@ class MoveToAddressableAreaForDropTip( "moveToAddressableAreaForDropTip" ) params: MoveToAddressableAreaForDropTipParams - result: Optional[MoveToAddressableAreaForDropTipResult] + result: Optional[MoveToAddressableAreaForDropTipResult] = None _ImplementationCls: Type[ MoveToAddressableAreaForDropTipImplementation diff --git a/api/src/opentrons/protocol_engine/commands/move_to_coordinates.py b/api/src/opentrons/protocol_engine/commands/move_to_coordinates.py index 36b7ff64ed0..3493f5d6ea6 100644 --- a/api/src/opentrons/protocol_engine/commands/move_to_coordinates.py +++ b/api/src/opentrons/protocol_engine/commands/move_to_coordinates.py @@ -91,7 +91,7 @@ class MoveToCoordinates( commandType: MoveToCoordinatesCommandType = "moveToCoordinates" params: MoveToCoordinatesParams - result: Optional[MoveToCoordinatesResult] + result: Optional[MoveToCoordinatesResult] = None _ImplementationCls: Type[ MoveToCoordinatesImplementation diff --git a/api/src/opentrons/protocol_engine/commands/move_to_well.py b/api/src/opentrons/protocol_engine/commands/move_to_well.py index 6aaf398650f..73ebfbff638 100644 --- a/api/src/opentrons/protocol_engine/commands/move_to_well.py +++ b/api/src/opentrons/protocol_engine/commands/move_to_well.py @@ -106,7 +106,7 @@ class MoveToWell( commandType: MoveToWellCommandType = "moveToWell" params: MoveToWellParams - result: Optional[MoveToWellResult] + result: Optional[MoveToWellResult] = None _ImplementationCls: Type[MoveToWellImplementation] = MoveToWellImplementation diff --git a/api/src/opentrons/protocol_engine/commands/movement_common.py b/api/src/opentrons/protocol_engine/commands/movement_common.py index ca12d2d1ad8..786b59921b2 100644 --- a/api/src/opentrons/protocol_engine/commands/movement_common.py +++ b/api/src/opentrons/protocol_engine/commands/movement_common.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Optional, Union, TYPE_CHECKING, Literal +from typing import Optional, Union, TYPE_CHECKING, Literal, Any from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from opentrons_shared_data.errors import ErrorCodes from opentrons_shared_data.errors.exceptions import StallOrCollisionDetectedError @@ -26,6 +27,10 @@ from ..resources.model_utils import ModelUtils +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class WellLocationMixin(BaseModel): """Mixin for command requests that take a location that's somewhere in a well.""" @@ -63,13 +68,14 @@ class LiquidHandlingWellLocationMixin(BaseModel): class MovementMixin(BaseModel): """Mixin for command requests that move a pipette.""" - minimumZHeight: Optional[float] = Field( + minimumZHeight: float | SkipJsonSchema[None] = Field( None, description=( "Optional minimal Z margin in mm." " If this is larger than the API's default safe Z margin," " it will make the arc higher. If it's smaller, it will have no effect." ), + json_schema_extra=_remove_default, ) forceDirect: bool = Field( @@ -83,12 +89,13 @@ class MovementMixin(BaseModel): ), ) - speed: Optional[float] = Field( + speed: float | SkipJsonSchema[None] = Field( None, description=( "Override the travel speed in mm/s." " This controls the straight linear speed of motion." ), + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/pick_up_tip.py b/api/src/opentrons/protocol_engine/commands/pick_up_tip.py index af8723a5bba..e5612bb3cdc 100644 --- a/api/src/opentrons/protocol_engine/commands/pick_up_tip.py +++ b/api/src/opentrons/protocol_engine/commands/pick_up_tip.py @@ -212,7 +212,7 @@ class PickUpTip( commandType: PickUpTipCommandType = "pickUpTip" params: PickUpTipParams - result: Optional[PickUpTipResult] + result: Optional[PickUpTipResult] = None _ImplementationCls: Type[PickUpTipImplementation] = PickUpTipImplementation diff --git a/api/src/opentrons/protocol_engine/commands/pipetting_common.py b/api/src/opentrons/protocol_engine/commands/pipetting_common.py index 0292b51eee1..c373642a02e 100644 --- a/api/src/opentrons/protocol_engine/commands/pipetting_common.py +++ b/api/src/opentrons/protocol_engine/commands/pipetting_common.py @@ -1,10 +1,12 @@ """Common pipetting command base models.""" from __future__ import annotations -from opentrons_shared_data.errors import ErrorCodes +from typing import Literal, Tuple, TYPE_CHECKING + +from typing_extensions import TypedDict from pydantic import BaseModel, Field -from typing import Literal, Tuple, TypedDict, TYPE_CHECKING +from opentrons_shared_data.errors import ErrorCodes from opentrons.protocol_engine.errors.error_occurrence import ErrorOccurrence from opentrons.protocol_engine.types import AspiratedFluid, FluidKind from opentrons_shared_data.errors.exceptions import PipetteOverpressureError @@ -71,6 +73,10 @@ class BaseLiquidHandlingResult(BaseModel): ) +class EmptyResult(BaseModel): + """A result with no data.""" + + class ErrorLocationInfo(TypedDict): """Holds a retry location for in-place error recovery. @@ -139,7 +145,7 @@ async def prepare_for_aspirate( pipetting: PipettingHandler, model_utils: ModelUtils, location_if_error: ErrorLocationInfo, -) -> SuccessData[BaseModel] | DefinedErrorData[OverpressureError]: +) -> SuccessData[EmptyResult] | DefinedErrorData[OverpressureError]: """Execute pipetting.prepare_for_aspirate, handle errors, and marshal success.""" try: await pipetting.prepare_for_aspirate(pipette_id) @@ -161,7 +167,7 @@ async def prepare_for_aspirate( ) else: return SuccessData( - public=BaseModel(), + public=EmptyResult(), state_update=StateUpdate().set_fluid_empty(pipette_id=pipette_id), ) @@ -259,7 +265,7 @@ async def blow_out_in_place( location_if_error: ErrorLocationInfo, pipetting: PipettingHandler, model_utils: ModelUtils, -) -> SuccessData[BaseModel] | DefinedErrorData[OverpressureError]: +) -> SuccessData[EmptyResult] | DefinedErrorData[OverpressureError]: """Execute a blow-out-in-place micro-operation.""" try: await pipetting.blow_out_in_place(pipette_id=pipette_id, flow_rate=flow_rate) @@ -281,6 +287,6 @@ async def blow_out_in_place( ) else: return SuccessData( - public=BaseModel(), + public=EmptyResult(), state_update=StateUpdate().set_fluid_empty(pipette_id=pipette_id), ) diff --git a/api/src/opentrons/protocol_engine/commands/prepare_to_aspirate.py b/api/src/opentrons/protocol_engine/commands/prepare_to_aspirate.py index cabcb2039eb..beaf6e1ca0c 100644 --- a/api/src/opentrons/protocol_engine/commands/prepare_to_aspirate.py +++ b/api/src/opentrons/protocol_engine/commands/prepare_to_aspirate.py @@ -95,7 +95,7 @@ class PrepareToAspirate( commandType: PrepareToAspirateCommandType = "prepareToAspirate" params: PrepareToAspirateParams - result: Optional[PrepareToAspirateResult] + result: Optional[PrepareToAspirateResult] = None _ImplementationCls: Type[ PrepareToAspirateImplementation diff --git a/api/src/opentrons/protocol_engine/commands/reload_labware.py b/api/src/opentrons/protocol_engine/commands/reload_labware.py index 60230a1c6dd..07d70957cdb 100644 --- a/api/src/opentrons/protocol_engine/commands/reload_labware.py +++ b/api/src/opentrons/protocol_engine/commands/reload_labware.py @@ -89,7 +89,7 @@ class ReloadLabware( commandType: ReloadLabwareCommandType = "reloadLabware" params: ReloadLabwareParams - result: Optional[ReloadLabwareResult] + result: Optional[ReloadLabwareResult] = None _ImplementationCls: Type[ReloadLabwareImplementation] = ReloadLabwareImplementation diff --git a/api/src/opentrons/protocol_engine/commands/retract_axis.py b/api/src/opentrons/protocol_engine/commands/retract_axis.py index 49020eb517e..19c7653793f 100644 --- a/api/src/opentrons/protocol_engine/commands/retract_axis.py +++ b/api/src/opentrons/protocol_engine/commands/retract_axis.py @@ -61,7 +61,7 @@ class RetractAxis(BaseCommand[RetractAxisParams, RetractAxisResult, ErrorOccurre commandType: RetractAxisCommandType = "retractAxis" params: RetractAxisParams - result: Optional[RetractAxisResult] + result: Optional[RetractAxisResult] = None _ImplementationCls: Type[RetractAxisImplementation] = RetractAxisImplementation diff --git a/api/src/opentrons/protocol_engine/commands/robot/close_gripper_jaw.py b/api/src/opentrons/protocol_engine/commands/robot/close_gripper_jaw.py index 965c6d2ec72..36b027c351a 100644 --- a/api/src/opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +++ b/api/src/opentrons/protocol_engine/commands/robot/close_gripper_jaw.py @@ -1,10 +1,12 @@ """Command models for opening a gripper jaw.""" from __future__ import annotations -from typing import Literal, Type, Optional -from opentrons.hardware_control import HardwareControlAPI -from opentrons.protocol_engine.resources import ensure_ot3_hardware +from typing import Literal, Type, Optional, Any from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema + +from opentrons.hardware_control import HardwareControlAPI +from opentrons.protocol_engine.resources import ensure_ot3_hardware from ..command import ( AbstractCommandImpl, @@ -18,12 +20,17 @@ closeGripperJawCommandType = Literal["robot/closeGripperJaw"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class closeGripperJawParams(BaseModel): """Payload required to close a gripper.""" - force: Optional[float] = Field( + force: float | SkipJsonSchema[None] = Field( default=None, description="The force the gripper should use to hold the jaws, falls to default if none is provided.", + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/robot/move_axes_relative.py b/api/src/opentrons/protocol_engine/commands/robot/move_axes_relative.py index 238229ebce6..99b30e9595a 100644 --- a/api/src/opentrons/protocol_engine/commands/robot/move_axes_relative.py +++ b/api/src/opentrons/protocol_engine/commands/robot/move_axes_relative.py @@ -1,8 +1,10 @@ """Command models for moving any robot axis relative.""" + from __future__ import annotations -from typing import Literal, Type, Optional, TYPE_CHECKING +from typing import Literal, Type, Optional, TYPE_CHECKING, Any from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from opentrons.hardware_control import HardwareControlAPI from opentrons.protocol_engine.resources import ensure_ot3_hardware @@ -23,15 +25,20 @@ MoveAxesRelativeCommandType = Literal["robot/moveAxesRelative"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class MoveAxesRelativeParams(BaseModel): """Payload required to move axes relative to position.""" axis_map: MotorAxisMapType = Field( ..., description="A dictionary mapping axes to relative movements in mm." ) - speed: Optional[float] = Field( + speed: float | SkipJsonSchema[None] = Field( default=None, description="The max velocity to move the axes at. Will fall to hardware defaults if none provided.", + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/robot/move_axes_to.py b/api/src/opentrons/protocol_engine/commands/robot/move_axes_to.py index 0d17d5f171f..93fc2746c84 100644 --- a/api/src/opentrons/protocol_engine/commands/robot/move_axes_to.py +++ b/api/src/opentrons/protocol_engine/commands/robot/move_axes_to.py @@ -1,7 +1,9 @@ """Command models for moving any robot axis to an absolute position.""" from __future__ import annotations -from typing import Literal, Optional, Type, TYPE_CHECKING +from typing import Literal, Optional, Type, TYPE_CHECKING, Any + from pydantic import Field, BaseModel +from pydantic.json_schema import SkipJsonSchema from opentrons.hardware_control import HardwareControlAPI from opentrons.protocol_engine.resources import ensure_ot3_hardware @@ -22,18 +24,25 @@ MoveAxesToCommandType = Literal["robot/moveAxesTo"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class MoveAxesToParams(BaseModel): """Payload required to move axes to absolute position.""" axis_map: MotorAxisMapType = Field( ..., description="The specified axes to move to an absolute deck position with." ) - critical_point: Optional[MotorAxisMapType] = Field( - default=None, description="The critical point to move the mount with." + critical_point: MotorAxisMapType | SkipJsonSchema[None] = Field( + default=None, + description="The critical point to move the mount with.", + json_schema_extra=_remove_default, ) - speed: Optional[float] = Field( + speed: float | SkipJsonSchema[None] = Field( default=None, description="The max velocity to move the axes at. Will fall to hardware defaults if none provided.", + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/robot/move_to.py b/api/src/opentrons/protocol_engine/commands/robot/move_to.py index 199d5be5079..e2a3af07767 100644 --- a/api/src/opentrons/protocol_engine/commands/robot/move_to.py +++ b/api/src/opentrons/protocol_engine/commands/robot/move_to.py @@ -1,8 +1,10 @@ """Command models for moving any robot mount to a destination point.""" from __future__ import annotations -from typing import Literal, Type, Optional, TYPE_CHECKING +from typing import Literal, Type, Optional, TYPE_CHECKING, Any from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema + from opentrons.types import MountType from ..movement_common import DestinationPositionResult @@ -23,6 +25,10 @@ MoveToCommandType = Literal["robot/moveTo"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class MoveToParams(BaseModel): """Payload required to move to a destination position.""" @@ -34,9 +40,10 @@ class MoveToParams(BaseModel): ..., description="X, Y and Z coordinates in mm from deck's origin location (left-front-bottom corner of work space)", ) - speed: Optional[float] = Field( + speed: float | SkipJsonSchema[None] = Field( default=None, description="The max velocity to move the axes at. Will fall to hardware defaults if none provided.", + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/save_position.py b/api/src/opentrons/protocol_engine/commands/save_position.py index 4bc208d1421..6a1d22c4687 100644 --- a/api/src/opentrons/protocol_engine/commands/save_position.py +++ b/api/src/opentrons/protocol_engine/commands/save_position.py @@ -1,8 +1,10 @@ """Save pipette position command request, result, and implementation models.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Type, Any + from pydantic import BaseModel, Field -from typing import TYPE_CHECKING, Optional, Type +from pydantic.json_schema import SkipJsonSchema from typing_extensions import Literal from ..types import DeckPoint @@ -16,19 +18,26 @@ SavePositionCommandType = Literal["savePosition"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class SavePositionParams(BaseModel): """Payload needed to save a pipette's current position.""" pipetteId: str = Field( ..., description="Unique identifier of the pipette in question." ) - positionId: Optional[str] = Field( + positionId: str | SkipJsonSchema[None] = Field( None, description="An optional ID to assign to this command instance. " "Auto-assigned if not defined.", + json_schema_extra=_remove_default, ) - failOnNotHomed: Optional[bool] = Field( - True, descrption="Require all axes to be homed before saving position." + failOnNotHomed: bool | SkipJsonSchema[None] = Field( + True, + description="Require all axes to be homed before saving position.", + json_schema_extra=_remove_default, ) @@ -86,7 +95,7 @@ class SavePosition( commandType: SavePositionCommandType = "savePosition" params: SavePositionParams - result: Optional[SavePositionResult] + result: Optional[SavePositionResult] = None _ImplementationCls: Type[SavePositionImplementation] = SavePositionImplementation diff --git a/api/src/opentrons/protocol_engine/commands/set_rail_lights.py b/api/src/opentrons/protocol_engine/commands/set_rail_lights.py index 09254dbe966..7ca3929695b 100644 --- a/api/src/opentrons/protocol_engine/commands/set_rail_lights.py +++ b/api/src/opentrons/protocol_engine/commands/set_rail_lights.py @@ -53,7 +53,7 @@ class SetRailLights( commandType: SetRailLightsCommandType = "setRailLights" params: SetRailLightsParams - result: Optional[SetRailLightsResult] + result: Optional[SetRailLightsResult] = None _ImplementationCls: Type[SetRailLightsImplementation] = SetRailLightsImplementation diff --git a/api/src/opentrons/protocol_engine/commands/set_status_bar.py b/api/src/opentrons/protocol_engine/commands/set_status_bar.py index 2e1483f6d93..62ca9b7682a 100644 --- a/api/src/opentrons/protocol_engine/commands/set_status_bar.py +++ b/api/src/opentrons/protocol_engine/commands/set_status_bar.py @@ -75,7 +75,7 @@ class SetStatusBar( commandType: SetStatusBarCommandType = "setStatusBar" params: SetStatusBarParams - result: Optional[SetStatusBarResult] + result: Optional[SetStatusBarResult] = None _ImplementationCls: Type[SetStatusBarImplementation] = SetStatusBarImplementation diff --git a/api/src/opentrons/protocol_engine/commands/temperature_module/deactivate.py b/api/src/opentrons/protocol_engine/commands/temperature_module/deactivate.py index e56c98e6e30..e1514c91f30 100644 --- a/api/src/opentrons/protocol_engine/commands/temperature_module/deactivate.py +++ b/api/src/opentrons/protocol_engine/commands/temperature_module/deactivate.py @@ -72,7 +72,7 @@ class DeactivateTemperature( commandType: DeactivateTemperatureCommandType = "temperatureModule/deactivate" params: DeactivateTemperatureParams - result: Optional[DeactivateTemperatureResult] + result: Optional[DeactivateTemperatureResult] = None _ImplementationCls: Type[DeactivateTemperatureImpl] = DeactivateTemperatureImpl diff --git a/api/src/opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py b/api/src/opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py index 6d65bf47bb0..b0aa7bd5cd0 100644 --- a/api/src/opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +++ b/api/src/opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py @@ -81,7 +81,7 @@ class SetTargetTemperature( "temperatureModule/setTargetTemperature" ) params: SetTargetTemperatureParams - result: Optional[SetTargetTemperatureResult] + result: Optional[SetTargetTemperatureResult] = None _ImplementationCls: Type[SetTargetTemperatureImpl] = SetTargetTemperatureImpl diff --git a/api/src/opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py b/api/src/opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py index fa7784de141..5f3f052d91b 100644 --- a/api/src/opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +++ b/api/src/opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py @@ -1,9 +1,10 @@ """Command models to wait for target temperature of a Temperature Module.""" from __future__ import annotations -from typing import Optional, TYPE_CHECKING -from typing_extensions import Literal, Type +from typing import Optional, TYPE_CHECKING, Any +from typing_extensions import Literal, Type from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ...errors.error_occurrence import ErrorOccurrence @@ -15,11 +16,15 @@ WaitForTemperatureCommandType = Literal["temperatureModule/waitForTemperature"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class WaitForTemperatureParams(BaseModel): """Input parameters to wait for a Temperature Module's target temperature.""" moduleId: str = Field(..., description="Unique ID of the Temperature Module.") - celsius: Optional[float] = Field( + celsius: float | SkipJsonSchema[None] = Field( None, description="Target temperature in °C. If not specified, will " "default to the module's target temperature. " @@ -27,6 +32,7 @@ class WaitForTemperatureParams(BaseModel): "could lead to unpredictable behavior and hence is not " "recommended for use. This parameter can be removed in a " "future version without prior notice.", + json_schema_extra=_remove_default, ) @@ -84,7 +90,7 @@ class WaitForTemperature( commandType: WaitForTemperatureCommandType = "temperatureModule/waitForTemperature" params: WaitForTemperatureParams - result: Optional[WaitForTemperatureResult] + result: Optional[WaitForTemperatureResult] = None _ImplementationCls: Type[WaitForTemperatureImpl] = WaitForTemperatureImpl diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py b/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py index 578a5d6b7a7..c5171c82da8 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py @@ -73,7 +73,7 @@ class CloseLid(BaseCommand[CloseLidParams, CloseLidResult, ErrorOccurrence]): commandType: CloseLidCommandType = "thermocycler/closeLid" params: CloseLidParams - result: Optional[CloseLidResult] + result: Optional[CloseLidResult] = None _ImplementationCls: Type[CloseLidImpl] = CloseLidImpl diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/deactivate_block.py b/api/src/opentrons/protocol_engine/commands/thermocycler/deactivate_block.py index 67199577d53..fb49f031ac4 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/deactivate_block.py @@ -66,7 +66,7 @@ class DeactivateBlock( commandType: DeactivateBlockCommandType = "thermocycler/deactivateBlock" params: DeactivateBlockParams - result: Optional[DeactivateBlockResult] + result: Optional[DeactivateBlockResult] = None _ImplementationCls: Type[DeactivateBlockImpl] = DeactivateBlockImpl diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py b/api/src/opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py index 9c3541efb12..f92065c88e9 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py @@ -66,7 +66,7 @@ class DeactivateLid( commandType: DeactivateLidCommandType = "thermocycler/deactivateLid" params: DeactivateLidParams - result: Optional[DeactivateLidResult] + result: Optional[DeactivateLidResult] = None _ImplementationCls: Type[DeactivateLidImpl] = DeactivateLidImpl diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py b/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py index 3df32d1ec99..6eedb9f4c60 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py @@ -73,7 +73,7 @@ class OpenLid(BaseCommand[OpenLidParams, OpenLidResult, ErrorOccurrence]): commandType: OpenLidCommandType = "thermocycler/openLid" params: OpenLidParams - result: Optional[OpenLidResult] + result: Optional[OpenLidResult] = None _ImplementationCls: Type[OpenLidImpl] = OpenLidImpl diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py b/api/src/opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py index 6f63aed8fe3..40f87af7772 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py @@ -1,9 +1,10 @@ """Command models to execute a Thermocycler profile.""" from __future__ import annotations -from typing import List, Optional, TYPE_CHECKING, overload, Union +from typing import List, Optional, TYPE_CHECKING, overload, Union, Any from typing_extensions import Literal, Type from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from opentrons.hardware_control.modules.types import ThermocyclerStep, ThermocyclerCycle @@ -21,6 +22,10 @@ RunExtendedProfileCommandType = Literal["thermocycler/runExtendedProfile"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class ProfileStep(BaseModel): """An individual step in a Thermocycler extended profile.""" @@ -45,10 +50,11 @@ class RunExtendedProfileParams(BaseModel): ..., description="Elements of the profile. Each can be either a step or a cycle.", ) - blockMaxVolumeUl: Optional[float] = Field( + blockMaxVolumeUl: float | SkipJsonSchema[None] = Field( None, description="Amount of liquid in uL of the most-full well" " in labware loaded onto the thermocycler.", + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/run_profile.py b/api/src/opentrons/protocol_engine/commands/thermocycler/run_profile.py index 02aa7ad93e2..fee6ed82bb3 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/run_profile.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/run_profile.py @@ -1,9 +1,10 @@ """Command models to execute a Thermocycler profile.""" from __future__ import annotations -from typing import List, Optional, TYPE_CHECKING +from typing import List, Optional, TYPE_CHECKING, Any from typing_extensions import Literal, Type from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from opentrons.hardware_control.modules.types import ThermocyclerStep @@ -18,6 +19,10 @@ RunProfileCommandType = Literal["thermocycler/runProfile"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class RunProfileStepParams(BaseModel): """Input parameters for an individual Thermocycler profile step.""" @@ -35,10 +40,11 @@ class RunProfileParams(BaseModel): ..., description="Array of profile steps with target temperature and temperature hold time.", ) - blockMaxVolumeUl: Optional[float] = Field( + blockMaxVolumeUl: float | SkipJsonSchema[None] = Field( None, description="Amount of liquid in uL of the most-full well" " in labware loaded onto the thermocycler.", + json_schema_extra=_remove_default, ) @@ -104,7 +110,7 @@ class RunProfile(BaseCommand[RunProfileParams, RunProfileResult, ErrorOccurrence commandType: RunProfileCommandType = "thermocycler/runProfile" params: RunProfileParams - result: Optional[RunProfileResult] + result: Optional[RunProfileResult] = None _ImplementationCls: Type[RunProfileImpl] = RunProfileImpl diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py b/api/src/opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py index b69bb15ea90..f1884e8ee9e 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py @@ -1,9 +1,10 @@ """Command models to start heating a Thermocycler's block.""" from __future__ import annotations -from typing import Optional, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING, Any from typing_extensions import Literal, Type from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ...errors.error_occurrence import ErrorOccurrence @@ -16,21 +17,27 @@ SetTargetBlockTemperatureCommandType = Literal["thermocycler/setTargetBlockTemperature"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class SetTargetBlockTemperatureParams(BaseModel): """Input parameters to set a Thermocycler's target block temperature.""" moduleId: str = Field(..., description="Unique ID of the Thermocycler Module.") celsius: float = Field(..., description="Target temperature in °C.") - blockMaxVolumeUl: Optional[float] = Field( + blockMaxVolumeUl: float | SkipJsonSchema[None] = Field( None, description="Amount of liquid in uL of the most-full well" " in labware loaded onto the thermocycler.", + json_schema_extra=_remove_default, ) - holdTimeSeconds: Optional[float] = Field( + holdTimeSeconds: float | SkipJsonSchema[None] = Field( None, description="Amount of time, in seconds, to hold the temperature for." " If specified, a waitForBlockTemperature command will block until" " the given hold time has elapsed.", + json_schema_extra=_remove_default, ) @@ -113,7 +120,7 @@ class SetTargetBlockTemperature( "thermocycler/setTargetBlockTemperature" ) params: SetTargetBlockTemperatureParams - result: Optional[SetTargetBlockTemperatureResult] + result: Optional[SetTargetBlockTemperatureResult] = None _ImplementationCls: Type[ SetTargetBlockTemperatureImpl diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py b/api/src/opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py index 37217e047ae..a1af8941ee9 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py @@ -84,7 +84,7 @@ class SetTargetLidTemperature( "thermocycler/setTargetLidTemperature" ) params: SetTargetLidTemperatureParams - result: Optional[SetTargetLidTemperatureResult] + result: Optional[SetTargetLidTemperatureResult] = None _ImplementationCls: Type[SetTargetLidTemperatureImpl] = SetTargetLidTemperatureImpl diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py b/api/src/opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py index 8e8c9b1a4ec..388d1af13d9 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py @@ -77,7 +77,7 @@ class WaitForBlockTemperature( "thermocycler/waitForBlockTemperature" ) params: WaitForBlockTemperatureParams - result: Optional[WaitForBlockTemperatureResult] + result: Optional[WaitForBlockTemperatureResult] = None _ImplementationCls: Type[WaitForBlockTemperatureImpl] = WaitForBlockTemperatureImpl diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py b/api/src/opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py index 95e5fbc4f0a..233e4ff5a8c 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py @@ -75,7 +75,7 @@ class WaitForLidTemperature( commandType: WaitForLidTemperatureCommandType = "thermocycler/waitForLidTemperature" params: WaitForLidTemperatureParams - result: Optional[WaitForLidTemperatureResult] + result: Optional[WaitForLidTemperatureResult] = None _ImplementationCls: Type[WaitForLidTemperatureImpl] = WaitForLidTemperatureImpl diff --git a/api/src/opentrons/protocol_engine/commands/touch_tip.py b/api/src/opentrons/protocol_engine/commands/touch_tip.py index 2eefd572d9a..4ccced4b3d3 100644 --- a/api/src/opentrons/protocol_engine/commands/touch_tip.py +++ b/api/src/opentrons/protocol_engine/commands/touch_tip.py @@ -1,9 +1,11 @@ """Touch tip command request, result, and implementation models.""" from __future__ import annotations -from pydantic import Field -from typing import TYPE_CHECKING, Optional, Type +from typing import TYPE_CHECKING, Optional, Type, Any + from typing_extensions import Literal +from pydantic import Field +from pydantic.json_schema import SkipJsonSchema from opentrons.types import Point @@ -39,6 +41,10 @@ TouchTipCommandType = Literal["touchTip"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class TouchTipParams(PipetteIdMixin, WellLocationMixin): """Payload needed to touch a pipette tip the sides of a specific well.""" @@ -49,18 +55,20 @@ class TouchTipParams(PipetteIdMixin, WellLocationMixin): ), ) - mmFromEdge: Optional[float] = Field( + mmFromEdge: float | SkipJsonSchema[None] = Field( None, description="Offset away from the the well edge, in millimeters." "Incompatible when a radius is included as a non 1.0 value.", + json_schema_extra=_remove_default, ) - speed: Optional[float] = Field( + speed: float | SkipJsonSchema[None] = Field( None, description=( "Override the travel speed in mm/s." " This controls the straight linear speed of motion." ), + json_schema_extra=_remove_default, ) @@ -167,7 +175,7 @@ class TouchTip(BaseCommand[TouchTipParams, TouchTipResult, StallOrCollisionError commandType: TouchTipCommandType = "touchTip" params: TouchTipParams - result: Optional[TouchTipResult] + result: Optional[TouchTipResult] = None _ImplementationCls: Type[TouchTipImplementation] = TouchTipImplementation diff --git a/api/src/opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py b/api/src/opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py index 5aa4e292f63..56a87a468dd 100644 --- a/api/src/opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +++ b/api/src/opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py @@ -1,13 +1,16 @@ """Command models to drop tip in place while plunger positions are unknown.""" + from __future__ import annotations -from opentrons.protocol_engine.state.update_types import StateUpdate +from typing import TYPE_CHECKING, Optional, Type, Any + from pydantic import Field, BaseModel -from typing import TYPE_CHECKING, Optional, Type +from pydantic.json_schema import SkipJsonSchema from typing_extensions import Literal from opentrons.hardware_control import HardwareControlAPI from opentrons.hardware_control.types import Axis +from opentrons.protocol_engine.state.update_types import StateUpdate from ..pipetting_common import PipetteIdMixin from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ...errors.error_occurrence import ErrorOccurrence @@ -21,16 +24,21 @@ UnsafeDropTipInPlaceCommandType = Literal["unsafe/dropTipInPlace"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class UnsafeDropTipInPlaceParams(PipetteIdMixin): """Payload required to drop a tip in place even if the plunger position is not known.""" - homeAfter: Optional[bool] = Field( + homeAfter: bool | SkipJsonSchema[None] = Field( None, description=( "Whether to home this pipette's plunger after dropping the tip." " You should normally leave this unspecified to let the robot choose" " a safe default depending on its hardware." ), + json_schema_extra=_remove_default, ) diff --git a/api/src/opentrons/protocol_engine/commands/verify_tip_presence.py b/api/src/opentrons/protocol_engine/commands/verify_tip_presence.py index e0412022e85..dc6f451e3e4 100644 --- a/api/src/opentrons/protocol_engine/commands/verify_tip_presence.py +++ b/api/src/opentrons/protocol_engine/commands/verify_tip_presence.py @@ -1,8 +1,9 @@ """Verify tip presence command request, result and implementation models.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Type, Any from pydantic import Field, BaseModel -from typing import TYPE_CHECKING, Optional, Type +from pydantic.json_schema import SkipJsonSchema from typing_extensions import Literal from .pipetting_common import PipetteIdMixin @@ -18,14 +19,20 @@ VerifyTipPresenceCommandType = Literal["verifyTipPresence"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class VerifyTipPresenceParams(PipetteIdMixin): """Payload required for a VerifyTipPresence command.""" expectedState: TipPresenceStatus = Field( ..., description="The expected tip presence status on the pipette." ) - followSingularSensor: Optional[InstrumentSensorId] = Field( - default=None, description="The sensor id to follow if the other can be ignored." + followSingularSensor: InstrumentSensorId | SkipJsonSchema[None] = Field( + default=None, + description="The sensor id to follow if the other can be ignored.", + json_schema_extra=_remove_default, ) @@ -77,7 +84,7 @@ class VerifyTipPresence( commandType: VerifyTipPresenceCommandType = "verifyTipPresence" params: VerifyTipPresenceParams - result: Optional[VerifyTipPresenceResult] + result: Optional[VerifyTipPresenceResult] = None _ImplementationCls: Type[ VerifyTipPresenceImplementation diff --git a/api/src/opentrons/protocol_engine/commands/wait_for_duration.py b/api/src/opentrons/protocol_engine/commands/wait_for_duration.py index 04f8693386e..26a4372c8ca 100644 --- a/api/src/opentrons/protocol_engine/commands/wait_for_duration.py +++ b/api/src/opentrons/protocol_engine/commands/wait_for_duration.py @@ -1,7 +1,9 @@ """Wait for duration command request, result, and implementation models.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Type, Any + from pydantic import BaseModel, Field -from typing import TYPE_CHECKING, Optional, Type +from pydantic.json_schema import SkipJsonSchema from typing_extensions import Literal from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData @@ -14,13 +16,18 @@ WaitForDurationCommandType = Literal["waitForDuration"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class WaitForDurationParams(BaseModel): """Payload required to pause the protocol.""" seconds: float = Field(..., description="Duration, in seconds, to wait for.") - message: Optional[str] = Field( + message: str | SkipJsonSchema[None] = Field( None, description="A user-facing message associated with the pause", + json_schema_extra=_remove_default, ) @@ -53,7 +60,7 @@ class WaitForDuration( commandType: WaitForDurationCommandType = "waitForDuration" params: WaitForDurationParams - result: Optional[WaitForDurationResult] + result: Optional[WaitForDurationResult] = None _ImplementationCls: Type[ WaitForDurationImplementation diff --git a/api/src/opentrons/protocol_engine/commands/wait_for_resume.py b/api/src/opentrons/protocol_engine/commands/wait_for_resume.py index f5066d52521..28458aa3721 100644 --- a/api/src/opentrons/protocol_engine/commands/wait_for_resume.py +++ b/api/src/opentrons/protocol_engine/commands/wait_for_resume.py @@ -1,7 +1,9 @@ """Wait for resume command request, result, and implementation models.""" from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Type, Any + from pydantic import BaseModel, Field -from typing import TYPE_CHECKING, Optional, Type +from pydantic.json_schema import SkipJsonSchema from typing_extensions import Literal from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData @@ -16,12 +18,17 @@ WaitForResumeCommandType = Literal["waitForResume", "pause"] +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default", None) + + class WaitForResumeParams(BaseModel): """Payload required to pause the protocol.""" - message: Optional[str] = Field( + message: str | SkipJsonSchema[None] = Field( None, description="A user-facing message associated with the pause", + json_schema_extra=_remove_default, ) @@ -54,7 +61,7 @@ class WaitForResume( commandType: WaitForResumeCommandType = "waitForResume" params: WaitForResumeParams - result: Optional[WaitForResumeResult] + result: Optional[WaitForResumeResult] = None _ImplementationCls: Type[WaitForResumeImplementation] = WaitForResumeImplementation diff --git a/api/src/opentrons/protocol_engine/errors/error_occurrence.py b/api/src/opentrons/protocol_engine/errors/error_occurrence.py index 4141befe9b8..34f3e1d2ac7 100644 --- a/api/src/opentrons/protocol_engine/errors/error_occurrence.py +++ b/api/src/opentrons/protocol_engine/errors/error_occurrence.py @@ -4,7 +4,7 @@ from datetime import datetime from textwrap import dedent from typing import Any, Dict, Mapping, List, Type, Union, Optional, Sequence -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, ConfigDict from opentrons_shared_data.errors.codes import ErrorCodes from .exceptions import ProtocolEngineError from opentrons_shared_data.errors.exceptions import EnumeratedError @@ -39,6 +39,21 @@ def from_failed( wrappedErrors=wrappedErrors, ) + @staticmethod + def schema_extra(schema: Dict[str, Any], model: object) -> None: + """Append the schema to make the errorCode appear required. + + `errorCode`, `wrappedErrors`, and `errorInfo` have defaults because they are not included in earlier + versions of this model, _and_ this model is loaded directly from + the on-robot store. That means that, without a default, it will + fail to parse. Once a default is defined, the automated schema will + mark this as a non-required field, which is misleading as this is + a response from the server to the client and it will always have an + errorCode defined. This hack is required because it informs the client + that it does not, in fact, have to account for a missing errorCode, wrappedError, or errorInfo. + """ + schema["required"].extend(["errorCode", "wrappedErrors", "errorInfo"]) + id: str = Field(..., description="Unique identifier of this error occurrence.") createdAt: datetime = Field(..., description="When the error occurred.") @@ -145,23 +160,7 @@ def from_failed( default=[], description="Errors that may have caused this one." ) - class Config: - """Customize configuration for this model.""" - - @staticmethod - def schema_extra(schema: Dict[str, Any], model: object) -> None: - """Append the schema to make the errorCode appear required. - - `errorCode`, `wrappedErrors`, and `errorInfo` have defaults because they are not included in earlier - versions of this model, _and_ this model is loaded directly from - the on-robot store. That means that, without a default, it will - fail to parse. Once a default is defined, the automated schema will - mark this as a non-required field, which is misleading as this is - a response from the server to the client and it will always have an - errorCode defined. This hack is required because it informs the client - that it does not, in fact, have to account for a missing errorCode, wrappedError, or errorInfo. - """ - schema["required"].extend(["errorCode", "wrappedErrors", "errorInfo"]) + model_config = ConfigDict(json_schema_extra=schema_extra) # TODO (tz, 7-12-23): move this to exceptions.py when we stop relaying on ErrorOccurrence. @@ -180,4 +179,4 @@ def __init__( self.original_error = original_error -ErrorOccurrence.update_forward_refs() +ErrorOccurrence.model_rebuild() diff --git a/api/src/opentrons/protocol_engine/state/commands.py b/api/src/opentrons/protocol_engine/state/commands.py index 8aa71c9c1f8..e059212e73f 100644 --- a/api/src/opentrons/protocol_engine/state/commands.py +++ b/api/src/opentrons/protocol_engine/state/commands.py @@ -304,7 +304,7 @@ def _handle_queue_command_action(self, action: QueueCommandAction) -> None: # TODO(mc, 2021-06-22): mypy has trouble with this automatic # request > command mapping, figure out how to type precisely # (or wait for a future mypy version that can figure it out). - queued_command = action.request._CommandCls.construct( + queued_command = action.request._CommandCls.model_construct( # type: ignore[call-arg] id=action.command_id, key=( action.request.key @@ -326,7 +326,7 @@ def _handle_queue_command_action(self, action: QueueCommandAction) -> None: def _handle_run_command_action(self, action: RunCommandAction) -> None: prev_entry = self._state.command_history.get(action.command_id) - running_command = prev_entry.command.copy( + running_command = prev_entry.command.model_copy( update={ "status": CommandStatus.RUNNING, "startedAt": action.started_at, @@ -525,7 +525,7 @@ def _update_to_failed( notes: Optional[List[CommandNote]], ) -> None: prev_entry = self._state.command_history.get(command_id) - failed_command = prev_entry.command.copy( + failed_command = prev_entry.command.model_copy( update={ "completedAt": failed_at, "status": CommandStatus.FAILED, @@ -679,7 +679,7 @@ def get_error(self) -> Optional[ErrorOccurrence]: finish_error = self._state.finish_error if run_error and finish_error: - combined_error = ErrorOccurrence.construct( + combined_error = ErrorOccurrence( id=finish_error.id, createdAt=finish_error.createdAt, errorType="RunAndFinishFailed", diff --git a/api/src/opentrons/protocol_engine/state/labware.py b/api/src/opentrons/protocol_engine/state/labware.py index 95b2baa1974..d81d5bfa756 100644 --- a/api/src/opentrons/protocol_engine/state/labware.py +++ b/api/src/opentrons/protocol_engine/state/labware.py @@ -998,11 +998,15 @@ def get_child_gripper_offsets( return None else: return LabwareMovementOffsetData( - pickUpOffset=cast( - LabwareOffsetVector, parsed_offsets[offset_key].pickUpOffset + pickUpOffset=LabwareOffsetVector.construct( + x=parsed_offsets[offset_key].pickUpOffset.x, + y=parsed_offsets[offset_key].pickUpOffset.y, + z=parsed_offsets[offset_key].pickUpOffset.z, ), - dropOffset=cast( - LabwareOffsetVector, parsed_offsets[offset_key].dropOffset + dropOffset=LabwareOffsetVector.construct( + x=parsed_offsets[offset_key].dropOffset.x, + y=parsed_offsets[offset_key].dropOffset.y, + z=parsed_offsets[offset_key].dropOffset.z, ), ) diff --git a/api/src/opentrons/protocol_engine/state/state_summary.py b/api/src/opentrons/protocol_engine/state/state_summary.py index d6b18613071..64f8e2b2737 100644 --- a/api/src/opentrons/protocol_engine/state/state_summary.py +++ b/api/src/opentrons/protocol_engine/state/state_summary.py @@ -28,8 +28,8 @@ class StateSummary(BaseModel): pipettes: List[LoadedPipette] modules: List[LoadedModule] labwareOffsets: List[LabwareOffset] - startedAt: Optional[datetime] - completedAt: Optional[datetime] + startedAt: Optional[datetime] = None + completedAt: Optional[datetime] = None liquids: List[Liquid] = Field(default_factory=list) wells: List[WellInfoSummary] = Field(default_factory=list) files: List[str] = Field(default_factory=list) diff --git a/api/src/opentrons/protocol_engine/types.py b/api/src/opentrons/protocol_engine/types.py index 11f1972e105..2a4ff4bd726 100644 --- a/api/src/opentrons/protocol_engine/types.py +++ b/api/src/opentrons/protocol_engine/types.py @@ -1,30 +1,30 @@ """Public protocol engine value types and models.""" from __future__ import annotations -import re from datetime import datetime from enum import Enum from dataclasses import dataclass from pathlib import Path +from typing import ( + Any, + Dict, + FrozenSet, + List, + Mapping, + NamedTuple, + Optional, + Tuple, + Union, +) + from pydantic import ( + ConfigDict, BaseModel, Field, + RootModel, StrictBool, StrictFloat, StrictInt, StrictStr, - validator, - Extra, -) -from typing import ( - Optional, - Union, - List, - Dict, - Any, - NamedTuple, - Tuple, - FrozenSet, - Mapping, ) from typing_extensions import Literal, TypeGuard @@ -554,7 +554,7 @@ class ModuleDimensions(BaseModel): bareOverallHeight: float overLabwareHeight: float - lidHeight: Optional[float] + lidHeight: Optional[float] = None class Vec3f(BaseModel): @@ -709,8 +709,8 @@ class LoadedModule(BaseModel): id: str model: ModuleModel - location: Optional[DeckSlotLocation] - serialNumber: Optional[str] + location: Optional[DeckSlotLocation] = None + serialNumber: Optional[str] = None class LabwareOffsetLocation(BaseModel): @@ -819,17 +819,10 @@ class LoadedLabware(BaseModel): ) -class HexColor(BaseModel): +class HexColor(RootModel[str]): """Hex color representation.""" - __root__: str - - @validator("__root__") - def _color_is_a_valid_hex(cls, v: str) -> str: - match = re.search(r"^#(?:[0-9a-fA-F]{3,4}){1,2}$", v) - if not match: - raise ValueError("Color is not a valid hex color.") - return v + root: str = Field(pattern=r"^#(?:[0-9a-fA-F]{3,4}){1,2}$") EmptyLiquidId = Literal["EMPTY"] @@ -842,7 +835,7 @@ class Liquid(BaseModel): id: str displayName: str description: str - displayColor: Optional[HexColor] + displayColor: Optional[HexColor] = None class LiquidClassRecord(ByTipTypeSetting, frozen=True): @@ -1051,12 +1044,12 @@ class QuadrantNozzleLayoutConfiguration(BaseModel): ) frontRightNozzle: str = Field( ..., - regex=NOZZLE_NAME_REGEX, + pattern=NOZZLE_NAME_REGEX, description="The front right nozzle in your configuration.", ) backLeftNozzle: str = Field( ..., - regex=NOZZLE_NAME_REGEX, + pattern=NOZZLE_NAME_REGEX, description="The back left nozzle in your configuration.", ) @@ -1186,11 +1179,7 @@ class CustomCommandAnnotation(BaseCommandAnnotation): """Annotates a group of atomic commands in some manner that Opentrons software does not anticipate or originate.""" annotationType: Literal["custom"] = "custom" - - class Config: - """Config to allow extra, non-defined properties.""" - - extra = Extra.allow + model_config = ConfigDict(extra="allow") CommandAnnotation = Union[SecondOrderCommandAnnotation, CustomCommandAnnotation] diff --git a/api/src/opentrons/protocol_reader/extract_labware_definitions.py b/api/src/opentrons/protocol_reader/extract_labware_definitions.py index 2ecb64a8a39..6bf8946404b 100644 --- a/api/src/opentrons/protocol_reader/extract_labware_definitions.py +++ b/api/src/opentrons/protocol_reader/extract_labware_definitions.py @@ -41,7 +41,10 @@ async def extract_labware_definitions( async def _extract_from_labware_file(path: Path) -> LabwareDefinition: - return await anyio.to_thread.run_sync(LabwareDefinition.parse_file, path) + def _do_parse() -> LabwareDefinition: + return LabwareDefinition.model_validate_json(path.read_bytes()) + + return await anyio.to_thread.run_sync(_do_parse) async def _extract_from_json_protocol_file(path: Path) -> List[LabwareDefinition]: diff --git a/api/src/opentrons/protocol_runner/json_file_reader.py b/api/src/opentrons/protocol_runner/json_file_reader.py index 488c28d273b..f318be1db5d 100644 --- a/api/src/opentrons/protocol_runner/json_file_reader.py +++ b/api/src/opentrons/protocol_runner/json_file_reader.py @@ -30,11 +30,17 @@ def read( }, ) if protocol_source.config.schema_version == 6: - return ProtocolSchemaV6.parse_file(protocol_source.main_file) + return ProtocolSchemaV6.model_validate_json( + protocol_source.main_file.read_bytes() + ) elif protocol_source.config.schema_version == 7: - return ProtocolSchemaV7.parse_file(protocol_source.main_file) + return ProtocolSchemaV7.model_validate_json( + protocol_source.main_file.read_bytes() + ) elif protocol_source.config.schema_version == 8: - return ProtocolSchemaV8.parse_file(protocol_source.main_file) + return ProtocolSchemaV8.model_validate_json( + protocol_source.main_file.read_bytes() + ) else: raise ProtocolFilesInvalidError( message=f"{name} is a JSON protocol v{protocol_source.config.schema_version} which this robot cannot execute", diff --git a/api/src/opentrons/protocol_runner/json_translator.py b/api/src/opentrons/protocol_runner/json_translator.py index 767bf058730..f75b0d51348 100644 --- a/api/src/opentrons/protocol_runner/json_translator.py +++ b/api/src/opentrons/protocol_runner/json_translator.py @@ -1,6 +1,7 @@ """Translation of JSON protocol commands into ProtocolEngine commands.""" -from typing import cast, List, Union, Iterator -from pydantic import parse_obj_as, ValidationError as PydanticValidationError + +from typing import List, Union, Iterator +from pydantic import ValidationError as PydanticValidationError, TypeAdapter from opentrons_shared_data.pipette.types import PipetteNameType from opentrons_shared_data.protocol.models import ( @@ -10,6 +11,8 @@ protocol_schema_v7, ProtocolSchemaV8, protocol_schema_v8, + Location, + # CommandSchemaId, ) from opentrons_shared_data import command as command_schema from opentrons_shared_data.errors.exceptions import InvalidProtocolData, PythonException @@ -31,6 +34,15 @@ class CommandTranslatorError(Exception): pass +# Each time a TypeAdapter is instantiated, it will construct a new validator and +# serializer. To improve performance, TypeAdapters are instantiated once. +# See https://docs.pydantic.dev/latest/concepts/performance/#typeadapter-instantiated-once +LabwareLocationAdapter: TypeAdapter[LabwareLocation] = TypeAdapter(LabwareLocation) +CommandAnnotationAdapter: TypeAdapter[CommandAnnotation] = TypeAdapter( + CommandAnnotation +) + + def _translate_labware_command( protocol: ProtocolSchemaV6, command: protocol_schema_v6.Command, @@ -41,6 +53,8 @@ def _translate_labware_command( assert labware_id is not None definition_id = protocol.labware[labware_id].definitionId assert definition_id is not None + + location = command.params.location labware_command = pe_commands.LoadLabwareCreate( params=pe_commands.LoadLabwareParams( labwareId=command.params.labwareId, @@ -48,10 +62,8 @@ def _translate_labware_command( version=protocol.labwareDefinitions[definition_id].version, namespace=protocol.labwareDefinitions[definition_id].namespace, loadName=protocol.labwareDefinitions[definition_id].parameters.loadName, - location=parse_obj_as( - # https://github.com/samuelcolvin/pydantic/issues/1847 - LabwareLocation, # type: ignore[arg-type] - command.params.location, + location=LabwareLocationAdapter.validate_python( + location.dict() if isinstance(location, Location) else location ), ), key=command.key, @@ -70,6 +82,7 @@ def _translate_v7_labware_command( assert command.params.namespace is not None assert command.params.loadName is not None + location = command.params.location labware_command = pe_commands.LoadLabwareCreate( params=pe_commands.LoadLabwareParams( labwareId=command.params.labwareId, @@ -77,10 +90,8 @@ def _translate_v7_labware_command( version=command.params.version, namespace=command.params.namespace, loadName=command.params.loadName, - location=parse_obj_as( - # https://github.com/samuelcolvin/pydantic/issues/1847 - LabwareLocation, # type: ignore[arg-type] - command.params.location, + location=LabwareLocationAdapter.validate_python( + location.dict() if isinstance(location, Location) else location ), ), key=command.key, @@ -98,10 +109,14 @@ def _translate_module_command( # load module command must contain module_id. modules cannot be None. assert module_id is not None assert modules is not None + + location = command.params.location translated_obj = pe_commands.LoadModuleCreate( params=pe_commands.LoadModuleParams( model=ModuleModel(modules[module_id].model), - location=DeckSlotLocation.parse_obj(command.params.location), + location=DeckSlotLocation.parse_obj( + location.dict() if isinstance(location, Location) else location + ), moduleId=command.params.moduleId, ), key=command.key, @@ -117,10 +132,13 @@ def _translate_v7_module_command( # load module command must contain module_id. modules cannot be None. assert module_id is not None assert command.params.model is not None + location = command.params.location translated_obj = pe_commands.LoadModuleCreate( params=pe_commands.LoadModuleParams( model=ModuleModel(command.params.model), - location=DeckSlotLocation.parse_obj(command.params.location), + location=DeckSlotLocation.parse_obj( + location.dict() if isinstance(location, Location) else location + ), moduleId=command.params.moduleId, ), key=command.key, @@ -171,7 +189,7 @@ def _translate_simple_command( protocol_schema_v6.Command, protocol_schema_v7.Command, protocol_schema_v8.Command, - ] + ], ) -> pe_commands.CommandCreate: dict_command = command.dict(exclude_none=True) @@ -182,15 +200,7 @@ def _translate_simple_command( else: dict_command["commandType"] = "waitForDuration" - translated_obj = cast( - pe_commands.CommandCreate, - parse_obj_as( - # https://github.com/samuelcolvin/pydantic/issues/1847 - pe_commands.CommandCreate, # type: ignore[arg-type] - dict_command, - ), - ) - return translated_obj + return pe_commands.CommandCreateAdapter.validate_python(dict_command) class JsonTranslator: @@ -207,7 +217,7 @@ def translate_liquids( id=liquid_id, displayName=liquid.displayName, description=liquid.description, - displayColor=HexColor(__root__=liquid.displayColor) + displayColor=HexColor(liquid.displayColor) if liquid.displayColor is not None else None, ) @@ -294,8 +304,7 @@ def translate_command_annotations( return [] else: command_annotations: List[CommandAnnotation] = [ - parse_obj_as( - CommandAnnotation, # type: ignore[arg-type] + CommandAnnotationAdapter.validate_python( command_annotation.dict(), ) for command_annotation in protocol.commandAnnotations diff --git a/api/src/opentrons/protocol_runner/legacy_command_mapper.py b/api/src/opentrons/protocol_runner/legacy_command_mapper.py index 27b1c7ea331..1dbf99e6e6e 100644 --- a/api/src/opentrons/protocol_runner/legacy_command_mapper.py +++ b/api/src/opentrons/protocol_runner/legacy_command_mapper.py @@ -181,7 +181,9 @@ def map_command( # noqa: C901 update={ "result": pe_commands.PickUpTipResult.construct( tipVolume=command["payload"]["location"].max_volume, # type: ignore[typeddict-item] - tipLength=command["payload"]["instrument"].hw_pipette["tip_length"], # type: ignore[typeddict-item] + tipLength=command["payload"]["instrument"].hw_pipette[ # type: ignore[typeddict-item] + "tip_length" + ], position=pe_types.DeckPoint(x=0, y=0, z=0), ), "status": pe_commands.CommandStatus.SUCCEEDED, @@ -528,7 +530,7 @@ def _build_liquid_handling( status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - # Don't .construct params, because we want to validate + # Don't .model_construct params, because we want to validate # volume and flowRate. params=pe_commands.DispenseParams( pipetteId=pipette_id, diff --git a/api/src/opentrons/protocols/labware.py b/api/src/opentrons/protocols/labware.py index 2fcffaaf2d4..d3159ee5d9f 100644 --- a/api/src/opentrons/protocols/labware.py +++ b/api/src/opentrons/protocols/labware.py @@ -3,7 +3,6 @@ import logging import json import os - from pathlib import Path from typing import Any, AnyStr, Dict, Optional, Union, List @@ -139,14 +138,24 @@ def verify_definition( :raises jsonschema.ValidationError: If the definition is not valid. :returns: The parsed definition """ - schema_body = load_shared_data("labware/schemas/2.json").decode("utf-8") - labware_schema_v2 = json.loads(schema_body) + schemata_by_version = { + 2: json.loads(load_shared_data("labware/schemas/2.json").decode("utf-8")), + 3: json.loads(load_shared_data("labware/schemas/3.json").decode("utf-8")), + } if isinstance(contents, dict): to_return = contents else: to_return = json.loads(contents) - jsonschema.validate(to_return, labware_schema_v2) + try: + schema_version = to_return["schemaVersion"] + schema = schemata_by_version[schema_version] + except KeyError: + raise RuntimeError( + f'Invalid or unknown labware schema version {to_return.get("schemaVersion", None)}' + ) + jsonschema.validate(to_return, schema) + # we can type ignore this because if it passes the jsonschema it has # the correct structure return to_return # type: ignore[return-value] @@ -201,7 +210,6 @@ def _get_labware_definition_from_bundle( def _get_standard_labware_definition( load_name: str, namespace: Optional[str] = None, version: Optional[int] = None ) -> LabwareDefinition: - if version is None: checked_version = 1 else: diff --git a/api/src/opentrons/protocols/models/json_protocol.py b/api/src/opentrons/protocols/models/json_protocol.py index 979d0192f62..ef2fec8823d 100644 --- a/api/src/opentrons/protocols/models/json_protocol.py +++ b/api/src/opentrons/protocols/models/json_protocol.py @@ -9,7 +9,7 @@ from typing import Any, Dict, List, Optional, Union -from pydantic import BaseModel, Extra, Field +from pydantic import ConfigDict, BaseModel, Field from typing_extensions import Literal from opentrons_shared_data.labware.labware_definition import LabwareDefinition @@ -75,8 +75,7 @@ class Metadata(BaseModel): Optional metadata about the protocol """ - class Config: - extra = Extra.allow + model_config = ConfigDict(extra="allow") protocolName: Optional[str] = Field( None, description="A short, human-readable name for the protocol" @@ -574,8 +573,7 @@ class Pipettes(BaseModel): Fields describing an individual pipette """ - class Config: - extra = Extra.allow + model_config = ConfigDict(extra="allow") mount: Literal["left", "right"] = Field( ..., description="Where the pipette is mounted" @@ -592,8 +590,7 @@ class Labware(BaseModel): Fields describing a single labware on the deck """ - class Config: - extra = Extra.allow + model_config = ConfigDict(extra="allow") slot: str = Field( ..., @@ -616,8 +613,7 @@ class Modules(BaseModel): Fields describing a single module on the deck """ - class Config: - extra = Extra.allow + model_config = ConfigDict(extra="allow") slot: str = Field( ..., diff --git a/api/src/opentrons/types.py b/api/src/opentrons/types.py index 1f73d63c8c6..09e138513c1 100644 --- a/api/src/opentrons/types.py +++ b/api/src/opentrons/types.py @@ -160,7 +160,7 @@ def __iter__(self) -> Iterator[Union[Point, LabwareLike]]: point, labware = location some_function_taking_both(*location) """ - return iter((self._point, self._labware)) # type: ignore [arg-type] + return iter((self._point, self._labware)) def __eq__(self, other: object) -> bool: return ( diff --git a/api/tests/opentrons/calibration_storage/test_deck_attitude.py b/api/tests/opentrons/calibration_storage/test_deck_attitude.py index bbb832651d1..bce3ae02809 100644 --- a/api/tests/opentrons/calibration_storage/test_deck_attitude.py +++ b/api/tests/opentrons/calibration_storage/test_deck_attitude.py @@ -57,7 +57,7 @@ def test_save_ot2_deck_attitude(ot_config_tempdir: Any) -> None: "pip1", "mytiprack", ) - assert get_robot_deck_attitude() != {} + assert get_robot_deck_attitude() is not None def test_save_ot3_deck_attitude(ot_config_tempdir: Any) -> None: diff --git a/api/tests/opentrons/hardware_control/instruments/test_instrument_calibration.py b/api/tests/opentrons/hardware_control/instruments/test_instrument_calibration.py index 6f9ad72c460..fd746ed9743 100644 --- a/api/tests/opentrons/hardware_control/instruments/test_instrument_calibration.py +++ b/api/tests/opentrons/hardware_control/instruments/test_instrument_calibration.py @@ -55,10 +55,10 @@ def tip_rack_dict() -> LabwareDefDict: @pytest.fixture def tip_rack_model() -> LabwareDefinition: """Get a tip rack Pydantic model definition value object.""" - return LabwareDefinition.construct( # type: ignore[call-arg] + return LabwareDefinition.model_construct( # type: ignore[call-arg] namespace="test", version=1, - parameters=Parameters.construct( # type: ignore[call-arg] + parameters=Parameters.model_construct( # type: ignore[call-arg] loadName="cool-labware", tipOverlap=None, # add a None value to validate serialization to dictionary ), diff --git a/api/tests/opentrons/hardware_control/test_gripper.py b/api/tests/opentrons/hardware_control/test_gripper.py index f084a11df89..7fc54791e33 100644 --- a/api/tests/opentrons/hardware_control/test_gripper.py +++ b/api/tests/opentrons/hardware_control/test_gripper.py @@ -105,7 +105,12 @@ def test_reload_instrument_cal_ot3_conf_changed( jaw_max_offset=15, ) new_conf = fake_gripper_conf.copy( - update={"grip_force_profile": {"default_grip_force": 1}} + update={ + "grip_force_profile": fake_gripper_conf.grip_force_profile.copy( + update={"default_grip_force": 1} + ) + }, + deep=True, ) assert new_conf != old_gripper.config diff --git a/api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py b/api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py index 352dcb35c58..73f39006299 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py @@ -1,4 +1,5 @@ """Test for the ProtocolEngine-based instrument API core.""" + from typing import cast, Optional from opentrons_shared_data.errors.exceptions import PipetteLiquidNotFoundError @@ -99,7 +100,7 @@ def subject( ) -> InstrumentCore: """Get a InstrumentCore test subject with its dependencies mocked out.""" decoy.when(mock_engine_client.state.pipettes.get("abc123")).then_return( - LoadedPipette.construct(mount=MountType.LEFT) # type: ignore[call-arg] + LoadedPipette.model_construct(mount=MountType.LEFT) # type: ignore[call-arg] ) decoy.when(mock_engine_client.state.pipettes.get_flow_rates("abc123")).then_return( @@ -130,7 +131,7 @@ def test_get_pipette_name( ) -> None: """It should get the pipette's load name.""" decoy.when(mock_engine_client.state.pipettes.get("abc123")).then_return( - LoadedPipette.construct(pipetteName=PipetteNameType.P300_SINGLE) # type: ignore[call-arg] + LoadedPipette.model_construct(pipetteName=PipetteNameType.P300_SINGLE) # type: ignore[call-arg] ) result = subject.get_pipette_name() @@ -143,7 +144,7 @@ def test_get_mount( ) -> None: """It should get the pipette's mount.""" decoy.when(mock_engine_client.state.pipettes.get("abc123")).then_return( - LoadedPipette.construct(mount=MountType.LEFT) # type: ignore[call-arg] + LoadedPipette.model_construct(mount=MountType.LEFT) # type: ignore[call-arg] ) result = subject.get_mount() @@ -161,7 +162,7 @@ def test_get_hardware_state( pipette_dict = cast(PipetteDict, {"display_name": "Cool Pipette", "has_tip": True}) decoy.when(mock_engine_client.state.pipettes.get("abc123")).then_return( - LoadedPipette.construct(mount=MountType.LEFT) # type: ignore[call-arg] + LoadedPipette.model_construct(mount=MountType.LEFT) # type: ignore[call-arg] ) decoy.when(mock_sync_hardware.get_attached_instrument(Mount.LEFT)).then_return( pipette_dict @@ -530,7 +531,7 @@ def test_aspirate_from_well( pipette_id="abc123", labware_id="123abc", well_name="my cool well", - well_location=WellLocation( + well_location=LiquidHandlingWellLocation( origin=WellOrigin.TOP, offset=WellOffset(x=3, y=2, z=1) ), ), @@ -828,7 +829,7 @@ def test_dispense_to_well( pipette_id="abc123", labware_id="123abc", well_name="my cool well", - well_location=WellLocation( + well_location=LiquidHandlingWellLocation( origin=WellOrigin.TOP, offset=WellOffset(x=3, y=2, z=1) ), ), @@ -1438,7 +1439,7 @@ def test_detect_liquid_presence( ) ) ).then_return( - cmd.TryLiquidProbeResult.construct( + cmd.TryLiquidProbeResult.model_construct( z_position=returned_from_engine, position=object(), # type: ignore[arg-type] ) diff --git a/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py b/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py index 6f4458f87ff..beca8fe99d1 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py @@ -35,7 +35,7 @@ @pytest.fixture def labware_definition() -> LabwareDefinition: """Get a LabwareDefinition value object to use in tests.""" - return LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + return LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] @pytest.fixture @@ -59,10 +59,10 @@ def subject(mock_engine_client: EngineClient) -> LabwareCore: @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] namespace="hello", version=42, - parameters=LabwareDefinitionParameters.construct(loadName="world"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="world"), # type: ignore[call-arg] ordering=[], ) ], @@ -76,14 +76,14 @@ def test_get_load_params(subject: LabwareCore) -> None: @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] namespace="hello", version=42, - parameters=LabwareDefinitionParameters.construct(loadName="world"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="world"), # type: ignore[call-arg] ordering=[], - metadata=LabwareDefinitionMetadata.construct( + metadata=LabwareDefinitionMetadata.model_construct( # type: ignore[call-arg] displayName="what a cool labware" - ), # type: ignore[call-arg] + ), ) ], ) @@ -130,10 +130,10 @@ def test_set_calibration_succeeds_in_ok_location( @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] namespace="hello", version=42, - parameters=LabwareDefinitionParameters.construct(loadName="world"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="world"), # type: ignore[call-arg] ordering=[], ) ], @@ -164,9 +164,9 @@ def test_set_calibration_fails_in_bad_location( @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] namespace="hello", - parameters=LabwareDefinitionParameters.construct(loadName="world"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="world"), # type: ignore[call-arg] ordering=[], allowedRoles=[], stackingOffsetWithLabware={}, @@ -208,9 +208,9 @@ def test_get_user_display_name(decoy: Decoy, mock_engine_client: EngineClient) - @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[], - metadata=LabwareDefinitionMetadata.construct( # type: ignore[call-arg] + metadata=LabwareDefinitionMetadata.model_construct( # type: ignore[call-arg] displayName="Cool Display Name" ), ) @@ -226,8 +226,10 @@ def test_get_display_name(subject: LabwareCore) -> None: @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] - parameters=LabwareDefinitionParameters.construct(loadName="load-name"), # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct( # type: ignore[call-arg] + loadName="load-name" + ), ), ], ) @@ -254,9 +256,9 @@ def test_get_name_display_name(decoy: Decoy, mock_engine_client: EngineClient) - @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[], - parameters=LabwareDefinitionParameters.construct(isTiprack=True), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(isTiprack=True), # type: ignore[call-arg] ) ], ) @@ -271,13 +273,13 @@ def test_is_tip_rack(subject: LabwareCore) -> None: argnames=["labware_definition", "expected_result"], argvalues=[ ( - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[], allowedRoles=[LabwareRole.adapter] ), True, ), ( - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[], allowedRoles=[LabwareRole.labware] ), False, @@ -294,7 +296,7 @@ def test_is_adapter(expected_result: bool, subject: LabwareCore) -> None: @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[["A1", "B1"], ["A2", "B2"]], ) ], @@ -354,9 +356,9 @@ def test_get_next_tip( @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[], - parameters=LabwareDefinitionParameters.construct(isTiprack=True), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(isTiprack=True), # type: ignore[call-arg] ) ], ) @@ -371,10 +373,10 @@ def test_reset_tips( @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[], - parameters=LabwareDefinitionParameters.construct(isTiprack=False), # type: ignore[call-arg] - metadata=LabwareDefinitionMetadata.construct( # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(isTiprack=False), # type: ignore[call-arg] + metadata=LabwareDefinitionMetadata.model_construct( # type: ignore[call-arg] displayName="Cool Display Name" ), ) @@ -430,9 +432,9 @@ def test_get_calibrated_offset( @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[], - parameters=LabwareDefinitionParameters.construct(quirks=["quirk"]), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(quirks=["quirk"]), # type: ignore[call-arg] ) ], ) diff --git a/api/tests/opentrons/protocol_api/core/engine/test_module_core.py b/api/tests/opentrons/protocol_api/core/engine/test_module_core.py index f18a672afb8..a1310999d72 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_module_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_module_core.py @@ -1,4 +1,5 @@ """Tests for opentrons.protocol_api.core.engine.ModuleCore.""" + import pytest import inspect from decoy import Decoy @@ -107,7 +108,7 @@ def test_get_display_name( decoy: Decoy, subject: ModuleCore, mock_engine_client: EngineClient ) -> None: """It should return the module display name.""" - module_definition = ModuleDefinition.construct( # type: ignore[call-arg] + module_definition = ModuleDefinition.model_construct( # type: ignore[call-arg] displayName="abra kadabra", ) decoy.when(mock_engine_client.state.modules.get_definition("1234")).then_return( diff --git a/api/tests/opentrons/protocol_api/core/engine/test_protocol_core.py b/api/tests/opentrons/protocol_api/core/engine/test_protocol_core.py index 1cf6bc57049..6b5065f98c9 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_protocol_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_protocol_core.py @@ -1,4 +1,5 @@ """Test for the ProtocolEngine-based protocol API core.""" + import inspect from typing import Optional, Type, cast, Tuple @@ -179,7 +180,7 @@ def subject( decoy.when( mock_engine_client.state.labware.get_definition("fixed-trash-123") ).then_return( - LabwareDefinition.construct(ordering=[["A1"]]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[["A1"]]) # type: ignore[call-arg] ) return ProtocolCore( @@ -358,13 +359,13 @@ def test_load_labware( ).then_return( commands.LoadLabwareResult( labwareId="abc123", - definition=LabwareDefinition.construct(), # type: ignore[call-arg] + definition=LabwareDefinition.model_construct(), # type: ignore[call-arg] offsetId=None, ) ) decoy.when(mock_engine_client.state.labware.get_definition("abc123")).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) result = subject.load_labware( @@ -394,7 +395,7 @@ def test_load_labware( slot_name=DeckSlotName.SLOT_5, ) ).then_return( - LoadedLabware.construct(id="abc123") # type: ignore[call-arg] + LoadedLabware.model_construct(id="abc123") # type: ignore[call-arg] ) assert subject.get_slot_item(DeckSlotName.SLOT_5) is result @@ -432,13 +433,13 @@ def test_load_labware_on_staging_slot( ).then_return( commands.LoadLabwareResult( labwareId="abc123", - definition=LabwareDefinition.construct(), # type: ignore[call-arg] + definition=LabwareDefinition.model_construct(), # type: ignore[call-arg] offsetId=None, ) ) decoy.when(mock_engine_client.state.labware.get_definition("abc123")).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) result = subject.load_labware( @@ -468,7 +469,7 @@ def test_load_labware_on_staging_slot( slot_name=StagingSlotName.SLOT_B4, ) ).then_return( - LoadedLabware.construct(id="abc123") # type: ignore[call-arg] + LoadedLabware.model_construct(id="abc123") # type: ignore[call-arg] ) assert subject.get_slot_item(StagingSlotName.SLOT_B4) is result @@ -509,13 +510,13 @@ def test_load_labware_on_labware( ).then_return( commands.LoadLabwareResult( labwareId="abc123", - definition=LabwareDefinition.construct(), # type: ignore[call-arg] + definition=LabwareDefinition.model_construct(), # type: ignore[call-arg] offsetId=None, ) ) decoy.when(mock_engine_client.state.labware.get_definition("abc123")).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) decoy.when( @@ -579,13 +580,13 @@ def test_load_labware_off_deck( ).then_return( commands.LoadLabwareResult( labwareId="abc123", - definition=LabwareDefinition.construct(), # type: ignore[call-arg] + definition=LabwareDefinition.model_construct(), # type: ignore[call-arg] offsetId=None, ) ) decoy.when(mock_engine_client.state.labware.get_definition("abc123")).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) result = subject.load_labware( @@ -642,13 +643,13 @@ def test_load_adapter( ).then_return( commands.LoadLabwareResult( labwareId="abc123", - definition=LabwareDefinition.construct(), # type: ignore[call-arg] + definition=LabwareDefinition.model_construct(), # type: ignore[call-arg] offsetId=None, ) ) decoy.when(mock_engine_client.state.labware.get_definition("abc123")).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) result = subject.load_adapter( @@ -677,7 +678,7 @@ def test_load_adapter( slot_name=DeckSlotName.SLOT_5, ) ).then_return( - LoadedLabware.construct(id="abc123") # type: ignore[call-arg] + LoadedLabware.model_construct(id="abc123") # type: ignore[call-arg] ) assert subject.get_slot_item(DeckSlotName.SLOT_5) is result @@ -714,13 +715,13 @@ def test_load_adapter_on_staging_slot( ).then_return( commands.LoadLabwareResult( labwareId="abc123", - definition=LabwareDefinition.construct(), # type: ignore[call-arg] + definition=LabwareDefinition.model_construct(), # type: ignore[call-arg] offsetId=None, ) ) decoy.when(mock_engine_client.state.labware.get_definition("abc123")).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) result = subject.load_adapter( @@ -749,7 +750,7 @@ def test_load_adapter_on_staging_slot( slot_name=StagingSlotName.SLOT_B4, ) ).then_return( - LoadedLabware.construct(id="abc123") # type: ignore[call-arg] + LoadedLabware.model_construct(id="abc123") # type: ignore[call-arg] ) assert subject.get_slot_item(StagingSlotName.SLOT_B4) is result @@ -860,7 +861,7 @@ def test_move_labware( decoy.when( mock_engine_client.state.labware.get_definition("labware-id") ).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) labware = LabwareCore(labware_id="labware-id", engine_client=mock_engine_client) subject.move_labware( @@ -903,7 +904,7 @@ def test_move_labware_on_staging_slot( decoy.when( mock_engine_client.state.labware.get_definition("labware-id") ).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) labware = LabwareCore(labware_id="labware-id", engine_client=mock_engine_client) subject.move_labware( @@ -944,7 +945,7 @@ def test_move_labware_on_non_connected_module( decoy.when( mock_engine_client.state.labware.get_definition("labware-id") ).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) labware = LabwareCore(labware_id="labware-id", engine_client=mock_engine_client) non_connected_module_core = NonConnectedModuleCore( @@ -990,7 +991,7 @@ def test_move_labware_off_deck( decoy.when( mock_engine_client.state.labware.get_definition("labware-id") ).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) labware = LabwareCore(labware_id="labware-id", engine_client=mock_engine_client) @@ -1056,13 +1057,13 @@ def test_load_labware_on_module( ).then_return( commands.LoadLabwareResult( labwareId="abc123", - definition=LabwareDefinition.construct(), # type: ignore[call-arg] + definition=LabwareDefinition.model_construct(), # type: ignore[call-arg] offsetId=None, ) ) decoy.when(mock_engine_client.state.labware.get_definition("abc123")).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) module_core = ModuleCore( @@ -1133,13 +1134,13 @@ def test_load_labware_on_non_connected_module( ).then_return( commands.LoadLabwareResult( labwareId="abc123", - definition=LabwareDefinition.construct(), # type: ignore[call-arg] + definition=LabwareDefinition.model_construct(), # type: ignore[call-arg] offsetId=None, ) ) decoy.when(mock_engine_client.state.labware.get_definition("abc123")).then_return( - LabwareDefinition.construct(ordering=[]) # type: ignore[call-arg] + LabwareDefinition.model_construct(ordering=[]) # type: ignore[call-arg] ) non_connected_module_core = NonConnectedModuleCore( @@ -1185,7 +1186,7 @@ def test_add_labware_definition( """It should add a labware definition to the engine.""" decoy.when( mock_engine_client.add_labware_definition( - definition=LabwareDefinition.parse_obj(minimal_labware_def) + definition=LabwareDefinition.model_validate(minimal_labware_def) ) ).then_return(LabwareUri("hello/world/123")) @@ -1261,7 +1262,7 @@ def test_load_module( robot_type: RobotType, ) -> None: """It should issue a load module engine command.""" - definition = ModuleDefinition.construct() # type: ignore[call-arg] + definition = ModuleDefinition.model_construct() # type: ignore[call-arg] mock_hw_mod_1 = decoy.mock(cls=AbstractModule) mock_hw_mod_2 = decoy.mock(cls=AbstractModule) @@ -1315,7 +1316,7 @@ def test_load_module( slot_name=slot_name, ) ).then_return( - LoadedModule.construct(id="abc123") # type: ignore[call-arg] + LoadedModule.model_construct(id="abc123") # type: ignore[call-arg] ) decoy.when(mock_engine_client.state.labware.get_id_by_module("abc123")).then_raise( LabwareNotLoadedOnModuleError("oh no") @@ -1333,7 +1334,7 @@ def test_load_mag_block( subject: ProtocolCore, ) -> None: """It should issue a load module engine command.""" - definition = ModuleDefinition.construct() # type: ignore[call-arg] + definition = ModuleDefinition.model_construct() # type: ignore[call-arg] decoy.when(mock_engine_client.state.config.robot_type).then_return("OT-3 Standard") @@ -1378,7 +1379,7 @@ def test_load_mag_block( slot_name=DeckSlotName.SLOT_1, ) ).then_return( - LoadedModule.construct(id="abc123") # type: ignore[call-arg] + LoadedModule.model_construct(id="abc123") # type: ignore[call-arg] ) decoy.when(mock_engine_client.state.labware.get_id_by_module("abc123")).then_raise( LabwareNotLoadedOnModuleError("oh no") @@ -1413,7 +1414,7 @@ def test_load_module_thermocycler_with_no_location( expected_slot: DeckSlotName, ) -> None: """It should issue a load module engine command with location at 7.""" - definition = ModuleDefinition.construct() # type: ignore[call-arg] + definition = ModuleDefinition.model_construct() # type: ignore[call-arg] mock_hw_mod = decoy.mock(cls=AbstractModule) decoy.when(mock_hw_mod.device_info).then_return({"serial": "xyz789"}) @@ -1670,11 +1671,11 @@ def test_add_liquid( subject: ProtocolCore, ) -> None: """It should return the created liquid.""" - liquid = PE_Liquid.construct( + liquid = PE_Liquid.model_construct( id="water-id", displayName="water", description="water desc", - displayColor=HexColor(__root__="#fff"), + displayColor=HexColor("#fff"), ) expected_result = Liquid( diff --git a/api/tests/opentrons/protocol_api/core/engine/test_well_core.py b/api/tests/opentrons/protocol_api/core/engine/test_well_core.py index 31b562f7e81..6e1912f0aec 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_well_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_well_core.py @@ -1,4 +1,5 @@ """Test for the ProtocolEngine-based well API core.""" + import inspect import pytest @@ -49,7 +50,7 @@ def api_version() -> APIVersion: @pytest.fixture def well_definition() -> WellDefinition: """Get a partial WellDefinition value object.""" - return WellDefinition.construct() # type: ignore[call-arg] + return WellDefinition.model_construct() # type: ignore[call-arg] @pytest.fixture @@ -93,7 +94,7 @@ def test_display_name( @pytest.mark.parametrize( "well_definition", - [WellDefinition.construct(totalLiquidVolume=101)], # type: ignore[call-arg] + [WellDefinition.model_construct(totalLiquidVolume=101)], # type: ignore[call-arg] ) def test_max_volume(subject: WellCore) -> None: """It should have a max volume.""" @@ -192,7 +193,7 @@ def test_load_liquid( @pytest.mark.parametrize( "well_definition", - [WellDefinition.construct(diameter=123.4)], # type: ignore[call-arg] + [WellDefinition.model_construct(diameter=123.4)], # type: ignore[call-arg] ) def test_diameter(subject: WellCore) -> None: """It should get the diameter.""" @@ -201,7 +202,7 @@ def test_diameter(subject: WellCore) -> None: @pytest.mark.parametrize( "well_definition", - [WellDefinition.construct(xDimension=567.8)], # type: ignore[call-arg] + [WellDefinition.model_construct(xDimension=567.8)], # type: ignore[call-arg] ) def test_length(subject: WellCore) -> None: """It should get the length.""" @@ -210,7 +211,7 @@ def test_length(subject: WellCore) -> None: @pytest.mark.parametrize( "well_definition", - [WellDefinition.construct(yDimension=987.6)], # type: ignore[call-arg] + [WellDefinition.model_construct(yDimension=987.6)], # type: ignore[call-arg] ) def test_width(subject: WellCore) -> None: """It should get the width.""" @@ -219,7 +220,7 @@ def test_width(subject: WellCore) -> None: @pytest.mark.parametrize( "well_definition", - [WellDefinition.construct(depth=42.0)], # type: ignore[call-arg] + [WellDefinition.model_construct(depth=42.0)], # type: ignore[call-arg] ) def test_depth(subject: WellCore) -> None: """It should get the depth.""" diff --git a/api/tests/opentrons/protocol_api/test_liquid_class_properties.py b/api/tests/opentrons/protocol_api/test_liquid_class_properties.py index f335cb385bc..94e6dd49205 100644 --- a/api/tests/opentrons/protocol_api/test_liquid_class_properties.py +++ b/api/tests/opentrons/protocol_api/test_liquid_class_properties.py @@ -17,7 +17,7 @@ def test_build_aspirate_settings() -> None: """It should convert the shared data aspirate settings to the PAPI type.""" fixture_data = load_shared_data("liquid-class/fixtures/1/fixture_glycerol50.json") - liquid_class_model = LiquidClassSchemaV1.parse_raw(fixture_data) + liquid_class_model = LiquidClassSchemaV1.model_validate_json(fixture_data) aspirate_data = liquid_class_model.byPipette[0].byTipType[0].aspirate aspirate_properties = build_aspirate_properties(aspirate_data) @@ -61,7 +61,7 @@ def test_build_aspirate_settings() -> None: def test_build_single_dispense_settings() -> None: """It should convert the shared data single dispense settings to the PAPI type.""" fixture_data = load_shared_data("liquid-class/fixtures/1/fixture_glycerol50.json") - liquid_class_model = LiquidClassSchemaV1.parse_raw(fixture_data) + liquid_class_model = LiquidClassSchemaV1.model_validate_json(fixture_data) single_dispense_data = liquid_class_model.byPipette[0].byTipType[0].singleDispense single_dispense_properties = build_single_dispense_properties(single_dispense_data) @@ -118,7 +118,7 @@ def test_build_single_dispense_settings() -> None: def test_build_multi_dispense_settings() -> None: """It should convert the shared data multi dispense settings to the PAPI type.""" fixture_data = load_shared_data("liquid-class/fixtures/1/fixture_glycerol50.json") - liquid_class_model = LiquidClassSchemaV1.parse_raw(fixture_data) + liquid_class_model = LiquidClassSchemaV1.model_validate_json(fixture_data) multi_dispense_data = liquid_class_model.byPipette[0].byTipType[0].multiDispense assert multi_dispense_data is not None diff --git a/api/tests/opentrons/protocol_api/test_validation.py b/api/tests/opentrons/protocol_api/test_validation.py index 342e197535b..ce12d1a8f53 100644 --- a/api/tests/opentrons/protocol_api/test_validation.py +++ b/api/tests/opentrons/protocol_api/test_validation.py @@ -1,4 +1,5 @@ """Tests for Protocol API input validation.""" + from typing import ContextManager, List, Type, Union, Optional, Dict, Sequence, Any from contextlib import nullcontext as do_not_raise @@ -223,7 +224,9 @@ def test_ensure_deck_slot_invalid( """It should raise an exception if given an invalid name.""" with pytest.raises(expected_error_type, match=expected_error_match): subject.ensure_and_convert_deck_slot( - input_value, input_api_version, input_robot_type # type: ignore[arg-type] + input_value, # type: ignore[arg-type] + input_api_version, + input_robot_type, ) @@ -243,23 +246,23 @@ def test_ensure_lowercase_name_invalid() -> None: ("definition", "expected_raise"), [ ( - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=[LabwareRole.labware], - parameters=LabwareDefinitionParameters.construct(loadName="Foo"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="Foo"), # type: ignore[call-arg] ), do_not_raise(), ), ( - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=[], - parameters=LabwareDefinitionParameters.construct(loadName="Foo"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="Foo"), # type: ignore[call-arg] ), do_not_raise(), ), ( - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=[LabwareRole.adapter], - parameters=LabwareDefinitionParameters.construct(loadName="Foo"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="Foo"), # type: ignore[call-arg] ), pytest.raises(subject.LabwareDefinitionIsNotLabwareError), ), @@ -277,23 +280,23 @@ def test_ensure_definition_is_labware( ("definition", "expected_raise"), [ ( - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=[LabwareRole.adapter], - parameters=LabwareDefinitionParameters.construct(loadName="Foo"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="Foo"), # type: ignore[call-arg] ), do_not_raise(), ), ( - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=[], - parameters=LabwareDefinitionParameters.construct(loadName="Foo"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="Foo"), # type: ignore[call-arg] ), pytest.raises(subject.LabwareDefinitionIsNotAdapterError), ), ( - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=[LabwareRole.labware], - parameters=LabwareDefinitionParameters.construct(loadName="Foo"), # type: ignore[call-arg] + parameters=LabwareDefinitionParameters.model_construct(loadName="Foo"), # type: ignore[call-arg] ), pytest.raises(subject.LabwareDefinitionIsNotAdapterError), ), @@ -547,7 +550,8 @@ def test_validate_with_wrong_location() -> None: """Should raise a LocationTypeError.""" with pytest.raises(subject.LocationTypeError): subject.validate_location( - location=42, last_location=None # type: ignore[arg-type] + location=42, # type: ignore[arg-type] + last_location=None, ) diff --git a/api/tests/opentrons/protocol_engine/clients/test_child_thread_transport.py b/api/tests/opentrons/protocol_engine/clients/test_child_thread_transport.py index 9cbd03c3ec8..700f11ff190 100644 --- a/api/tests/opentrons/protocol_engine/clients/test_child_thread_transport.py +++ b/api/tests/opentrons/protocol_engine/clients/test_child_thread_transport.py @@ -1,4 +1,5 @@ """Tests for am ChildThreadTransport.""" + import threading from asyncio import get_running_loop from datetime import datetime @@ -104,7 +105,7 @@ async def test_call_method( subject: ChildThreadTransport, ) -> None: """It should call a synchronous method in a thread-safe manner.""" - labware_def = LabwareDefinition.construct(namespace="hello") # type: ignore[call-arg] + labware_def = LabwareDefinition.model_construct(namespace="hello") # type: ignore[call-arg] labware_uri = LabwareUri("hello/world/123") calling_thread_id = None diff --git a/api/tests/opentrons/protocol_engine/clients/test_sync_client.py b/api/tests/opentrons/protocol_engine/clients/test_sync_client.py index 03d6912371c..628e23cc052 100644 --- a/api/tests/opentrons/protocol_engine/clients/test_sync_client.py +++ b/api/tests/opentrons/protocol_engine/clients/test_sync_client.py @@ -12,6 +12,7 @@ import pytest from decoy import Decoy + from opentrons_shared_data.labware.types import LabwareUri from opentrons_shared_data.labware.labware_definition import LabwareDefinition @@ -61,7 +62,7 @@ def test_execute_command_without_recovery( result_from_transport ) result_from_subject = subject.execute_command_without_recovery(params) - assert result_from_subject == result_from_transport + assert result_from_subject == result_from_transport # type: ignore[comparison-overlap] def test_add_labware_definition( @@ -70,7 +71,7 @@ def test_add_labware_definition( subject: SyncClient, ) -> None: """It should add a labware definition.""" - labware_definition = LabwareDefinition.construct(namespace="hello") # type: ignore[call-arg] + labware_definition = LabwareDefinition.model_construct(namespace="hello") # type: ignore[call-arg] expected_labware_uri = LabwareUri("hello/world/123") decoy.when( @@ -108,7 +109,7 @@ def test_add_liquid( subject: SyncClient, ) -> None: """It should add a liquid to engine state.""" - liquid = Liquid.construct(displayName="water") # type: ignore[call-arg] + liquid = Liquid.model_construct(displayName="water") # type: ignore[call-arg] decoy.when( transport.call_method( diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_labware.py b/api/tests/opentrons/protocol_engine/commands/test_move_labware.py index 49e3c4f5471..2036bda558a 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_labware.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_labware.py @@ -1,4 +1,5 @@ """Test the ``moveLabware`` command.""" + from datetime import datetime import inspect from unittest.mock import sentinel @@ -6,13 +7,13 @@ import pytest from decoy import Decoy, matchers +from opentrons_shared_data.labware.labware_definition import Parameters, Dimensions from opentrons_shared_data.errors.exceptions import ( EnumeratedError, FailedGripperPickupError, LabwareDroppedError, StallOrCollisionDetectedError, ) -from opentrons_shared_data.labware.labware_definition import Parameters, Dimensions from opentrons_shared_data.gripper.constants import GRIPPER_PADDLE_WIDTH from opentrons.protocol_engine.state import update_types @@ -168,7 +169,7 @@ async def test_move_labware_implementation_on_labware( decoy.when( state_view.labware.get_definition(labware_id="my-cool-labware-id") ).then_return( - LabwareDefinition.construct(namespace="spacename") # type: ignore[call-arg] + LabwareDefinition.model_construct(namespace="spacename") # type: ignore[call-arg] ) decoy.when( state_view.geometry.ensure_location_not_occupied( @@ -189,7 +190,7 @@ async def test_move_labware_implementation_on_labware( "my-even-cooler-labware-id" ), state_view.labware.raise_if_labware_cannot_be_stacked( - LabwareDefinition.construct(namespace="spacename"), # type: ignore[call-arg] + LabwareDefinition.model_construct(namespace="spacename"), # type: ignore[call-arg] "my-even-cooler-labware-id", ), ) @@ -314,7 +315,7 @@ async def test_gripper_error( labware_namespace = "labware-namespace" labware_load_name = "load-name" labware_definition_uri = "opentrons-test/load-name/1" - labware_def = LabwareDefinition.construct( # type: ignore[call-arg] + labware_def = LabwareDefinition.model_construct( # type: ignore[call-arg] namespace=labware_namespace, ) original_location = DeckSlotLocation(slotName=DeckSlotName.SLOT_A1) @@ -324,7 +325,7 @@ async def test_gripper_error( # Common MoveLabwareImplementation boilerplate: decoy.when(state_view.labware.get_definition(labware_id=labware_id)).then_return( - LabwareDefinition.construct(namespace=labware_namespace) # type: ignore[call-arg] + LabwareDefinition.model_construct(namespace=labware_namespace) # type: ignore[call-arg] ) decoy.when(state_view.labware.get(labware_id=labware_id)).then_return( LoadedLabware( @@ -374,7 +375,7 @@ async def test_gripper_error( result = await subject.execute(params) assert result == DefinedErrorData( - public=GripperMovementError.construct( + public=GripperMovementError.model_construct( id=error_id, createdAt=error_created_at, errorCode=underlying_exception.code.value.code, @@ -462,7 +463,7 @@ async def test_gripper_move_to_waste_chute_implementation( pickUpOffset=LabwareOffsetVector(x=1, y=2, z=3), dropOffset=None, ) - labware_def = LabwareDefinition.construct( # type: ignore[call-arg] + labware_def = LabwareDefinition.model_construct( # type: ignore[call-arg] namespace="my-cool-namespace", dimensions=Dimensions( yDimension=labware_width, zDimension=labware_width, xDimension=labware_width @@ -670,8 +671,8 @@ async def test_move_labware_raises_when_moving_adapter_with_gripper( strategy=LabwareMovementStrategy.USING_GRIPPER, ) - definition = LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct(loadName="My cool adapter"), # type: ignore[call-arg] + definition = LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(loadName="My cool adapter"), # type: ignore[call-arg] ) decoy.when(state_view.labware.get(labware_id="my-cool-labware-id")).then_return( @@ -711,8 +712,8 @@ async def test_move_labware_raises_when_moving_labware_with_gripper_incompatible strategy=LabwareMovementStrategy.USING_GRIPPER, ) - definition = LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct(loadName="My cool labware"), # type: ignore[call-arg] + definition = LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(loadName="My cool labware"), # type: ignore[call-arg] ) decoy.when(state_view.labware.get(labware_id="my-cool-labware-id")).then_return( @@ -761,7 +762,7 @@ async def test_move_labware_with_gripper_raises_on_ot2( decoy.when( state_view.labware.get_definition(labware_id="my-cool-labware-id") ).then_return( - LabwareDefinition.construct(namespace="spacename") # type: ignore[call-arg] + LabwareDefinition.model_construct(namespace="spacename") # type: ignore[call-arg] ) decoy.when(state_view.config).then_return( @@ -783,8 +784,10 @@ async def test_move_labware_raises_when_moving_fixed_trash_labware( strategy=LabwareMovementStrategy.USING_GRIPPER, ) - definition = LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct(loadName="My cool labware", quirks=["fixedTrash"]), # type: ignore[call-arg] + definition = LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct( # type: ignore[call-arg] + loadName="My cool labware", quirks=["fixedTrash"] + ), ) decoy.when(state_view.labware.get(labware_id="my-cool-labware-id")).then_return( diff --git a/api/tests/opentrons/protocol_engine/conftest.py b/api/tests/opentrons/protocol_engine/conftest.py index 76c5d754f3e..88a166524ba 100644 --- a/api/tests/opentrons/protocol_engine/conftest.py +++ b/api/tests/opentrons/protocol_engine/conftest.py @@ -169,63 +169,63 @@ def magdeck_well_plate_def() -> LabwareDefinition: def tempdeck_v1_def() -> ModuleDefinition: """Get the definition of a V1 tempdeck.""" definition = load_shared_data("module/definitions/3/temperatureModuleV1.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture(scope="session") def tempdeck_v2_def() -> ModuleDefinition: """Get the definition of a V2 tempdeck.""" definition = load_shared_data("module/definitions/3/temperatureModuleV2.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture(scope="session") def magdeck_v1_def() -> ModuleDefinition: """Get the definition of a V1 magdeck.""" definition = load_shared_data("module/definitions/3/magneticModuleV1.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture(scope="session") def magdeck_v2_def() -> ModuleDefinition: """Get the definition of a V2 magdeck.""" definition = load_shared_data("module/definitions/3/magneticModuleV2.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture(scope="session") def thermocycler_v1_def() -> ModuleDefinition: """Get the definition of a V2 thermocycler.""" definition = load_shared_data("module/definitions/3/thermocyclerModuleV1.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture(scope="session") def thermocycler_v2_def() -> ModuleDefinition: """Get the definition of a V2 thermocycler.""" definition = load_shared_data("module/definitions/3/thermocyclerModuleV2.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture(scope="session") def heater_shaker_v1_def() -> ModuleDefinition: """Get the definition of a V1 heater-shaker.""" definition = load_shared_data("module/definitions/3/heaterShakerModuleV1.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture(scope="session") def mag_block_v1_def() -> ModuleDefinition: """Get the definition of a V1 Mag Block.""" definition = load_shared_data("module/definitions/3/magneticBlockV1.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture(scope="session") def abs_reader_v1_def() -> ModuleDefinition: """Get the definition of a V1 absorbance plate reader.""" definition = load_shared_data("module/definitions/3/absorbanceReaderV1.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture(scope="session") diff --git a/api/tests/opentrons/protocol_engine/errors/test_error_occurrence.py b/api/tests/opentrons/protocol_engine/errors/test_error_occurrence.py index a2feb8261f7..531c2decc98 100644 --- a/api/tests/opentrons/protocol_engine/errors/test_error_occurrence.py +++ b/api/tests/opentrons/protocol_engine/errors/test_error_occurrence.py @@ -1,4 +1,5 @@ """Test ErrorOccurrence module.""" + import datetime from typing import List @@ -11,7 +12,7 @@ def test_error_occurrence_schema() -> None: This is explicitly tested because we are overriding the schema due to a default value for errorCode. """ - required_items: List[str] = ErrorOccurrence.schema()["definitions"][ + required_items: List[str] = ErrorOccurrence.model_json_schema()["$defs"][ "ErrorOccurrence" ]["required"] assert "errorCode" in required_items @@ -24,7 +25,7 @@ def test_parse_error_occurrence() -> None: """ input = '{"id": "abcdefg","errorType": "a bad one","createdAt": "2023-06-12 15:08:54.730451","detail": "This is a bad error"}' - result = ErrorOccurrence.parse_raw(input) + result = ErrorOccurrence.model_validate_json(input) expected = ErrorOccurrence( id="abcdefg", diff --git a/api/tests/opentrons/protocol_engine/execution/test_command_executor.py b/api/tests/opentrons/protocol_engine/execution/test_command_executor.py index eb84ceb018b..d838eaded87 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_command_executor.py +++ b/api/tests/opentrons/protocol_engine/execution/test_command_executor.py @@ -1,11 +1,12 @@ """Smoke tests for the CommandExecutor class.""" + import asyncio from datetime import datetime -from typing import Any, Optional, Type, Union, cast +from typing import Optional, Type, cast, Any, Union import pytest from decoy import Decoy, matchers -from pydantic import BaseModel +from pydantic import BaseModel, PrivateAttr from opentrons.hardware_control import HardwareControlAPI, OT2HardwareControlAPI @@ -13,6 +14,7 @@ from opentrons.protocol_engine.error_recovery_policy import ( ErrorRecoveryPolicy, ErrorRecoveryType, + never_recover, ) from opentrons.protocol_engine.errors.error_occurrence import ErrorOccurrence from opentrons.protocol_engine.errors.exceptions import ( @@ -253,6 +255,12 @@ async def test_execute( TestCommandImplCls = decoy.mock(func=_TestCommandImpl) command_impl = decoy.mock(cls=_TestCommandImpl) + # Note: private attrs (which are attrs that start with _) are instantiated via deep + # copy from a provided default in the model, so if + # _TestCommand()._ImplementationCls != _TestCommand._ImplementationCls.default if + # we provide a default. Therefore, provide a default factory, so we can always have + # the same object. + class _TestCommand( BaseCommand[_TestCommandParams, _TestCommandResult, ErrorOccurrence] ): @@ -260,14 +268,16 @@ class _TestCommand( params: _TestCommandParams result: Optional[_TestCommandResult] - _ImplementationCls: Type[_TestCommandImpl] = TestCommandImplCls + _ImplementationCls: Type[_TestCommandImpl] = PrivateAttr( + default_factory=lambda: TestCommandImplCls + ) command_params = _TestCommandParams() command_result = SuccessData(public=_TestCommandResult()) queued_command = cast( Command, - _TestCommand( + _TestCommand.model_construct( # type: ignore[call-arg] id="command-id", key="command-key", createdAt=datetime(year=2021, month=1, day=1), @@ -278,7 +288,7 @@ class _TestCommand( running_command = cast( Command, - _TestCommand( + _TestCommand.model_construct( # type: ignore[call-arg] id="command-id", key="command-key", createdAt=datetime(year=2021, month=1, day=1), @@ -299,7 +309,7 @@ class _TestCommand( expected_completed_command = cast( Command, - _TestCommand( + _TestCommand.model_construct( id="command-id", key="command-key", createdAt=datetime(year=2021, month=1, day=1), @@ -327,7 +337,6 @@ class _TestCommand( state_store.commands.get(command_id="command-id") ).then_return(running_command) ) - decoy.when( queued_command._ImplementationCls( state_view=state_store, @@ -358,6 +367,10 @@ class _TestCommand( datetime(year=2023, month=3, day=3), ) + decoy.when(state_store.commands.get_error_recovery_policy()).then_return( + never_recover + ) + await subject.execute("command-id") decoy.verify( @@ -421,13 +434,15 @@ class _TestCommand( params: _TestCommandParams result: Optional[_TestCommandResult] - _ImplementationCls: Type[_TestCommandImpl] = TestCommandImplCls + _ImplementationCls: Type[_TestCommandImpl] = PrivateAttr( + default_factory=lambda: TestCommandImplCls + ) command_params = _TestCommandParams() queued_command = cast( Command, - _TestCommand( + _TestCommand.model_construct( # type: ignore[call-arg] id="command-id", key="command-key", createdAt=datetime(year=2021, month=1, day=1), @@ -438,7 +453,7 @@ class _TestCommand( running_command = cast( Command, - _TestCommand( + _TestCommand.model_construct( # type: ignore[call-arg] id="command-id", key="command-key", createdAt=datetime(year=2021, month=1, day=1), @@ -556,7 +571,9 @@ class _TestCommand( params: _TestCommandParams result: Optional[_TestCommandResult] - _ImplementationCls: Type[_TestCommandImpl] = TestCommandImplCls + _ImplementationCls: Type[_TestCommandImpl] = PrivateAttr( + default_factory=lambda: TestCommandImplCls + ) command_params = _TestCommandParams() command_id = "command-id" @@ -569,7 +586,7 @@ class _TestCommand( ) queued_command = cast( Command, - _TestCommand( + _TestCommand.model_construct( # type: ignore[call-arg] id=command_id, key="command-key", createdAt=created_at, @@ -579,7 +596,7 @@ class _TestCommand( ) running_command = cast( Command, - _TestCommand( + _TestCommand.model_construct( # type: ignore[call-arg] id=command_id, key="command-key", createdAt=created_at, diff --git a/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py b/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py index 39208184754..29117a894b5 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py +++ b/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py @@ -1,4 +1,5 @@ """Test equipment command execution side effects.""" + import pytest from _pytest.fixtures import SubRequest import inspect @@ -648,7 +649,7 @@ async def test_load_pipette( decoy.when(state_store.config.use_virtual_pipettes).then_return(False) decoy.when(model_utils.generate_id()).then_return("unique-id") decoy.when(state_store.pipettes.get_by_mount(MountType.RIGHT)).then_return( - LoadedPipette.construct(pipetteName=PipetteNameType.P300_MULTI) # type: ignore[call-arg] + LoadedPipette.model_construct(pipetteName=PipetteNameType.P300_MULTI) # type: ignore[call-arg] ) decoy.when(hardware_api.get_attached_instrument(mount=HwMount.LEFT)).then_return( pipette_dict diff --git a/api/tests/opentrons/protocol_engine/execution/test_tip_handler.py b/api/tests/opentrons/protocol_engine/execution/test_tip_handler.py index 4e9a10fdfaa..23f701db80b 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_tip_handler.py +++ b/api/tests/opentrons/protocol_engine/execution/test_tip_handler.py @@ -1,4 +1,5 @@ """Pipetting execution handler.""" + import pytest from decoy import Decoy, matchers @@ -51,7 +52,7 @@ def mock_labware_data_provider(decoy: Decoy) -> LabwareDataProvider: @pytest.fixture def tip_rack_definition() -> LabwareDefinition: """Get a tip rack defintion value object.""" - return LabwareDefinition.construct(namespace="test", version=42) # type: ignore[call-arg] + return LabwareDefinition.model_construct(namespace="test", version=42) # type: ignore[call-arg] MOCK_MAP = NozzleMap.build( diff --git a/api/tests/opentrons/protocol_engine/resources/test_labware_validation.py b/api/tests/opentrons/protocol_engine/resources/test_labware_validation.py index 663aec7337f..fbe9d6c21a4 100644 --- a/api/tests/opentrons/protocol_engine/resources/test_labware_validation.py +++ b/api/tests/opentrons/protocol_engine/resources/test_labware_validation.py @@ -14,9 +14,18 @@ @pytest.mark.parametrize( ("definition", "expected_result"), [ - (LabwareDefinition.construct(allowedRoles=[LabwareRole.labware]), True), # type: ignore[call-arg] - (LabwareDefinition.construct(allowedRoles=[]), True), # type: ignore[call-arg] - (LabwareDefinition.construct(allowedRoles=[LabwareRole.adapter]), False), # type: ignore[call-arg] + ( + LabwareDefinition.model_construct(allowedRoles=[LabwareRole.labware]), # type: ignore[call-arg] + True, + ), + ( + LabwareDefinition.model_construct(allowedRoles=[]), # type: ignore[call-arg] + True, + ), + ( + LabwareDefinition.model_construct(allowedRoles=[LabwareRole.adapter]), # type: ignore[call-arg] + False, + ), ], ) def test_validate_definition_is_labware( @@ -29,9 +38,18 @@ def test_validate_definition_is_labware( @pytest.mark.parametrize( ("definition", "expected_result"), [ - (LabwareDefinition.construct(allowedRoles=[LabwareRole.adapter]), True), # type: ignore[call-arg] - (LabwareDefinition.construct(allowedRoles=[]), False), # type: ignore[call-arg] - (LabwareDefinition.construct(allowedRoles=[LabwareRole.labware]), False), # type: ignore[call-arg] + ( + LabwareDefinition.model_construct(allowedRoles=[LabwareRole.adapter]), # type: ignore[call-arg] + True, + ), + ( + LabwareDefinition.model_construct(allowedRoles=[]), # type: ignore[call-arg] + False, + ), + ( + LabwareDefinition.model_construct(allowedRoles=[LabwareRole.labware]), # type: ignore[call-arg] + False, + ), ], ) def test_validate_definition_is_adapter( @@ -44,9 +62,22 @@ def test_validate_definition_is_adapter( @pytest.mark.parametrize( ("definition", "expected_result"), [ - (LabwareDefinition.construct(stackingOffsetWithLabware={"labware123": OverlapOffset(x=4, y=5, z=6)}), True), # type: ignore[call-arg] - (LabwareDefinition.construct(stackingOffsetWithLabware={"labwareXYZ": OverlapOffset(x=4, y=5, z=6)}), False), # type: ignore[call-arg] - (LabwareDefinition.construct(stackingOffsetWithLabware={}), False), # type: ignore[call-arg] + ( + LabwareDefinition.model_construct( # type: ignore[call-arg] + stackingOffsetWithLabware={"labware123": OverlapOffset(x=4, y=5, z=6)} + ), + True, + ), + ( + LabwareDefinition.model_construct( # type: ignore[call-arg] + stackingOffsetWithLabware={"labwareXYZ": OverlapOffset(x=4, y=5, z=6)} + ), + False, + ), + ( + LabwareDefinition.model_construct(stackingOffsetWithLabware={}), # type: ignore[call-arg] + False, + ), ], ) def test_validate_labware_can_be_stacked( @@ -62,9 +93,24 @@ def test_validate_labware_can_be_stacked( @pytest.mark.parametrize( ("definition", "expected_result"), [ - (LabwareDefinition.construct(parameters=Parameters.construct(quirks=None)), True), # type: ignore[call-arg] - (LabwareDefinition.construct(parameters=Parameters.construct(quirks=["foo"])), True), # type: ignore[call-arg] - (LabwareDefinition.construct(parameters=Parameters.construct(quirks=["gripperIncompatible"])), False), # type: ignore[call-arg] + ( + LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(quirks=None) # type: ignore[call-arg] + ), + True, + ), + ( + LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(quirks=["foo"]) # type: ignore[call-arg] + ), + True, + ), + ( + LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(quirks=["gripperIncompatible"]) # type: ignore[call-arg] + ), + False, + ), ], ) def test_validate_gripper_compatible( diff --git a/api/tests/opentrons/protocol_engine/state/command_fixtures.py b/api/tests/opentrons/protocol_engine/state/command_fixtures.py index 5ac522095f2..31f06858b53 100644 --- a/api/tests/opentrons/protocol_engine/state/command_fixtures.py +++ b/api/tests/opentrons/protocol_engine/state/command_fixtures.py @@ -1,4 +1,5 @@ """Command factories to use in tests as data fixtures.""" + from datetime import datetime from pydantic import BaseModel from typing import Optional, cast, Dict @@ -21,6 +22,12 @@ ) +class FixtureModel(BaseModel): + """Fixture Model.""" + + ... + + def create_queued_command( command_id: str = "command-id", command_key: str = "command-key", @@ -29,6 +36,10 @@ def create_queued_command( params: Optional[BaseModel] = None, ) -> cmd.Command: """Given command data, build a pending command model.""" + + class DummyParams(BaseModel): + pass + return cast( cmd.Command, cmd.BaseCommand( @@ -37,7 +48,7 @@ def create_queued_command( commandType=command_type, createdAt=datetime(year=2021, month=1, day=1), status=cmd.CommandStatus.QUEUED, - params=params or BaseModel(), + params=params or DummyParams(), intent=intent, ), ) @@ -59,7 +70,7 @@ def create_running_command( createdAt=created_at, commandType=command_type, status=cmd.CommandStatus.RUNNING, - params=params or BaseModel(), + params=params or FixtureModel(), ), ) @@ -84,7 +95,7 @@ def create_failed_command( completedAt=completed_at, commandType=command_type, status=cmd.CommandStatus.FAILED, - params=params or BaseModel(), + params=params or FixtureModel(), error=error, intent=intent, ), @@ -108,8 +119,8 @@ def create_succeeded_command( createdAt=created_at, commandType=command_type, status=cmd.CommandStatus.SUCCEEDED, - params=params or BaseModel(), - result=result or BaseModel(), + params=params or FixtureModel(), + result=result or FixtureModel(), ), ) @@ -193,7 +204,7 @@ def create_load_module_command( moduleId=module_id, model=model, serialNumber=None, - definition=ModuleDefinition.construct(), # type: ignore[call-arg] + definition=ModuleDefinition.model_construct(), # type: ignore[call-arg] ) return cmd.LoadModule( diff --git a/api/tests/opentrons/protocol_engine/state/test_addressable_area_store_old.py b/api/tests/opentrons/protocol_engine/state/test_addressable_area_store_old.py index 1bbccf96d42..b04237c702d 100644 --- a/api/tests/opentrons/protocol_engine/state/test_addressable_area_store_old.py +++ b/api/tests/opentrons/protocol_engine/state/test_addressable_area_store_old.py @@ -45,7 +45,7 @@ def _make_deck_config() -> DeckConfigurationType: def _dummy_command() -> Command: """Return a placeholder command.""" - return Comment.construct() # type: ignore[call-arg] + return Comment.model_construct() # type: ignore[call-arg] @pytest.fixture diff --git a/api/tests/opentrons/protocol_engine/state/test_geometry_view.py b/api/tests/opentrons/protocol_engine/state/test_geometry_view.py index b145458649d..fda32a56ce0 100644 --- a/api/tests/opentrons/protocol_engine/state/test_geometry_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_geometry_view.py @@ -1,4 +1,5 @@ """Test state getters for retrieving geometry views of state.""" + import inspect import json from datetime import datetime @@ -257,7 +258,7 @@ def addressable_area_view( @pytest.fixture def nice_labware_definition() -> LabwareDefinition: """Load a nice labware def that won't blow up your terminal.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( json.loads( load_shared_data("labware/fixtures/2/fixture_12_trough_v2.json").decode( "utf-8" @@ -269,7 +270,7 @@ def nice_labware_definition() -> LabwareDefinition: @pytest.fixture def nice_adapter_definition() -> LabwareDefinition: """Load a friendly adapter definition.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( json.loads( load_shared_data( "labware/definitions/2/opentrons_aluminum_flat_bottom_plate/1.json" @@ -849,8 +850,8 @@ def test_get_all_obstacle_highest_z_with_modules( subject: GeometryView, ) -> None: """It should get the highest Z including modules.""" - module_1 = LoadedModule.construct(id="module-id-1") # type: ignore[call-arg] - module_2 = LoadedModule.construct(id="module-id-2") # type: ignore[call-arg] + module_1 = LoadedModule.model_construct(id="module-id-1") # type: ignore[call-arg] + module_2 = LoadedModule.model_construct(id="module-id-2") # type: ignore[call-arg] decoy.when(mock_labware_view.get_all()).then_return([]) decoy.when(mock_addressable_area_view.get_all()).then_return([]) @@ -939,7 +940,7 @@ def test_get_highest_z_in_slot_with_single_module( ) -> None: """It should get the highest Z in slot with just a single module.""" # Case: Slot has a module that doesn't have any labware on it. Highest z is equal to module height. - module_in_slot = LoadedModule.construct( + module_in_slot = LoadedModule.model_construct( id="only-module", model=ModuleModel.THERMOCYCLER_MODULE_V2, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_4), @@ -1094,7 +1095,7 @@ def test_get_highest_z_in_slot_with_labware_stack_on_module( location=ModuleLocation(moduleId="module-id"), offsetId="offset-id2", ) - module_on_slot = LoadedModule.construct( + module_on_slot = LoadedModule.model_construct( id="module-id", model=ModuleModel.THERMOCYCLER_MODULE_V2, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_4), @@ -1982,7 +1983,7 @@ def test_get_relative_well_location( assert result == WellLocation( origin=WellOrigin.TOP, - offset=WellOffset.construct( + offset=WellOffset.model_construct( x=cast(float, pytest.approx(7)), y=cast(float, pytest.approx(8)), z=cast(float, pytest.approx(9)), @@ -2007,7 +2008,7 @@ def test_get_relative_liquid_handling_well_location( assert result == LiquidHandlingWellLocation( origin=WellOrigin.MENISCUS, - offset=WellOffset.construct( + offset=WellOffset.model_construct( x=0.0, y=0.0, z=cast(float, pytest.approx(-2)), @@ -2457,8 +2458,8 @@ def test_get_slot_item( subject: GeometryView, ) -> None: """It should get items in certain slots.""" - labware = LoadedLabware.construct(id="cool-labware") # type: ignore[call-arg] - module = LoadedModule.construct(id="cool-module") # type: ignore[call-arg] + labware = LoadedLabware.model_construct(id="cool-labware") # type: ignore[call-arg] + module = LoadedModule.model_construct(id="cool-module") # type: ignore[call-arg] decoy.when(mock_labware_view.get_by_slot(DeckSlotName.SLOT_1)).then_return(None) decoy.when(mock_labware_view.get_by_slot(DeckSlotName.SLOT_2)).then_return(labware) @@ -2485,7 +2486,7 @@ def test_get_slot_item_that_is_overflowed_module( subject: GeometryView, ) -> None: """It should return the module that occupies the slot, even if not loaded on it.""" - module = LoadedModule.construct(id="cool-module") # type: ignore[call-arg] + module = LoadedModule.model_construct(id="cool-module") # type: ignore[call-arg] decoy.when(mock_labware_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(None) decoy.when(mock_module_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(None) decoy.when( @@ -2901,19 +2902,19 @@ def test_check_gripper_labware_tip_collision( ) ) - definition = LabwareDefinition.construct( # type: ignore[call-arg] + definition = LabwareDefinition.model_construct( # type: ignore[call-arg] namespace="hello", - dimensions=LabwareDimensions.construct( + dimensions=LabwareDimensions.model_construct( yDimension=1, zDimension=2, xDimension=3 ), version=1, - parameters=LabwareDefinitionParameters.construct( + parameters=LabwareDefinitionParameters.model_construct( format="96Standard", loadName="labware-id", isTiprack=True, isMagneticModuleCompatible=False, ), - cornerOffsetFromSlot=CornerOffsetFromSlot.construct(x=1, y=2, z=3), + cornerOffsetFromSlot=CornerOffsetFromSlot.model_construct(x=1, y=2, z=3), ordering=[], ) diff --git a/api/tests/opentrons/protocol_engine/state/test_labware_view_old.py b/api/tests/opentrons/protocol_engine/state/test_labware_view_old.py index 0b6886040c6..7ace6d767ad 100644 --- a/api/tests/opentrons/protocol_engine/state/test_labware_view_old.py +++ b/api/tests/opentrons/protocol_engine/state/test_labware_view_old.py @@ -261,13 +261,13 @@ def test_find_custom_labware_params( namespace: Optional[str], version: Optional[int] ) -> None: """It should find the missing (if any) load labware parameters.""" - labware_def = LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct(loadName="hello"), # type: ignore[call-arg] + labware_def = LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(loadName="hello"), # type: ignore[call-arg] namespace="world", version=123, ) - standard_def = LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct(loadName="goodbye"), # type: ignore[call-arg] + standard_def = LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(loadName="goodbye"), # type: ignore[call-arg] namespace="opentrons", version=456, ) @@ -551,12 +551,12 @@ def test_validate_liquid_allowed_raises_incompatible_labware() -> None: ), }, definitions_by_uri={ - "some-tiprack-uri": LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct(isTiprack=True), # type: ignore[call-arg] + "some-tiprack-uri": LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(isTiprack=True), # type: ignore[call-arg] wells={}, ), - "some-adapter-uri": LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct(isTiprack=False), # type: ignore[call-arg] + "some-adapter-uri": LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(isTiprack=False), # type: ignore[call-arg] allowedRoles=[LabwareRole.adapter], wells={}, ), @@ -598,8 +598,8 @@ def test_get_tip_length_gets_length_from_definition( def test_get_tip_drop_z_offset() -> None: """It should get a tip drop z offset by scaling the tip length.""" - tip_rack_def = LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct( # type: ignore[call-arg] + tip_rack_def = LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct( # type: ignore[call-arg] tipLength=100, ) ) @@ -693,7 +693,7 @@ def test_get_labware_overlap_offsets() -> None: """It should get the labware overlap offsets.""" subject = get_labware_view() result = subject.get_labware_overlap_offsets( - definition=LabwareDefinition.construct( # type: ignore[call-arg] + definition=LabwareDefinition.model_construct( # type: ignore[call-arg] stackingOffsetWithLabware={ "bottom-labware-name": SharedDataOverlapOffset(x=1, y=2, z=3) } @@ -779,7 +779,7 @@ def test_get_module_overlap_offsets( deck_definition=spec_deck_definition, ) result = subject.get_module_overlap_offsets( - definition=LabwareDefinition.construct( # type: ignore[call-arg] + definition=LabwareDefinition.model_construct( # type: ignore[call-arg] stackingOffsetWithModule=stacking_offset_with_module ), module_model=module_model, @@ -1131,13 +1131,13 @@ def test_raise_if_labware_in_location( def test_get_by_slot() -> None: """It should get the labware in a given slot.""" - labware_1 = LoadedLabware.construct( # type: ignore[call-arg] + labware_1 = LoadedLabware.model_construct( # type: ignore[call-arg] id="1", location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1) ) - labware_2 = LoadedLabware.construct( # type: ignore[call-arg] + labware_2 = LoadedLabware.model_construct( # type: ignore[call-arg] id="2", location=DeckSlotLocation(slotName=DeckSlotName.SLOT_2) ) - labware_3 = LoadedLabware.construct( # type: ignore[call-arg] + labware_3 = LoadedLabware.model_construct( # type: ignore[call-arg] id="3", location=ModuleLocation(moduleId="cool-module") ) @@ -1183,7 +1183,7 @@ def test_get_edge_path_type( offsetId=None, ) - labware_def = LabwareDefinition.construct( # type: ignore[call-arg] + labware_def = LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[["abc", "def"], ["ghi", "jkl"], ["mno", "pqr"]] ) @@ -1307,10 +1307,8 @@ def test_raise_if_labware_cannot_be_stacked_is_adapter() -> None: errors.LabwareCannotBeStackedError, match="defined as an adapter" ): subject.raise_if_labware_cannot_be_stacked( - top_labware_definition=LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct( # type: ignore[call-arg] - loadName="name" - ), + top_labware_definition=LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(loadName="name"), # type: ignore[call-arg] allowedRoles=[LabwareRole.adapter], ), bottom_labware_id="labware-id", @@ -1334,10 +1332,8 @@ def test_raise_if_labware_cannot_be_stacked_not_validated() -> None: errors.LabwareCannotBeStackedError, match="loaded onto labware test" ): subject.raise_if_labware_cannot_be_stacked( - top_labware_definition=LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct( # type: ignore[call-arg] - loadName="name" - ), + top_labware_definition=LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(loadName="name"), # type: ignore[call-arg] stackingOffsetWithLabware={}, ), bottom_labware_id="labware-id", @@ -1356,7 +1352,7 @@ def test_raise_if_labware_cannot_be_stacked_on_module_not_adapter() -> None: ) }, definitions_by_uri={ - "def-uri": LabwareDefinition.construct( # type: ignore[call-arg] + "def-uri": LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=[LabwareRole.labware] ) }, @@ -1364,10 +1360,8 @@ def test_raise_if_labware_cannot_be_stacked_on_module_not_adapter() -> None: with pytest.raises(errors.LabwareCannotBeStackedError, match="module"): subject.raise_if_labware_cannot_be_stacked( - top_labware_definition=LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct( # type: ignore[call-arg] - loadName="name" - ), + top_labware_definition=LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(loadName="name"), # type: ignore[call-arg] stackingOffsetWithLabware={ "test": SharedDataOverlapOffset(x=0, y=0, z=0) }, @@ -1394,10 +1388,10 @@ def test_raise_if_labware_cannot_be_stacked_on_labware_on_adapter() -> None: ), }, definitions_by_uri={ - "def-uri-1": LabwareDefinition.construct( # type: ignore[call-arg] + "def-uri-1": LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=[LabwareRole.labware] ), - "def-uri-2": LabwareDefinition.construct( # type: ignore[call-arg] + "def-uri-2": LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=[LabwareRole.adapter] ), }, @@ -1407,10 +1401,8 @@ def test_raise_if_labware_cannot_be_stacked_on_labware_on_adapter() -> None: errors.LabwareCannotBeStackedError, match="cannot be loaded to stack" ): subject.raise_if_labware_cannot_be_stacked( - top_labware_definition=LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct( # type: ignore[call-arg] - loadName="name" - ), + top_labware_definition=LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct(loadName="name"), # type: ignore[call-arg] stackingOffsetWithLabware={ "test": SharedDataOverlapOffset(x=0, y=0, z=0) }, @@ -1472,9 +1464,9 @@ def test_labware_stacking_height_passes_or_raises( ), }, definitions_by_uri={ - "def-uri-1": LabwareDefinition.construct( # type: ignore[call-arg] + "def-uri-1": LabwareDefinition.model_construct( # type: ignore[call-arg] allowedRoles=allowed_roles, - parameters=Parameters.construct( + parameters=Parameters.model_construct( format="irregular", quirks=stacking_quirks, isTiprack=False, @@ -1487,8 +1479,8 @@ def test_labware_stacking_height_passes_or_raises( with exception: subject.raise_if_labware_cannot_be_stacked( - top_labware_definition=LabwareDefinition.construct( # type: ignore[call-arg] - parameters=Parameters.construct( + top_labware_definition=LabwareDefinition.model_construct( # type: ignore[call-arg] + parameters=Parameters.model_construct( format="irregular", quirks=stacking_quirks, isTiprack=False, @@ -1554,7 +1546,7 @@ def test_get_labware_gripper_offsets_default_no_slots( ) }, definitions_by_uri={ - "some-labware-uri": LabwareDefinition.construct( # type: ignore[call-arg] + "some-labware-uri": LabwareDefinition.model_construct( # type: ignore[call-arg] gripperOffsets={ "default": GripperOffsets( pickUpOffset=OffsetVector(x=1, y=2, z=3), @@ -1618,7 +1610,7 @@ def test_calculates_well_bounding_box( labware_to_check: str, well_bbox: Dimensions ) -> None: """It should be able to calculate well bounding boxes.""" - definition = LabwareDefinition.parse_obj(load_definition(labware_to_check, 1)) + definition = LabwareDefinition.model_validate(load_definition(labware_to_check, 1)) subject = get_labware_view() assert subject.get_well_bbox(definition).x == pytest.approx(well_bbox.x) assert subject.get_well_bbox(definition).y == pytest.approx(well_bbox.y) diff --git a/api/tests/opentrons/protocol_engine/state/test_liquid_class_store_old.py b/api/tests/opentrons/protocol_engine/state/test_liquid_class_store_old.py index 57397ec61cb..9d910d9495a 100644 --- a/api/tests/opentrons/protocol_engine/state/test_liquid_class_store_old.py +++ b/api/tests/opentrons/protocol_engine/state/test_liquid_class_store_old.py @@ -39,7 +39,7 @@ def test_handles_add_liquid_class( subject.handle_action( actions.SucceedCommandAction( - command=LoadLiquidClass.construct(), # type: ignore[call-arg] + command=LoadLiquidClass.model_construct(), # type: ignore[call-arg] state_update=update_types.StateUpdate( liquid_class_loaded=update_types.LiquidClassLoadedUpdate( liquid_class_id="liquid-class-id", diff --git a/api/tests/opentrons/protocol_engine/state/test_module_store_old.py b/api/tests/opentrons/protocol_engine/state/test_module_store_old.py index e4ab52ebaf8..4767ecad16b 100644 --- a/api/tests/opentrons/protocol_engine/state/test_module_store_old.py +++ b/api/tests/opentrons/protocol_engine/state/test_module_store_old.py @@ -202,7 +202,7 @@ def test_load_module( ) -> None: """It should handle a successful LoadModule command.""" action = actions.SucceedCommandAction( - command=commands.LoadModule.construct( # type: ignore[call-arg] + command=commands.LoadModule.model_construct( # type: ignore[call-arg] params=commands.LoadModuleParams( model=params_model, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), @@ -265,7 +265,7 @@ def test_load_thermocycler_in_thermocycler_slot( ) -> None: """It should update additional slots for thermocycler module.""" action = actions.SucceedCommandAction( - command=commands.LoadModule.construct( # type: ignore[call-arg] + command=commands.LoadModule.model_construct( # type: ignore[call-arg] params=commands.LoadModuleParams( model=ModuleModel.THERMOCYCLER_MODULE_V2, location=DeckSlotLocation(slotName=tc_slot), @@ -389,7 +389,7 @@ def test_add_module_action( def test_handle_hs_temperature_commands(heater_shaker_v1_def: ModuleDefinition) -> None: """It should update `plate_target_temperature` correctly.""" - load_module_cmd = commands.LoadModule.construct( # type: ignore[call-arg] + load_module_cmd = commands.LoadModule.model_construct( # type: ignore[call-arg] params=commands.LoadModuleParams( model=ModuleModel.HEATER_SHAKER_MODULE_V1, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), @@ -401,11 +401,11 @@ def test_handle_hs_temperature_commands(heater_shaker_v1_def: ModuleDefinition) definition=heater_shaker_v1_def, ), ) - set_temp_cmd = hs_commands.SetTargetTemperature.construct( # type: ignore[call-arg] + set_temp_cmd = hs_commands.SetTargetTemperature.model_construct( # type: ignore[call-arg] params=hs_commands.SetTargetTemperatureParams(moduleId="module-id", celsius=42), result=hs_commands.SetTargetTemperatureResult(), ) - deactivate_cmd = hs_commands.DeactivateHeater.construct( # type: ignore[call-arg] + deactivate_cmd = hs_commands.DeactivateHeater.model_construct( # type: ignore[call-arg] params=hs_commands.DeactivateHeaterParams(moduleId="module-id"), result=hs_commands.DeactivateHeaterResult(), ) @@ -437,7 +437,7 @@ def test_handle_hs_temperature_commands(heater_shaker_v1_def: ModuleDefinition) def test_handle_hs_shake_commands(heater_shaker_v1_def: ModuleDefinition) -> None: """It should update heater-shaker's `is_plate_shaking` correctly.""" - load_module_cmd = commands.LoadModule.construct( # type: ignore[call-arg] + load_module_cmd = commands.LoadModule.model_construct( # type: ignore[call-arg] params=commands.LoadModuleParams( model=ModuleModel.HEATER_SHAKER_MODULE_V1, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), @@ -449,11 +449,11 @@ def test_handle_hs_shake_commands(heater_shaker_v1_def: ModuleDefinition) -> Non definition=heater_shaker_v1_def, ), ) - set_shake_cmd = hs_commands.SetAndWaitForShakeSpeed.construct( # type: ignore[call-arg] + set_shake_cmd = hs_commands.SetAndWaitForShakeSpeed.model_construct( # type: ignore[call-arg] params=hs_commands.SetAndWaitForShakeSpeedParams(moduleId="module-id", rpm=111), result=hs_commands.SetAndWaitForShakeSpeedResult(pipetteRetracted=False), ) - deactivate_cmd = hs_commands.DeactivateShaker.construct( # type: ignore[call-arg] + deactivate_cmd = hs_commands.DeactivateShaker.model_construct( # type: ignore[call-arg] params=hs_commands.DeactivateShakerParams(moduleId="module-id"), result=hs_commands.DeactivateShakerResult(), ) @@ -487,7 +487,7 @@ def test_handle_hs_labware_latch_commands( heater_shaker_v1_def: ModuleDefinition, ) -> None: """It should update heater-shaker's `is_labware_latch_closed` correctly.""" - load_module_cmd = commands.LoadModule.construct( # type: ignore[call-arg] + load_module_cmd = commands.LoadModule.model_construct( # type: ignore[call-arg] params=commands.LoadModuleParams( model=ModuleModel.HEATER_SHAKER_MODULE_V1, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), @@ -499,11 +499,11 @@ def test_handle_hs_labware_latch_commands( definition=heater_shaker_v1_def, ), ) - close_latch_cmd = hs_commands.CloseLabwareLatch.construct( # type: ignore[call-arg] + close_latch_cmd = hs_commands.CloseLabwareLatch.model_construct( # type: ignore[call-arg] params=hs_commands.CloseLabwareLatchParams(moduleId="module-id"), result=hs_commands.CloseLabwareLatchResult(), ) - open_latch_cmd = hs_commands.OpenLabwareLatch.construct( # type: ignore[call-arg] + open_latch_cmd = hs_commands.OpenLabwareLatch.model_construct( # type: ignore[call-arg] params=hs_commands.OpenLabwareLatchParams(moduleId="module-id"), result=hs_commands.OpenLabwareLatchResult(pipetteRetracted=False), ) @@ -546,7 +546,7 @@ def test_handle_tempdeck_temperature_commands( tempdeck_v2_def: ModuleDefinition, ) -> None: """It should update Tempdeck's `plate_target_temperature` correctly.""" - load_module_cmd = commands.LoadModule.construct( # type: ignore[call-arg] + load_module_cmd = commands.LoadModule.model_construct( # type: ignore[call-arg] params=commands.LoadModuleParams( model=ModuleModel.TEMPERATURE_MODULE_V2, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), @@ -558,13 +558,13 @@ def test_handle_tempdeck_temperature_commands( definition=tempdeck_v2_def, ), ) - set_temp_cmd = temp_commands.SetTargetTemperature.construct( # type: ignore[call-arg] + set_temp_cmd = temp_commands.SetTargetTemperature.model_construct( # type: ignore[call-arg] params=temp_commands.SetTargetTemperatureParams( moduleId="module-id", celsius=42.4 ), result=temp_commands.SetTargetTemperatureResult(targetTemperature=42), ) - deactivate_cmd = temp_commands.DeactivateTemperature.construct( # type: ignore[call-arg] + deactivate_cmd = temp_commands.DeactivateTemperature.model_construct( # type: ignore[call-arg] params=temp_commands.DeactivateTemperatureParams(moduleId="module-id"), result=temp_commands.DeactivateTemperatureResult(), ) @@ -592,7 +592,7 @@ def test_handle_thermocycler_temperature_commands( thermocycler_v1_def: ModuleDefinition, ) -> None: """It should update thermocycler's temperature statuses correctly.""" - load_module_cmd = commands.LoadModule.construct( # type: ignore[call-arg] + load_module_cmd = commands.LoadModule.model_construct( # type: ignore[call-arg] params=commands.LoadModuleParams( model=ModuleModel.THERMOCYCLER_MODULE_V1, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), @@ -604,23 +604,23 @@ def test_handle_thermocycler_temperature_commands( definition=thermocycler_v1_def, ), ) - set_block_temp_cmd = tc_commands.SetTargetBlockTemperature.construct( # type: ignore[call-arg] + set_block_temp_cmd = tc_commands.SetTargetBlockTemperature.model_construct( # type: ignore[call-arg] params=tc_commands.SetTargetBlockTemperatureParams( moduleId="module-id", celsius=42.4 ), result=tc_commands.SetTargetBlockTemperatureResult(targetBlockTemperature=42.4), ) - deactivate_block_cmd = tc_commands.DeactivateBlock.construct( # type: ignore[call-arg] + deactivate_block_cmd = tc_commands.DeactivateBlock.model_construct( # type: ignore[call-arg] params=tc_commands.DeactivateBlockParams(moduleId="module-id"), result=tc_commands.DeactivateBlockResult(), ) - set_lid_temp_cmd = tc_commands.SetTargetLidTemperature.construct( # type: ignore[call-arg] + set_lid_temp_cmd = tc_commands.SetTargetLidTemperature.model_construct( # type: ignore[call-arg] params=tc_commands.SetTargetLidTemperatureParams( moduleId="module-id", celsius=35.3 ), result=tc_commands.SetTargetLidTemperatureResult(targetLidTemperature=35.3), ) - deactivate_lid_cmd = tc_commands.DeactivateLid.construct( # type: ignore[call-arg] + deactivate_lid_cmd = tc_commands.DeactivateLid.model_construct( # type: ignore[call-arg] params=tc_commands.DeactivateLidParams(moduleId="module-id"), result=tc_commands.DeactivateLidResult(), ) @@ -672,7 +672,7 @@ def test_handle_thermocycler_lid_commands( thermocycler_v1_def: ModuleDefinition, ) -> None: """It should update thermocycler's lid status after executing lid commands.""" - load_module_cmd = commands.LoadModule.construct( # type: ignore[call-arg] + load_module_cmd = commands.LoadModule.model_construct( # type: ignore[call-arg] params=commands.LoadModuleParams( model=ModuleModel.THERMOCYCLER_MODULE_V1, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), @@ -685,11 +685,11 @@ def test_handle_thermocycler_lid_commands( ), ) - open_lid_cmd = tc_commands.OpenLid.construct( # type: ignore[call-arg] + open_lid_cmd = tc_commands.OpenLid.model_construct( # type: ignore[call-arg] params=tc_commands.OpenLidParams(moduleId="module-id"), result=tc_commands.OpenLidResult(), ) - close_lid_cmd = tc_commands.CloseLid.construct( # type: ignore[call-arg] + close_lid_cmd = tc_commands.CloseLid.model_construct( # type: ignore[call-arg] params=tc_commands.CloseLidParams(moduleId="module-id"), result=tc_commands.CloseLidResult(), ) diff --git a/api/tests/opentrons/protocol_engine/state/test_module_view_old.py b/api/tests/opentrons/protocol_engine/state/test_module_view_old.py index 3902eedc76f..65e1a467977 100644 --- a/api/tests/opentrons/protocol_engine/state/test_module_view_old.py +++ b/api/tests/opentrons/protocol_engine/state/test_module_view_old.py @@ -149,7 +149,7 @@ def get_sample_parent_module_view( ) -> ModuleView: """Get a ModuleView with attached modules including a requested matching module.""" definition = load_shared_data("module/definitions/2/magneticModuleV1.json") - magdeck_def = ModuleDefinition.parse_raw(definition) + magdeck_def = ModuleDefinition.model_validate_json(definition) return make_module_view( slot_by_module_id={ @@ -1735,13 +1735,13 @@ def test_get_by_slot() -> None: hardware_by_module_id={ "1": HardwareModule( serial_number="serial-number-1", - definition=ModuleDefinition.construct( # type: ignore[call-arg] + definition=ModuleDefinition.model_construct( # type: ignore[call-arg] model=ModuleModel.TEMPERATURE_MODULE_V1 ), ), "2": HardwareModule( serial_number="serial-number-2", - definition=ModuleDefinition.construct( # type: ignore[call-arg] + definition=ModuleDefinition.model_construct( # type: ignore[call-arg] model=ModuleModel.TEMPERATURE_MODULE_V2 ), ), @@ -1773,13 +1773,13 @@ def test_get_by_slot_prefers_later() -> None: hardware_by_module_id={ "1": HardwareModule( serial_number="serial-number-1", - definition=ModuleDefinition.construct( # type: ignore[call-arg] + definition=ModuleDefinition.model_construct( # type: ignore[call-arg] model=ModuleModel.TEMPERATURE_MODULE_V1 ), ), "1-again": HardwareModule( serial_number="serial-number-1-again", - definition=ModuleDefinition.construct( # type: ignore[call-arg] + definition=ModuleDefinition.model_construct( # type: ignore[call-arg] model=ModuleModel.TEMPERATURE_MODULE_V1 ), ), diff --git a/api/tests/opentrons/protocol_engine/state/test_pipette_store_old.py b/api/tests/opentrons/protocol_engine/state/test_pipette_store_old.py index b88844bb53d..9e4db725415 100644 --- a/api/tests/opentrons/protocol_engine/state/test_pipette_store_old.py +++ b/api/tests/opentrons/protocol_engine/state/test_pipette_store_old.py @@ -770,8 +770,8 @@ def test_add_pipette_config( available_sensors: pipette_definition.AvailableSensorDefinition, ) -> None: """It should update state from any pipette config private result.""" - command = cmd.LoadPipette.construct( # type: ignore[call-arg] - params=cmd.LoadPipetteParams.construct( + command = cmd.LoadPipette.model_construct( + params=cmd.LoadPipetteParams.model_construct( # type: ignore[call-arg] mount=MountType.LEFT, pipetteName="p300_single" # type: ignore[arg-type] ), result=cmd.LoadPipetteResult(pipetteId="pipette-id"), diff --git a/api/tests/opentrons/protocol_engine/state/test_tip_state.py b/api/tests/opentrons/protocol_engine/state/test_tip_state.py index 7a958a37e5f..7246a5f4cb2 100644 --- a/api/tests/opentrons/protocol_engine/state/test_tip_state.py +++ b/api/tests/opentrons/protocol_engine/state/test_tip_state.py @@ -32,7 +32,7 @@ get_default_nozzle_map, ) -_tip_rack_parameters = LabwareParameters.construct(isTiprack=True) # type: ignore[call-arg] +_tip_rack_parameters = LabwareParameters.model_construct(isTiprack=True) # type: ignore[call-arg] @pytest.fixture @@ -50,7 +50,7 @@ def subject() -> TipStore: @pytest.fixture def labware_definition() -> LabwareDefinition: """Get a labware definition value object.""" - return LabwareDefinition.construct( # type: ignore[call-arg] + return LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[ ["A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1"], ["A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2"], @@ -90,14 +90,12 @@ def load_labware_action( def _dummy_command() -> commands.Command: """Return a placeholder command.""" - return commands.Comment.construct() # type: ignore[call-arg] + return commands.Comment.model_construct() # type: ignore[call-arg] @pytest.mark.parametrize( "labware_definition", - [ - LabwareDefinition.construct(ordering=[], parameters=_tip_rack_parameters) # type: ignore[call-arg] - ], + [LabwareDefinition.model_construct(ordering=[], parameters=_tip_rack_parameters)], # type: ignore[call-arg] ) def test_get_next_tip_returns_none( load_labware_action: actions.SucceedCommandAction, @@ -594,7 +592,6 @@ def test_get_next_tip_with_1_channel_followed_by_8_channel( command=_dummy_command(), ) ) - config_update_2 = update_types.PipetteConfigUpdate( pipette_id="pipette-id2", serial_number="pipette-serial2", @@ -929,9 +926,9 @@ def test_handle_pipette_config_action( @pytest.mark.parametrize( "labware_definition", [ - LabwareDefinition.construct( # type: ignore[call-arg] + LabwareDefinition.model_construct( # type: ignore[call-arg] ordering=[["A1"]], - parameters=LabwareParameters.construct(isTiprack=False), # type: ignore[call-arg] + parameters=LabwareParameters.model_construct(isTiprack=False), # type: ignore[call-arg] ) ], ) diff --git a/api/tests/opentrons/protocol_engine/test_protocol_engine.py b/api/tests/opentrons/protocol_engine/test_protocol_engine.py index cd6ffeb99cb..95289d681b8 100644 --- a/api/tests/opentrons/protocol_engine/test_protocol_engine.py +++ b/api/tests/opentrons/protocol_engine/test_protocol_engine.py @@ -1,4 +1,5 @@ """Tests for the ProtocolEngine class.""" + import inspect from datetime import datetime from typing import Any @@ -803,9 +804,9 @@ async def test_finish_with_estop_error_will_not_drop_tip_and_home( ) -> None: """It should be able to tell the engine it's finished because of an error and will not drop tip and home.""" error = ProtocolCommandFailedError( - original_error=ErrorOccurrence.construct( # type: ignore[call-arg] + original_error=ErrorOccurrence.model_construct( # type: ignore[call-arg] wrappedErrors=[ - ErrorOccurrence.construct(errorCode="3008") # type: ignore[call-arg] + ErrorOccurrence.model_construct(errorCode="3008") # type: ignore[call-arg] ] ) ) diff --git a/api/tests/opentrons/protocol_engine/test_types.py b/api/tests/opentrons/protocol_engine/test_types.py index ccf6b91de7f..d48c67ee61e 100644 --- a/api/tests/opentrons/protocol_engine/test_types.py +++ b/api/tests/opentrons/protocol_engine/test_types.py @@ -9,10 +9,14 @@ def test_hex_validation(hex_color: str) -> None: """Should allow creating a HexColor.""" # make sure noting is raised when instantiating this class - assert HexColor(__root__=hex_color) + assert HexColor(hex_color) + assert HexColor.model_validate_json(f'"{hex_color}"') -def test_handles_invalid_hex() -> None: +@pytest.mark.parametrize("invalid_hex_color", ["true", "null", "#123456789"]) +def test_handles_invalid_hex(invalid_hex_color: str) -> None: """Should raise a validation error.""" with pytest.raises(ValidationError): - HexColor(__root__="#123456789") + HexColor(invalid_hex_color) + with pytest.raises(ValidationError): + HexColor.model_validate_json(f'"{invalid_hex_color}"') diff --git a/api/tests/opentrons/protocol_runner/smoke_tests/conftest.py b/api/tests/opentrons/protocol_runner/smoke_tests/conftest.py index 5a758922e59..ade6ed4dae8 100644 --- a/api/tests/opentrons/protocol_runner/smoke_tests/conftest.py +++ b/api/tests/opentrons/protocol_runner/smoke_tests/conftest.py @@ -17,7 +17,7 @@ def tempdeck_v1_def() -> ModuleDefinition: """Get the definition of a V1 tempdeck.""" definition = load_shared_data("module/definitions/3/temperatureModuleV1.json") - return ModuleDefinition.parse_raw(definition) + return ModuleDefinition.model_validate_json(definition) @pytest.fixture() diff --git a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py index a652d76eac3..d4b59513be7 100644 --- a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py +++ b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py @@ -278,14 +278,12 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: result=pipette_right_result_captor, ) - # TODO(mc, 2021-11-11): not sure why I have to dict-access these properties - # might be a bug in Decoy, might be something weird that Pydantic does - tiprack_1_id = tiprack_1_result_captor.value["labwareId"] - tiprack_2_id = tiprack_2_result_captor.value["labwareId"] - well_plate_1_id = well_plate_1_result_captor.value["labwareId"] - module_plate_1_id = module_plate_1_result_captor.value["labwareId"] - pipette_left_id = pipette_left_result_captor.value["pipetteId"] - pipette_right_id = pipette_right_result_captor.value["pipetteId"] + tiprack_1_id = tiprack_1_result_captor.value.labwareId + tiprack_2_id = tiprack_2_result_captor.value.labwareId + well_plate_1_id = well_plate_1_result_captor.value.labwareId + module_plate_1_id = module_plate_1_result_captor.value.labwareId + pipette_left_id = pipette_left_result_captor.value.pipetteId + pipette_right_id = pipette_right_result_captor.value.pipetteId assert commands_result[8] == commands.PickUpTip.construct( id=matchers.IsA(str), diff --git a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_module_commands.py b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_module_commands.py index de14413a7ab..e27c23faa27 100644 --- a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_module_commands.py +++ b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_module_commands.py @@ -146,12 +146,9 @@ async def test_runner_with_modules_in_legacy_python( result=heater_shaker_result_captor, ) - assert temp_module_result_captor.value["model"] == ModuleModel.TEMPERATURE_MODULE_V1 - assert mag_module_result_captor.value["model"] == ModuleModel.MAGNETIC_MODULE_V1 + assert temp_module_result_captor.value.model == ModuleModel.TEMPERATURE_MODULE_V1 + assert mag_module_result_captor.value.model == ModuleModel.MAGNETIC_MODULE_V1 + assert thermocycler_result_captor.value.model == ModuleModel.THERMOCYCLER_MODULE_V1 assert ( - thermocycler_result_captor.value["model"] == ModuleModel.THERMOCYCLER_MODULE_V1 - ) - assert ( - heater_shaker_result_captor.value["model"] - == ModuleModel.HEATER_SHAKER_MODULE_V1 + heater_shaker_result_captor.value.model == ModuleModel.HEATER_SHAKER_MODULE_V1 ) diff --git a/api/tests/opentrons/protocol_runner/test_json_translator.py b/api/tests/opentrons/protocol_runner/test_json_translator.py index e2735e4cdbc..b9abbf4e655 100644 --- a/api/tests/opentrons/protocol_runner/test_json_translator.py +++ b/api/tests/opentrons/protocol_runner/test_json_translator.py @@ -1,4 +1,5 @@ """Tests for the JSON JsonTranslator interface.""" + import pytest from typing import Dict, List @@ -193,7 +194,7 @@ wellName="A1", ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="dropTip", params={ "pipetteId": "pipette-id-1", @@ -230,7 +231,7 @@ wellName="A1", ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="pickUpTip", params={ "pipetteId": "pipette-id-1", @@ -272,7 +273,7 @@ ), ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="touchTip", params={ "pipetteId": "pipette-id-1", @@ -307,7 +308,7 @@ pipetteId="pipette-id-1", mount="left", pipetteName="p10_single" ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="loadPipette", params={ "pipetteId": "pipette-id-1", @@ -339,7 +340,7 @@ location=Location(slotName="3"), ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="loadModule", params={ "moduleId": "module-id-1", @@ -374,7 +375,7 @@ displayName="Trash", ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="loadLabware", params={ "labwareId": "labware-id-2", @@ -423,7 +424,7 @@ flowRate=1.23, ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="blowout", params={ "pipetteId": "pipette-id-1", @@ -458,7 +459,7 @@ commandType="delay", params=protocol_schema_v7.Params(waitForResume=True, message="hello world"), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="delay", params={"waitForResume": True, "message": "hello world"}, ), @@ -475,7 +476,7 @@ commandType="delay", params=protocol_schema_v7.Params(seconds=12.34, message="hello world"), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="delay", params={"seconds": 12.34, "message": "hello world"}, ), @@ -495,7 +496,7 @@ commandType="waitForResume", params=protocol_schema_v7.Params(message="hello world"), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="waitForResume", params={"message": "hello world"}, ), @@ -512,7 +513,7 @@ commandType="waitForDuration", params=protocol_schema_v7.Params(seconds=12.34, message="hello world"), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="waitForDuration", params={"seconds": 12.34, "message": "hello world"}, ), @@ -542,7 +543,7 @@ forceDirect=True, ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="moveToCoordinates", params={ "pipetteId": "pipette-id-1", @@ -595,7 +596,7 @@ ], ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="thermocycler/runProfile", params={ "moduleId": "module-id-2", @@ -646,7 +647,7 @@ volumeByWell={"A1": 32, "B2": 50}, ), ), - protocol_schema_v8.Command( + protocol_schema_v8.Command.construct( commandType="loadLiquid", key=None, params={ @@ -873,6 +874,6 @@ def test_load_liquid( id="liquid-id-555", displayName="water", description="water description", - displayColor=HexColor(__root__="#F00"), + displayColor=HexColor("#F00"), ) ] diff --git a/api/tests/opentrons/protocol_runner/test_protocol_runner.py b/api/tests/opentrons/protocol_runner/test_protocol_runner.py index 15e0192175e..2080ec69587 100644 --- a/api/tests/opentrons/protocol_runner/test_protocol_runner.py +++ b/api/tests/opentrons/protocol_runner/test_protocol_runner.py @@ -361,7 +361,7 @@ async def test_run_json_runner_stop_requested_stops_enqueuing( json_translator: JsonTranslator, ) -> None: """It should run a protocol to completion.""" - labware_definition = LabwareDefinition.construct() # type: ignore[call-arg] + labware_definition = LabwareDefinition.model_construct() # type: ignore[call-arg] json_protocol_source = ProtocolSource( directory=Path("/dev/null"), main_file=Path("/dev/null/abc.json"), @@ -388,7 +388,7 @@ async def test_run_json_runner_stop_requested_stops_enqueuing( Liquid(id="water-id", displayName="water", description="water desc") ] - json_protocol = ProtocolSchemaV6.construct() # type: ignore[call-arg] + json_protocol = ProtocolSchemaV6.model_construct() # type: ignore[call-arg] decoy.when( await protocol_reader.extract_labware_definitions(json_protocol_source) @@ -401,7 +401,7 @@ async def test_run_json_runner_stop_requested_stops_enqueuing( pe_commands.HomeCreate(params=pe_commands.HomeParams()), ) ).then_return( - pe_commands.Home.construct(status=pe_commands.CommandStatus.SUCCEEDED) # type: ignore[call-arg] + pe_commands.Home.model_construct(status=pe_commands.CommandStatus.SUCCEEDED) # type: ignore[call-arg] ) decoy.when( await protocol_engine.add_and_execute_command_wait_for_recovery( @@ -410,7 +410,7 @@ async def test_run_json_runner_stop_requested_stops_enqueuing( ), ) ).then_return( - pe_commands.WaitForDuration.construct( # type: ignore[call-arg] + pe_commands.WaitForDuration.model_construct( # type: ignore[call-arg] id="protocol-command-id", error=pe_errors.ErrorOccurrence.from_failed( id="some-id", @@ -452,8 +452,8 @@ async def test_run_json_runner_stop_requested_stops_enqueuing( @pytest.mark.parametrize( "schema_version, json_protocol", [ - (6, ProtocolSchemaV6.construct()), # type: ignore[call-arg] - (7, ProtocolSchemaV7.construct()), # type: ignore[call-arg] + (6, ProtocolSchemaV6.model_construct()), # type: ignore[call-arg] + (7, ProtocolSchemaV7.model_construct()), # type: ignore[call-arg] ], ) async def test_load_json_runner( @@ -467,7 +467,7 @@ async def test_load_json_runner( json_protocol: Union[ProtocolSchemaV6, ProtocolSchemaV7], ) -> None: """It should load a JSON protocol file.""" - labware_definition = LabwareDefinition.construct() # type: ignore[call-arg] + labware_definition = LabwareDefinition.model_construct() # type: ignore[call-arg] json_protocol_source = ProtocolSource( directory=Path("/dev/null"), @@ -528,7 +528,7 @@ async def test_load_json_runner( ), ) ).then_return( - pe_commands.WaitForResume.construct( # type: ignore[call-arg] + pe_commands.WaitForResume.model_construct( # type: ignore[call-arg] id="command-id-1", status=CommandStatus.SUCCEEDED, error=None, @@ -541,7 +541,7 @@ async def test_load_json_runner( ), ) ).then_return( - pe_commands.WaitForResume.construct( # type: ignore[call-arg] + pe_commands.WaitForResume.model_construct( # type: ignore[call-arg] id="command-id-2", status=CommandStatus.SUCCEEDED, error=None, @@ -556,7 +556,7 @@ async def test_load_json_runner( ), ) ).then_return( - pe_commands.WaitForResume.construct( # type: ignore[call-arg] + pe_commands.WaitForResume.model_construct( # type: ignore[call-arg] id="command-id-3", status=CommandStatus.SUCCEEDED, error=None, @@ -601,7 +601,7 @@ async def test_load_legacy_python( python_runner_subject: PythonAndLegacyRunner, ) -> None: """It should load a legacy context-based Python protocol.""" - labware_definition = LabwareDefinition.construct() # type: ignore[call-arg] + labware_definition = LabwareDefinition.model_construct() # type: ignore[call-arg] legacy_protocol_source = ProtocolSource( directory=Path("/dev/null"), @@ -752,7 +752,7 @@ async def test_load_legacy_json( python_runner_subject: PythonAndLegacyRunner, ) -> None: """It should load a legacy context-based JSON protocol.""" - labware_definition = LabwareDefinition.construct() # type: ignore[call-arg] + labware_definition = LabwareDefinition.model_construct() # type: ignore[call-arg] legacy_protocol_source = ProtocolSource( directory=Path("/dev/null"), diff --git a/g-code-testing/Pipfile b/g-code-testing/Pipfile index 0b39a9dd222..2eb3d56782a 100644 --- a/g-code-testing/Pipfile +++ b/g-code-testing/Pipfile @@ -11,7 +11,7 @@ opentrons-shared-data = { editable = true, path = "../shared-data/python" } opentrons_hardware = { editable = true, path = "../hardware" } g-code-testing = { editable = true, path = "." } anyio = "==3.7.1" -pydantic = "==1.10.12" +pydantic = "==2.6.4" # opentrons dependency on linux, spec'd here to force lockfile inclusion # https://github.com/pypa/pipenv/issues/4408#issuecomment-668324177 systemd-python = { version = "==234", markers="sys_platform=='linux'" } diff --git a/g-code-testing/Pipfile.lock b/g-code-testing/Pipfile.lock index c2ea7426d71..760db936cda 100644 --- a/g-code-testing/Pipfile.lock +++ b/g-code-testing/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "214f2b205b35dd2d385ec40836249499ecebefc1696107a12d48c58b13c6353d" + "sha256": "fa448b83f70b6937f46be6aeec3c0562410958165490aa6c5ede4f906364b751" }, "pipfile-spec": 6, "requires": { @@ -23,6 +23,14 @@ ], "version": "==0.3.1" }, + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "anyio": { "hashes": [ "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780", @@ -58,11 +66,11 @@ }, "fastapi": { "hashes": [ - "sha256:976df7bab51ac7beda9f68c4513b8c4490b5c1135c72aafd0a5ee4023ec5282e", - "sha256:ac78f717cd80d657bd183f94d33b9bda84aa376a46a9dab513586b8eef1dc6fc" + "sha256:271662daf986da8fa98dc2b7c7f61c4abdfdccfb4786d79ed8b2878f172c6d5f", + "sha256:acb5f941ea8215663283c10018323ba7ea737c571b67fc7e88e9469c7eb1d12e" ], "markers": "python_version >= '3.7'", - "version": "==0.99.1" + "version": "==0.100.0" }, "g-code-testing": { "editable": true, @@ -86,11 +94,19 @@ }, "jsonschema": { "hashes": [ - "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d", - "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6" + "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7", + "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802" ], - "markers": "python_version >= '3.7'", - "version": "==4.17.3" + "markers": "python_version >= '3.8'", + "version": "==4.22.0" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc", + "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" + ], + "markers": "python_version >= '3.8'", + "version": "==2023.12.1" }, "numpy": { "hashes": [ @@ -156,84 +172,105 @@ }, "pydantic": { "hashes": [ - "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303", - "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe", - "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47", - "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494", - "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33", - "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86", - "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d", - "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c", - "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a", - "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565", - "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb", - "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62", - "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62", - "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0", - "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523", - "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d", - "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405", - "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f", - "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b", - "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718", - "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed", - "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb", - "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5", - "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc", - "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942", - "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe", - "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246", - "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350", - "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303", - "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09", - "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33", - "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8", - "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a", - "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1", - "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6", - "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d" + "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6", + "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.10.12" - }, - "pyrsistent": { - "hashes": [ - "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", - "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", - "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", - "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", - "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca", - "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", - "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", - "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", - "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714", - "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf", - "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", - "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", - "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", - "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d", - "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054", - "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", - "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", - "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423", - "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", - "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", - "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", - "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0", - "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", - "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", - "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce", - "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", - "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", - "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86", - "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f", - "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", - "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98", - "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022" + "markers": "python_version >= '3.8'", + "version": "==2.6.4" + }, + "pydantic-core": { + "hashes": [ + "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a", + "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed", + "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979", + "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff", + "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5", + "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45", + "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340", + "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad", + "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23", + "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6", + "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7", + "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241", + "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda", + "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187", + "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba", + "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c", + "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2", + "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c", + "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132", + "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf", + "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972", + "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db", + "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade", + "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4", + "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8", + "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f", + "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9", + "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48", + "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec", + "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d", + "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9", + "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb", + "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4", + "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89", + "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c", + "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9", + "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da", + "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac", + "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b", + "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf", + "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e", + "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137", + "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1", + "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b", + "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8", + "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e", + "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053", + "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01", + "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe", + "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd", + "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805", + "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183", + "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8", + "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99", + "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820", + "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074", + "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256", + "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8", + "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975", + "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad", + "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e", + "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca", + "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df", + "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b", + "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a", + "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a", + "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721", + "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a", + "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f", + "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2", + "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97", + "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6", + "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed", + "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc", + "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1", + "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe", + "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120", + "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f", + "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a" + ], + "markers": "python_version >= '3.8'", + "version": "==2.16.3" + }, + "pydantic-settings": { + "hashes": [ + "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed", + "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091" ], "markers": "python_version >= '3.8'", - "version": "==0.20.0" + "version": "==2.2.1" }, "pyserial": { "hashes": [ @@ -258,10 +295,123 @@ "markers": "python_version >= '3.7'", "version": "==0.0.6" }, + "referencing": { + "hashes": [ + "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", + "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" + ], + "markers": "python_version >= '3.8'", + "version": "==0.35.1" + }, "robot-server": { "editable": true, "path": "./../robot-server" }, + "rpds-py": { + "hashes": [ + "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee", + "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc", + "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc", + "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944", + "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20", + "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7", + "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4", + "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6", + "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6", + "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93", + "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633", + "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0", + "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360", + "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8", + "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139", + "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7", + "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a", + "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9", + "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26", + "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724", + "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72", + "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b", + "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09", + "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100", + "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3", + "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261", + "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3", + "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9", + "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b", + "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3", + "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de", + "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d", + "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e", + "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8", + "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff", + "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5", + "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c", + "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e", + "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e", + "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4", + "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8", + "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922", + "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338", + "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d", + "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8", + "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2", + "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72", + "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80", + "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644", + "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae", + "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163", + "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104", + "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d", + "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60", + "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a", + "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d", + "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07", + "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49", + "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10", + "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f", + "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2", + "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8", + "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7", + "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88", + "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65", + "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0", + "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909", + "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8", + "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c", + "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184", + "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397", + "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a", + "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346", + "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590", + "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333", + "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb", + "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74", + "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e", + "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d", + "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa", + "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f", + "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53", + "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1", + "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac", + "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0", + "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd", + "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611", + "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f", + "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c", + "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5", + "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab", + "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc", + "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43", + "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da", + "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac", + "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843", + "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e", + "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89", + "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64" + ], + "markers": "python_version >= '3.8'", + "version": "==0.18.1" + }, "server-utils": { "editable": true, "path": "./../server-utils" @@ -343,11 +493,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", - "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8", + "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594" ], "markers": "python_version >= '3.8'", - "version": "==4.11.0" + "version": "==4.12.0" }, "uvicorn": { "hashes": [ @@ -980,11 +1130,11 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a", - "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f" + "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b", + "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268" ], "markers": "python_version >= '3.8'", - "version": "==0.23.6" + "version": "==0.23.7" }, "pytest-cov": { "hashes": [ @@ -1047,11 +1197,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", - "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8", + "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594" ], "markers": "python_version >= '3.8'", - "version": "==4.11.0" + "version": "==4.12.0" }, "yarl": { "hashes": [ diff --git a/g-code-testing/g_code_test_data/g_code_configuration.py b/g-code-testing/g_code_test_data/g_code_configuration.py index 488496e030a..ff7ccda0fb8 100644 --- a/g-code-testing/g_code_test_data/g_code_configuration.py +++ b/g-code-testing/g_code_test_data/g_code_configuration.py @@ -10,6 +10,7 @@ Union, ) from typing_extensions import ( + Annotated, Final, Literal, ) @@ -22,10 +23,11 @@ from opentrons.protocols.api_support.types import APIVersion from pydantic import ( + StringConstraints, + ConfigDict, BaseModel, Field, - constr, - validator, + model_validator, ) BUCKET_NAME = "g-code-comparison" @@ -41,20 +43,21 @@ def add_mark(self, user_mark: Mark) -> None: class ProtocolGCodeConfirmConfig(BaseModel, SharedFunctionsMixin): path: str - name: Optional[constr(regex=r'^[a-z0-9_]*$')] + name: Optional[Annotated[str, StringConstraints(pattern=r'^[a-z0-9_]*$')]] = None settings: Settings results_dir: ClassVar[str] = "protocols" driver: str = 'protocol' marks: List[Mark] = [pytest.mark.g_code_confirm] - versions: Set[Union[APIVersion,int]] = Field(..., min_items=1) + versions: Set[Union[APIVersion,int]] = Field(..., min_length=1) + model_config = ConfigDict(arbitrary_types_allowed=True) - class Config: - arbitrary_types_allowed = True - - @validator("name", pre=True, always=True) - def name_from_path(cls, name, values) -> str: - derived_name = os.path.splitext(os.path.basename(values["path"]))[0] - return derived_name if name is None else name + @model_validator(mode="after") + def _populate_name_from_path(self) -> "ProtocolGCodeConfirmConfig": + """If `.name` was not given, give it a default based on `.path`.""" + derived_name = os.path.splitext(os.path.basename(self.path))[0] + if self.name is None: + self.name = derived_name + return self def _get_full_path(self, version: APIVersion): return os.path.join( @@ -92,15 +95,13 @@ async def execute(self, version: APIVersion): class HTTPGCodeConfirmConfig(BaseModel, SharedFunctionsMixin): - name: constr(regex=r'^[a-z0-9_]*$') + name: Annotated[str, StringConstraints(pattern=r'^[a-z0-9_]*$')] executable: Callable settings: Settings results_dir: ClassVar[str] = "http" driver: str = 'http' marks: List[Mark] = [pytest.mark.g_code_confirm] - - class Config: - arbitrary_types_allowed = True + model_config = ConfigDict(arbitrary_types_allowed=True) def _get_full_path(self) -> str: return os.path.join(COMPARISON_FILES_FOLDER_PATH, self.get_comparison_file_path()) diff --git a/hardware-testing/Pipfile b/hardware-testing/Pipfile index e3c824f42b2..8182a96a66f 100644 --- a/hardware-testing/Pipfile +++ b/hardware-testing/Pipfile @@ -19,7 +19,7 @@ atomicwrites = "==1.4.1" colorama = "==0.4.4" pytest = "==7.1.1" pytest-cov = "==2.10.1" -mypy = "==0.990" +mypy = "==1.11.0" black = "==22.3.0" flake8 = "~=3.9.0" flake8-annotations = "~=2.6.2" diff --git a/hardware-testing/Pipfile.lock b/hardware-testing/Pipfile.lock index f8dcfd2f7df..5b88acf5b7a 100644 --- a/hardware-testing/Pipfile.lock +++ b/hardware-testing/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "bfa6574dcab4bd350d77135bd8ecefd5e12ad6479664f932a7c0c544ecdf4c47" + "sha256": "b99e29478d0dfb1309ba9c71f0b214bdaf682bb09eac44d9dad8bbbdc54fe12a" }, "pipfile-spec": 6, "requires": { @@ -28,6 +28,14 @@ "markers": "python_version >= '3.8'", "version": "==0.3.1" }, + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "anyio": { "hashes": [ "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780", @@ -46,36 +54,34 @@ }, "bcrypt": { "hashes": [ - "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", - "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", - "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", - "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", - "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", - "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170", - "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", - "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", - "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", - "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184", - "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a", - "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", - "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", - "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", - "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", - "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", - "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", - "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", - "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", - "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", - "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", - "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", - "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", - "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", - "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", - "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", - "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db" + "sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837", + "sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6", + "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17", + "sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99", + "sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe", + "sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54", + "sha256:76132c176a6d9953cdc83c296aeaed65e1a708485fd55abf163e0d9f8f16ce0e", + "sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396", + "sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d", + "sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685", + "sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413", + "sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526", + "sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad", + "sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a", + "sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea", + "sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005", + "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f", + "sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf", + "sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425", + "sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84", + "sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c", + "sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139", + "sha256:e158009a54c4c8bc91d5e0da80920d048f918c61a581f0a63e4e93bb556d362f", + "sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c", + "sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331" ], "markers": "python_version >= '3.7'", - "version": "==4.2.0" + "version": "==4.2.1" }, "cffi": { "hashes": [ @@ -147,7 +153,7 @@ "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" ], - "markers": "platform_python_implementation != 'PyPy'", + "markers": "python_version >= '3.8'", "version": "==1.17.1" }, "click": { @@ -160,43 +166,43 @@ }, "cryptography": { "hashes": [ - "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", - "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", - "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa", - "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83", - "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff", - "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", - "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", - "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664", - "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08", - "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", - "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", - "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", - "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", - "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", - "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", - "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", - "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3", - "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", - "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", - "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", - "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c", - "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", - "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", - "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", - "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7", - "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", - "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7" + "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", + "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731", + "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", + "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", + "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", + "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c", + "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", + "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", + "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", + "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", + "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", + "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c", + "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", + "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", + "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", + "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", + "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa", + "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", + "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", + "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", + "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", + "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", + "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", + "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", + "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", + "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756", + "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4" ], - "markers": "python_version >= '3.7'", - "version": "==43.0.3" + "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'", + "version": "==44.0.0" }, "exceptiongroup": { "hashes": [ "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], - "markers": "python_version < '3.11'", + "markers": "python_version >= '3.7'", "version": "==1.2.2" }, "hardware-testing": { @@ -213,11 +219,19 @@ }, "jsonschema": { "hashes": [ - "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d", - "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6" + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" ], - "markers": "python_version >= '3.7'", - "version": "==4.17.3" + "markers": "python_version >= '3.8'", + "version": "==4.23.0" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", + "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.10.1" }, "msgpack": { "hashes": [ @@ -278,7 +292,7 @@ "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d", "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d" ], - "markers": "platform_system != 'Windows'", + "markers": "python_version >= '3.8'", "version": "==1.0.8" }, "numpy": { @@ -370,52 +384,125 @@ }, "pydantic": { "hashes": [ - "sha256:0399094464ae7f28482de22383e667625e38e1516d6b213176df1acdd0c477ea", - "sha256:076c49e24b73d346c45f9282d00dbfc16eef7ae27c970583d499f11110d9e5b0", - "sha256:07d00ca5ef0de65dd274005433ce2bb623730271d495a7d190a91c19c5679d34", - "sha256:0890fbd7fec9e151c7512941243d830b2d6076d5df159a2030952d480ab80a4e", - "sha256:0bfb5b378b78229119d66ced6adac2e933c67a0aa1d0a7adffbe432f3ec14ce4", - "sha256:0d32227ea9a3bf537a2273fd2fdb6d64ab4d9b83acd9e4e09310a777baaabb98", - "sha256:11965f421f7eb026439d4eb7464e9182fe6d69c3d4d416e464a4485d1ba61ab6", - "sha256:1fc8cc264afaf47ae6a9bcbd36c018d0c6b89293835d7fb0e5e1a95898062d59", - "sha256:2206a1752d9fac011e95ca83926a269fb0ef5536f7e053966d058316e24d929f", - "sha256:22a1794e01591884741be56c6fba157c4e99dcc9244beb5a87bd4aa54b84ea8b", - "sha256:4739c206bfb6bb2bdc78dcd40bfcebb2361add4ceac6d170e741bb914e9eff0f", - "sha256:4a5d5b877c7d3d9e17399571a8ab042081d22fe6904416a8b20f8af5909e6c8f", - "sha256:566bebdbe6bc0ac593fa0f67d62febbad9f8be5433f686dc56401ba4aab034e3", - "sha256:570ad0aeaf98b5e33ff41af75aba2ef6604ee25ce0431ecd734a28e74a208555", - "sha256:573254d844f3e64093f72fcd922561d9c5696821ff0900a0db989d8c06ab0c25", - "sha256:5d4320510682d5a6c88766b2a286d03b87bd3562bf8d78c73d63bab04b21e7b4", - "sha256:6d8a38a44bb6a15810084316ed69c854a7c06e0c99c5429f1d664ad52cec353c", - "sha256:6eb56074b11a696e0b66c7181da682e88c00e5cebe6570af8013fcae5e63e186", - "sha256:7e66aa0fa7f8aa9d0a620361834f6eb60d01d3e9cea23ca1a92cda99e6f61dac", - "sha256:7ea24e8614f541d69ea72759ff635df0e612b7dc9d264d43f51364df310081a3", - "sha256:7f31742c95e3f9443b8c6fa07c119623e61d76603be9c0d390bcf7e888acabcb", - "sha256:83ee8c9916689f8e6e7d90161e6663ac876be2efd32f61fdcfa3a15e87d4e413", - "sha256:8b2cf5e26da84f2d2dee3f60a3f1782adedcee785567a19b68d0af7e1534bd1f", - "sha256:945407f4d08cd12485757a281fca0e5b41408606228612f421aa4ea1b63a095d", - "sha256:9c46f58ef2df958ed2ea7437a8be0897d5efe9ee480818405338c7da88186fb3", - "sha256:9d7d48fbc5289efd23982a0d68e973a1f37d49064ccd36d86de4543aff21e086", - "sha256:9f28a81978e936136c44e6a70c65bde7548d87f3807260f73aeffbf76fb94c2f", - "sha256:a415b9e95fa602b10808113967f72b2da8722061265d6af69268c111c254832d", - "sha256:a82746c6d6e91ca17e75f7f333ed41d70fce93af520a8437821dec3ee52dfb10", - "sha256:ad57004e5d73aee36f1e25e4e73a4bc853b473a1c30f652dc8d86b0a987ffce3", - "sha256:c6444368b651a14c2ce2fb22145e1496f7ab23cbdb978590d47c8d34a7bc0289", - "sha256:d216f8d0484d88ab72ab45d699ac669fe031275e3fa6553e3804e69485449fa0", - "sha256:d3449633c207ec3d2d672eedb3edbe753e29bd4e22d2e42a37a2c1406564c20f", - "sha256:d5b5b7c6bafaef90cbb7dafcb225b763edd71d9e22489647ee7df49d6d341890", - "sha256:d7a8a1dd68bac29f08f0a3147de1885f4dccec35d4ea926e6e637fac03cdb4b3", - "sha256:d8d72553d2f3f57ce547de4fa7dc8e3859927784ab2c88343f1fc1360ff17a08", - "sha256:dce355fe7ae53e3090f7f5fa242423c3a7b53260747aa398b4b3aaf8b25f41c3", - "sha256:e351df83d1c9cffa53d4e779009a093be70f1d5c6bb7068584086f6a19042526", - "sha256:ec5c44e6e9eac5128a9bfd21610df3b8c6b17343285cc185105686888dc81206", - "sha256:f5bb81fcfc6d5bff62cd786cbd87480a11d23f16d5376ad2e057c02b3b44df96", - "sha256:fd34012691fbd4e67bdf4accb1f0682342101015b78327eaae3543583fcd451e", - "sha256:fea36c2065b7a1d28c6819cc2e93387b43dd5d3cf5a1e82d8132ee23f36d1f10", - "sha256:ff09600cebe957ecbb4a27496fe34c1d449e7957ed20a202d5029a71a8af2e35" + "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d", + "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9" ], - "markers": "python_version >= '3.7'", - "version": "==1.10.19" + "markers": "python_version >= '3.8'", + "version": "==2.10.3" + }, + "pydantic-core": { + "hashes": [ + "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9", + "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b", + "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c", + "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529", + "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc", + "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854", + "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d", + "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278", + "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a", + "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c", + "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f", + "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27", + "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f", + "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac", + "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2", + "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97", + "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a", + "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919", + "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9", + "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4", + "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c", + "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131", + "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5", + "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd", + "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089", + "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107", + "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6", + "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60", + "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf", + "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5", + "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08", + "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05", + "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2", + "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e", + "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c", + "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17", + "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62", + "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23", + "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be", + "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067", + "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02", + "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f", + "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235", + "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840", + "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5", + "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807", + "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16", + "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c", + "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864", + "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e", + "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a", + "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35", + "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737", + "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a", + "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3", + "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52", + "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05", + "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31", + "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89", + "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de", + "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6", + "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36", + "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c", + "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154", + "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb", + "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e", + "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd", + "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3", + "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f", + "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78", + "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960", + "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618", + "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08", + "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4", + "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c", + "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c", + "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330", + "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8", + "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792", + "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025", + "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9", + "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f", + "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01", + "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337", + "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4", + "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f", + "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd", + "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51", + "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab", + "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc", + "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676", + "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381", + "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed", + "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb", + "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967", + "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073", + "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae", + "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c", + "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206", + "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b" + ], + "markers": "python_version >= '3.8'", + "version": "==2.27.1" + }, + "pydantic-settings": { + "hashes": [ + "sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87", + "sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0" + ], + "markers": "python_version >= '3.8'", + "version": "==2.6.1" }, "pynacl": { "hashes": [ @@ -433,44 +520,6 @@ "markers": "python_version >= '3.6'", "version": "==1.5.0" }, - "pyrsistent": { - "hashes": [ - "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", - "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", - "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", - "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", - "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca", - "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", - "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", - "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", - "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714", - "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf", - "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", - "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", - "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", - "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d", - "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054", - "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", - "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", - "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423", - "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", - "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", - "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", - "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0", - "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", - "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", - "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce", - "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", - "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", - "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86", - "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f", - "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", - "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98", - "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022" - ], - "markers": "python_version >= '3.8'", - "version": "==0.20.0" - }, "pyserial": { "hashes": [ "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", @@ -487,6 +536,14 @@ "markers": "python_version >= '3.7'", "version": "==4.2.2" }, + "python-dotenv": { + "hashes": [ + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" + ], + "markers": "python_version >= '3.8'", + "version": "==1.0.1" + }, "pyusb": { "hashes": [ "sha256:2b4c7cb86dbadf044dfb9d3a4ff69fd217013dbe78a792177a3feb172449ea36", @@ -495,13 +552,130 @@ "markers": "python_full_version >= '3.6.0'", "version": "==1.2.1" }, + "referencing": { + "hashes": [ + "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", + "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" + ], + "markers": "python_version >= '3.8'", + "version": "==0.35.1" + }, + "rpds-py": { + "hashes": [ + "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518", + "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", + "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", + "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5", + "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9", + "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543", + "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2", + "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a", + "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d", + "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", + "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d", + "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd", + "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b", + "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4", + "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99", + "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", + "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd", + "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe", + "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1", + "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", + "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f", + "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3", + "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca", + "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d", + "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e", + "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc", + "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea", + "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", + "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b", + "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c", + "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff", + "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723", + "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e", + "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493", + "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6", + "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83", + "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091", + "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1", + "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", + "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1", + "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728", + "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16", + "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c", + "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", + "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7", + "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a", + "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730", + "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967", + "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25", + "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24", + "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055", + "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d", + "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0", + "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e", + "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", + "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c", + "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f", + "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd", + "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652", + "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8", + "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11", + "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333", + "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96", + "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64", + "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b", + "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e", + "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c", + "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9", + "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec", + "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb", + "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37", + "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad", + "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9", + "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c", + "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf", + "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", + "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f", + "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d", + "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09", + "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", + "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566", + "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74", + "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338", + "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", + "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c", + "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648", + "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84", + "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3", + "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123", + "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520", + "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831", + "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", + "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf", + "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b", + "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2", + "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3", + "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130", + "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b", + "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de", + "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5", + "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d", + "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00", + "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e" + ], + "markers": "python_version >= '3.9'", + "version": "==0.22.3" + }, "setuptools": { "hashes": [ - "sha256:5c4ccb41111392671f02bb5f8436dfc5a9a7185e80500531b133f5775c4163ef", - "sha256:87cb777c3b96d638ca02031192d40390e0ad97737e27b6b4fa831bea86f2f829" + "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", + "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d" ], "markers": "python_version >= '3.9'", - "version": "==75.5.0" + "version": "==75.6.0" }, "sniffio": { "hashes": [ @@ -539,79 +713,74 @@ }, "wrapt": { "hashes": [ - "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc", - "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81", - "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09", - "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e", - "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca", - "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0", - "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb", - "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487", - "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40", - "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c", - "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060", - "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202", - "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41", - "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9", - "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b", - "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664", - "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d", - "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362", - "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00", - "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc", - "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1", - "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267", - "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956", - "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966", - "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1", - "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228", - "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72", - "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d", - "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292", - "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0", - "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0", - "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36", - "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c", - "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5", - "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f", - "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73", - "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b", - "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2", - "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593", - "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39", - "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389", - "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf", - "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf", - "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89", - "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c", - "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c", - "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f", - "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440", - "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465", - "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136", - "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b", - "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8", - "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3", - "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8", - "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6", - "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e", - "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f", - "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c", - "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e", - "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8", - "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2", - "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020", - "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35", - "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d", - "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3", - "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537", - "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809", - "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d", - "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a", - "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4" + "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d", + "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301", + "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635", + "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a", + "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed", + "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721", + "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801", + "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b", + "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1", + "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88", + "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8", + "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0", + "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f", + "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578", + "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7", + "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045", + "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada", + "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d", + "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b", + "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a", + "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977", + "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea", + "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346", + "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13", + "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22", + "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339", + "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9", + "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181", + "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c", + "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90", + "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a", + "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489", + "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f", + "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504", + "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea", + "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569", + "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4", + "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce", + "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab", + "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a", + "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f", + "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c", + "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9", + "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf", + "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d", + "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627", + "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d", + "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4", + "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c", + "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d", + "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad", + "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b", + "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33", + "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371", + "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1", + "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393", + "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106", + "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df", + "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379", + "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451", + "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b", + "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575", + "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed", + "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb", + "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838" ], - "markers": "python_version >= '3.6'", - "version": "==1.16.0" + "markers": "python_version >= '3.8'", + "version": "==1.17.0" } }, "develop": { @@ -673,7 +842,7 @@ "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" ], - "markers": "python_version >= '3'", + "markers": "python_full_version >= '3.5.0'", "version": "==2.0.12" }, "click": { @@ -695,71 +864,71 @@ }, "coverage": { "hashes": [ - "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433", - "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529", - "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671", - "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e", - "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42", - "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99", - "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327", - "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8", - "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06", - "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874", - "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4", - "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354", - "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1", - "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab", - "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3", - "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b", - "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37", - "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd", - "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f", - "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b", - "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c", - "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b", - "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7", - "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3", - "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808", - "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a", - "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76", - "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469", - "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55", - "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289", - "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc", - "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13", - "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2", - "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30", - "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163", - "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d", - "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c", - "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1", - "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c", - "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2", - "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3", - "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314", - "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0", - "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384", - "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb", - "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c", - "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45", - "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a", - "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24", - "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8", - "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec", - "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56", - "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777", - "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b", - "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f", - "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a", - "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d", - "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9", - "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413", - "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c", - "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b", - "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c" + "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4", + "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c", + "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f", + "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b", + "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6", + "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae", + "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692", + "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4", + "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4", + "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717", + "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d", + "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198", + "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1", + "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3", + "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb", + "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d", + "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08", + "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf", + "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b", + "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710", + "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c", + "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae", + "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077", + "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00", + "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb", + "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664", + "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014", + "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9", + "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6", + "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e", + "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9", + "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa", + "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", + "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b", + "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a", + "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8", + "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030", + "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678", + "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015", + "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902", + "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97", + "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845", + "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419", + "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464", + "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be", + "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9", + "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7", + "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be", + "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1", + "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba", + "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5", + "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073", + "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4", + "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a", + "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a", + "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3", + "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599", + "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0", + "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b", + "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec", + "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1", + "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3" ], "markers": "python_version >= '3.9'", - "version": "==7.6.7" + "version": "==7.6.9" }, "flake8": { "hashes": [ @@ -821,40 +990,37 @@ }, "mypy": { "hashes": [ - "sha256:0680389c34284287fe00e82fc8bccdea9aff318f7e7d55b90d967a13a9606013", - "sha256:1767830da2d1afa4e62b684647af0ff79b401f004d7fa08bc5b0ce2d45bcd5ec", - "sha256:1ee5f99817ee70254e7eb5cf97c1b11dda29c6893d846c8b07bce449184e9466", - "sha256:262c543ef24deb10470a3c1c254bb986714e2b6b1a67d66daf836a548a9f316c", - "sha256:269f0dfb6463b8780333310ff4b5134425157ef0d2b1d614015adaf6d6a7eabd", - "sha256:2a3150d409609a775c8cb65dbe305c4edd7fe576c22ea79d77d1454acd9aeda8", - "sha256:2b6f85c2ad378e3224e017904a051b26660087b3b76490d533b7344f1546d3ff", - "sha256:3227f14fe943524f5794679156488f18bf8d34bfecd4623cf76bc55958d229c5", - "sha256:3ff201a0c6d3ea029d73b1648943387d75aa052491365b101f6edd5570d018ea", - "sha256:46897755f944176fbc504178422a5a2875bbf3f7436727374724842c0987b5af", - "sha256:47a9955214615108c3480a500cfda8513a0b1cd3c09a1ed42764ca0dd7b931dd", - "sha256:49082382f571c3186ce9ea0bd627cb1345d4da8d44a8377870f4442401f0a706", - "sha256:4a8a6c10f4c63fbf6ad6c03eba22c9331b3946a4cec97f008e9ffb4d3b31e8e2", - "sha256:6826d9c4d85bbf6d68cb279b561de6a4d8d778ca8e9ab2d00ee768ab501a9852", - "sha256:72382cb609142dba3f04140d016c94b4092bc7b4d98ca718740dc989e5271b8d", - "sha256:7da0005e47975287a92b43276e460ac1831af3d23032c34e67d003388a0ce8d0", - "sha256:8798c8ed83aa809f053abff08664bdca056038f5a02af3660de00b7290b64c47", - "sha256:8f1940325a8ed460ba03d19ab83742260fa9534804c317224e5d4e5aa588e2d6", - "sha256:8f694d6d09a460b117dccb6857dda269188e3437c880d7b60fa0014fa872d1e9", - "sha256:9b8f4a8213b1fd4b751e26b59ae0e0c12896568d7e805861035c7a15ed6dc9eb", - "sha256:9d851c09b981a65d9d283a8ccb5b1d0b698e580493416a10942ef1a04b19fd37", - "sha256:aaf1be63e0207d7d17be942dcf9a6b641745581fe6c64df9a38deb562a7dbafa", - "sha256:aba38e3dd66bdbafbbfe9c6e79637841928ea4c79b32e334099463c17b0d90ef", - "sha256:b08541a06eed35b543ae1a6b301590eb61826a1eb099417676ddc5a42aa151c5", - "sha256:be88d665e76b452c26fb2bdc3d54555c01226fba062b004ede780b190a50f9db", - "sha256:c76c769c46a1e6062a84837badcb2a7b0cdb153d68601a61f60739c37d41cc74", - "sha256:cc6019808580565040cd2a561b593d7c3c646badd7e580e07d875eb1bf35c695", - "sha256:cd2dd3730ba894ec2a2082cc703fbf3e95a08479f7be84912e3131fc68809d46", - "sha256:d555aa7f44cecb7ea3c0ac69d58b1a5afb92caa017285a8e9c4efbf0518b61b4", - "sha256:d847dd23540e2912d9667602271e5ebf25e5788e7da46da5ffd98e7872616e8e" + "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", + "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095", + "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac", + "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6", + "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", + "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", + "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00", + "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", + "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7", + "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13", + "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be", + "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", + "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850", + "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287", + "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", + "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229", + "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", + "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c", + "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac", + "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", + "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", + "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", + "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9", + "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", + "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf", + "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe", + "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==0.990" + "markers": "python_version >= '3.8'", + "version": "==1.11.0" }, "mypy-extensions": { "hashes": [ @@ -972,11 +1138,41 @@ }, "tomli": { "hashes": [ - "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8", - "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391" + "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", + "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", + "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", + "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", + "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", + "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", + "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", + "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", + "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", + "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", + "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", + "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", + "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", + "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", + "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", + "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", + "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", + "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", + "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", + "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", + "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", + "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" ], - "markers": "python_version < '3.11'", - "version": "==2.1.0" + "markers": "python_version >= '3.8'", + "version": "==2.2.1" }, "types-requests": { "hashes": [ diff --git a/hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py b/hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py index b68e8e98343..0905e1cdefd 100644 --- a/hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py +++ b/hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py @@ -6,7 +6,17 @@ from math import pi from subprocess import run, Popen from time import time -from typing import Callable, Coroutine, Dict, List, Optional, Tuple, Union, cast +from typing import ( + Callable, + Coroutine, + Dict, + List, + Optional, + Tuple, + Union, + cast, + Sequence, +) import atexit from opentrons_hardware.drivers.can_bus import DriverSettings, build, CanMessenger from opentrons_hardware.drivers.can_bus import settings as can_bus_settings @@ -146,7 +156,7 @@ def _create_attached_instruments_dict( async def update_firmware( - api: OT3API, force: bool = False, subsystems: Optional[List[SubSystem]] = None + api: OT3API, force: bool = False, subsystems: Optional[Sequence[SubSystem]] = None ) -> None: """Update firmware of OT3.""" if not api.is_simulator: diff --git a/hardware-testing/hardware_testing/opentrons_api/p1000_gen3_ul_per_mm.py b/hardware-testing/hardware_testing/opentrons_api/p1000_gen3_ul_per_mm.py index 9da7424eda4..ea6c7afef00 100644 --- a/hardware-testing/hardware_testing/opentrons_api/p1000_gen3_ul_per_mm.py +++ b/hardware-testing/hardware_testing/opentrons_api/p1000_gen3_ul_per_mm.py @@ -287,4 +287,4 @@ def overwrite_attached_pipette_ul_per_mm( pipette: Optional[Pipette] = api._pipette_handler._attached_instruments[mount] if pipette is None: raise RuntimeError(f"No pipette is attached to mount: {mount}") - pipette._config = replace(pipette._config, ul_per_mm=ul_per_mm) + pipette._config = replace(pipette._config, ul_per_mm=ul_per_mm) # type: ignore[type-var] diff --git a/hardware-testing/hardware_testing/production_qc/firmware_check.py b/hardware-testing/hardware_testing/production_qc/firmware_check.py index f84f5eb386c..097eab4dc76 100644 --- a/hardware-testing/hardware_testing/production_qc/firmware_check.py +++ b/hardware-testing/hardware_testing/production_qc/firmware_check.py @@ -1,6 +1,6 @@ """Firmware Check.""" from asyncio import run -from typing import List +from typing import Sequence from opentrons.hardware_control.ot3api import OT3API @@ -31,7 +31,7 @@ def _get_instrument_serial_number(api: OT3API, subsystem: SubSystem) -> str: return _id -async def _main(simulate: bool, subsystems: List[SubSystem]) -> None: +async def _main(simulate: bool, subsystems: Sequence[SubSystem]) -> None: api = await helpers_ot3.build_async_ot3_hardware_api(is_simulating=simulate) while True: for subsys, state in api.attached_subsystems.items(): diff --git a/hardware-testing/hardware_testing/production_qc/robot_assembly_qc_ot3/test_instruments.py b/hardware-testing/hardware_testing/production_qc/robot_assembly_qc_ot3/test_instruments.py index 45c1a7cc9c3..a9a86cc6d9b 100644 --- a/hardware-testing/hardware_testing/production_qc/robot_assembly_qc_ot3/test_instruments.py +++ b/hardware-testing/hardware_testing/production_qc/robot_assembly_qc_ot3/test_instruments.py @@ -58,7 +58,7 @@ def build_csv_lines() -> List[Union[CSVLine, CSVLineRepeating]]: for t, d in PIPETTE_TESTS.items(): for m in ["left", "right"]: tests.append(CSVLine(f"{m}-{t}", d)) # type: ignore[arg-type] - for t, d in GRIPPER_TESTS.items(): + for t, d in GRIPPER_TESTS.items(): # type: ignore[assignment] tests.append(CSVLine(f"gripper-{t}", d)) # type: ignore[arg-type] return tests diff --git a/hardware-testing/mypy.ini b/hardware-testing/mypy.ini index eeb271520a5..30f61a87de7 100644 --- a/hardware-testing/mypy.ini +++ b/hardware-testing/mypy.ini @@ -1,5 +1,6 @@ [mypy] show_error_codes = True +plugins = pydantic.mypy strict = False [mypy-can.*] diff --git a/hardware/Pipfile b/hardware/Pipfile index b02e50c7c51..aeb7992ccf7 100644 --- a/hardware/Pipfile +++ b/hardware/Pipfile @@ -8,13 +8,14 @@ python-can = "==4.2.2" pyserial = "==3.5" typing-extensions = ">=4.0.0,<5" numpy = "==1.22.3" -pydantic = "==1.9.2" +pydantic = "==2.9.0" +pydantic-settings = "==2.4.0" [dev-packages] pytest = "==7.4.4" pytest-lazy-fixture = "==0.6.3" pytest-cov = "==4.1.0" -mypy = "==1.8.0" +mypy = "==1.11.0" black = "==22.3.0" flake8 = "==7.0.0" flake8-annotations = "~=3.0.1" diff --git a/hardware/Pipfile.lock b/hardware/Pipfile.lock index ccab8884999..aa21398c5f2 100644 --- a/hardware/Pipfile.lock +++ b/hardware/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "04ae6d52e739cf67e21d13822316f7dc2030d272976c0a9cfd0f7d35db743301" + "sha256": "570a23b85a17fe0749ea5bc3d8f0e9c52b88608d795c507ce5adaf65744d8587" }, "pipfile-spec": 6, "requires": { @@ -16,67 +16,75 @@ ] }, "default": { + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "msgpack": { "hashes": [ - "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862", - "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d", - "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3", - "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672", - "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0", - "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9", - "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee", - "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46", - "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524", - "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819", - "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc", - "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc", - "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1", - "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82", - "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81", - "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6", - "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d", - "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2", - "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c", - "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87", - "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84", - "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e", - "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95", - "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f", - "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b", - "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93", - "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf", - "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61", - "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c", - "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8", - "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d", - "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c", - "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4", - "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba", - "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415", - "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee", - "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d", - "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9", - "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075", - "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f", - "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7", - "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681", - "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329", - "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1", - "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf", - "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c", - "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5", - "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b", - "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5", - "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e", - "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b", - "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad", - "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd", - "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7", - "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002", - "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc" + "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982", + "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3", + "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40", + "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee", + "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693", + "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950", + "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151", + "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24", + "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305", + "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b", + "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c", + "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659", + "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d", + "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18", + "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746", + "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868", + "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2", + "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba", + "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228", + "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2", + "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273", + "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c", + "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653", + "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a", + "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596", + "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd", + "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8", + "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa", + "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85", + "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc", + "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836", + "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3", + "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58", + "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128", + "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db", + "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f", + "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77", + "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad", + "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13", + "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8", + "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b", + "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a", + "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543", + "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b", + "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce", + "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d", + "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a", + "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c", + "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f", + "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e", + "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011", + "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04", + "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480", + "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a", + "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d", + "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d" ], "markers": "platform_system != 'Windows'", - "version": "==1.0.7" + "version": "==1.0.8" }, "numpy": { "hashes": [ @@ -107,53 +115,124 @@ }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==23.2" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pydantic": { "hashes": [ - "sha256:1061c6ee6204f4f5a27133126854948e3b3d51fcc16ead2e5d04378c199b2f44", - "sha256:19b5686387ea0d1ea52ecc4cffb71abb21702c5e5b2ac626fd4dbaa0834aa49d", - "sha256:2bd446bdb7755c3a94e56d7bdfd3ee92396070efa8ef3a34fab9579fe6aa1d84", - "sha256:328558c9f2eed77bd8fffad3cef39dbbe3edc7044517f4625a769d45d4cf7555", - "sha256:32e0b4fb13ad4db4058a7c3c80e2569adbd810c25e6ca3bbd8b2a9cc2cc871d7", - "sha256:3ee0d69b2a5b341fc7927e92cae7ddcfd95e624dfc4870b32a85568bd65e6131", - "sha256:4aafd4e55e8ad5bd1b19572ea2df546ccace7945853832bb99422a79c70ce9b8", - "sha256:4b3946f87e5cef3ba2e7bd3a4eb5a20385fe36521d6cc1ebf3c08a6697c6cfb3", - "sha256:4de71c718c9756d679420c69f216776c2e977459f77e8f679a4a961dc7304a56", - "sha256:5565a49effe38d51882cb7bac18bda013cdb34d80ac336428e8908f0b72499b0", - "sha256:5803ad846cdd1ed0d97eb00292b870c29c1f03732a010e66908ff48a762f20e4", - "sha256:5da164119602212a3fe7e3bc08911a89db4710ae51444b4224c2382fd09ad453", - "sha256:615661bfc37e82ac677543704437ff737418e4ea04bef9cf11c6d27346606044", - "sha256:78a4d6bdfd116a559aeec9a4cfe77dda62acc6233f8b56a716edad2651023e5e", - "sha256:7d0f183b305629765910eaad707800d2f47c6ac5bcfb8c6397abdc30b69eeb15", - "sha256:7ead3cd020d526f75b4188e0a8d71c0dbbe1b4b6b5dc0ea775a93aca16256aeb", - "sha256:84d76ecc908d917f4684b354a39fd885d69dd0491be175f3465fe4b59811c001", - "sha256:8cb0bc509bfb71305d7a59d00163d5f9fc4530f0881ea32c74ff4f74c85f3d3d", - "sha256:91089b2e281713f3893cd01d8e576771cd5bfdfbff5d0ed95969f47ef6d676c3", - "sha256:9c9e04a6cdb7a363d7cb3ccf0efea51e0abb48e180c0d31dca8d247967d85c6e", - "sha256:a8c5360a0297a713b4123608a7909e6869e1b56d0e96eb0d792c27585d40757f", - "sha256:afacf6d2a41ed91fc631bade88b1d319c51ab5418870802cedb590b709c5ae3c", - "sha256:b34ba24f3e2d0b39b43f0ca62008f7ba962cff51efa56e64ee25c4af6eed987b", - "sha256:bd67cb2c2d9602ad159389c29e4ca964b86fa2f35c2faef54c3eb28b4efd36c8", - "sha256:c0f5e142ef8217019e3eef6ae1b6b55f09a7a15972958d44fbd228214cede567", - "sha256:cdb4272678db803ddf94caa4f94f8672e9a46bae4a44f167095e4d06fec12979", - "sha256:d70916235d478404a3fa8c997b003b5f33aeac4686ac1baa767234a0f8ac2326", - "sha256:d8ce3fb0841763a89322ea0432f1f59a2d3feae07a63ea2c958b2315e1ae8adb", - "sha256:e0b214e57623a535936005797567231a12d0da0c29711eb3514bc2b3cd008d0f", - "sha256:e631c70c9280e3129f071635b81207cad85e6c08e253539467e4ead0e5b219aa", - "sha256:e78578f0c7481c850d1c969aca9a65405887003484d24f6110458fb02cca7747", - "sha256:f0ca86b525264daa5f6b192f216a0d1e860b7383e3da1c65a1908f9c02f42801", - "sha256:f1a68f4f65a9ee64b6ccccb5bf7e17db07caebd2730109cb8a95863cfa9c4e55", - "sha256:fafe841be1103f340a24977f61dee76172e4ae5f647ab9e7fd1e1fca51524f08", - "sha256:ff68fc85355532ea77559ede81f35fff79a6a5543477e168ab3a381887caea76" + "sha256:c7a8a9fdf7d100afa49647eae340e2d23efa382466a8d177efcd1381e9be5598", + "sha256:f66a7073abd93214a20c5f7b32d56843137a7a2e70d02111f3be287035c45370" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.9.0" + }, + "pydantic-core": { + "hashes": [ + "sha256:0102e49ac7d2df3379ef8d658d3bc59d3d769b0bdb17da189b75efa861fc07b4", + "sha256:0123655fedacf035ab10c23450163c2f65a4174f2bb034b188240a6cf06bb123", + "sha256:043ef8469f72609c4c3a5e06a07a1f713d53df4d53112c6d49207c0bd3c3bd9b", + "sha256:0448b81c3dfcde439551bb04a9f41d7627f676b12701865c8a2574bcea034437", + "sha256:05b366fb8fe3d8683b11ac35fa08947d7b92be78ec64e3277d03bd7f9b7cda79", + "sha256:07049ec9306ec64e955b2e7c40c8d77dd78ea89adb97a2013d0b6e055c5ee4c5", + "sha256:084414ffe9a85a52940b49631321d636dadf3576c30259607b75516d131fecd0", + "sha256:086c5db95157dc84c63ff9d96ebb8856f47ce113c86b61065a066f8efbe80acf", + "sha256:12625e69b1199e94b0ae1c9a95d000484ce9f0182f9965a26572f054b1537e44", + "sha256:16b25a4a120a2bb7dab51b81e3d9f3cde4f9a4456566c403ed29ac81bf49744f", + "sha256:19f1352fe4b248cae22a89268720fc74e83f008057a652894f08fa931e77dced", + "sha256:1a2ab4f410f4b886de53b6bddf5dd6f337915a29dd9f22f20f3099659536b2f6", + "sha256:1c7b81beaf7c7ebde978377dc53679c6cba0e946426fc7ade54251dfe24a7604", + "sha256:1cf842265a3a820ebc6388b963ead065f5ce8f2068ac4e1c713ef77a67b71f7c", + "sha256:1eb37f7d6a8001c0f86dc8ff2ee8d08291a536d76e49e78cda8587bb54d8b329", + "sha256:23af245b8f2f4ee9e2c99cb3f93d0e22fb5c16df3f2f643f5a8da5caff12a653", + "sha256:257d6a410a0d8aeb50b4283dea39bb79b14303e0fab0f2b9d617701331ed1515", + "sha256:276ae78153a94b664e700ac362587c73b84399bd1145e135287513442e7dfbc7", + "sha256:2b1a195efd347ede8bcf723e932300292eb13a9d2a3c1f84eb8f37cbbc905b7f", + "sha256:329a721253c7e4cbd7aad4a377745fbcc0607f9d72a3cc2102dd40519be75ed2", + "sha256:358331e21a897151e54d58e08d0219acf98ebb14c567267a87e971f3d2a3be59", + "sha256:3649bd3ae6a8ebea7dc381afb7f3c6db237fc7cebd05c8ac36ca8a4187b03b30", + "sha256:3713dc093d5048bfaedbba7a8dbc53e74c44a140d45ede020dc347dda18daf3f", + "sha256:3ef71ec876fcc4d3bbf2ae81961959e8d62f8d74a83d116668409c224012e3af", + "sha256:41ae8537ad371ec018e3c5da0eb3f3e40ee1011eb9be1da7f965357c4623c501", + "sha256:4a801c5e1e13272e0909c520708122496647d1279d252c9e6e07dac216accc41", + "sha256:4c83c64d05ffbbe12d4e8498ab72bdb05bcc1026340a4a597dc647a13c1605ec", + "sha256:4cebb9794f67266d65e7e4cbe5dcf063e29fc7b81c79dc9475bd476d9534150e", + "sha256:5668b3173bb0b2e65020b60d83f5910a7224027232c9f5dc05a71a1deac9f960", + "sha256:56e6a12ec8d7679f41b3750ffa426d22b44ef97be226a9bab00a03365f217b2b", + "sha256:582871902e1902b3c8e9b2c347f32a792a07094110c1bca6c2ea89b90150caac", + "sha256:5c8aa40f6ca803f95b1c1c5aeaee6237b9e879e4dfb46ad713229a63651a95fb", + "sha256:5d813fd871b3d5c3005157622ee102e8908ad6011ec915a18bd8fde673c4360e", + "sha256:5dd0ec5f514ed40e49bf961d49cf1bc2c72e9b50f29a163b2cc9030c6742aa73", + "sha256:5f3cf3721eaf8741cffaf092487f1ca80831202ce91672776b02b875580e174a", + "sha256:6294907eaaccf71c076abdd1c7954e272efa39bb043161b4b8aa1cd76a16ce43", + "sha256:64d094ea1aa97c6ded4748d40886076a931a8bf6f61b6e43e4a1041769c39dd2", + "sha256:6650a7bbe17a2717167e3e23c186849bae5cef35d38949549f1c116031b2b3aa", + "sha256:67b6655311b00581914aba481729971b88bb8bc7996206590700a3ac85e457b8", + "sha256:6b06c5d4e8701ac2ba99a2ef835e4e1b187d41095a9c619c5b185c9068ed2a49", + "sha256:6ce883906810b4c3bd90e0ada1f9e808d9ecf1c5f0b60c6b8831d6100bcc7dd6", + "sha256:6db09153d8438425e98cdc9a289c5fade04a5d2128faff8f227c459da21b9703", + "sha256:6f80fba4af0cb1d2344869d56430e304a51396b70d46b91a55ed4959993c0589", + "sha256:743e5811b0c377eb830150d675b0847a74a44d4ad5ab8845923d5b3a756d8100", + "sha256:753294d42fb072aa1775bfe1a2ba1012427376718fa4c72de52005a3d2a22178", + "sha256:7568f682c06f10f30ef643a1e8eec4afeecdafde5c4af1b574c6df079e96f96c", + "sha256:7706e15cdbf42f8fab1e6425247dfa98f4a6f8c63746c995d6a2017f78e619ae", + "sha256:785e7f517ebb9890813d31cb5d328fa5eda825bb205065cde760b3150e4de1f7", + "sha256:7a05c0240f6c711eb381ac392de987ee974fa9336071fb697768dfdb151345ce", + "sha256:7ce7eaf9a98680b4312b7cebcdd9352531c43db00fca586115845df388f3c465", + "sha256:7ce8e26b86a91e305858e018afc7a6e932f17428b1eaa60154bd1f7ee888b5f8", + "sha256:7d0324a35ab436c9d768753cbc3c47a865a2cbc0757066cb864747baa61f6ece", + "sha256:7e9b24cca4037a561422bf5dc52b38d390fb61f7bfff64053ce1b72f6938e6b2", + "sha256:810ca06cca91de9107718dc83d9ac4d2e86efd6c02cba49a190abcaf33fb0472", + "sha256:820f6ee5c06bc868335e3b6e42d7ef41f50dfb3ea32fbd523ab679d10d8741c0", + "sha256:82764c0bd697159fe9947ad59b6db6d7329e88505c8f98990eb07e84cc0a5d81", + "sha256:8ae65fdfb8a841556b52935dfd4c3f79132dc5253b12c0061b96415208f4d622", + "sha256:8d5b0ff3218858859910295df6953d7bafac3a48d5cd18f4e3ed9999efd2245f", + "sha256:95d6bf449a1ac81de562d65d180af5d8c19672793c81877a2eda8fde5d08f2fd", + "sha256:964c7aa318da542cdcc60d4a648377ffe1a2ef0eb1e996026c7f74507b720a78", + "sha256:96ef39add33ff58cd4c112cbac076726b96b98bb8f1e7f7595288dcfb2f10b57", + "sha256:a6612c2a844043e4d10a8324c54cdff0042c558eef30bd705770793d70b224aa", + "sha256:a8031074a397a5925d06b590121f8339d34a5a74cfe6970f8a1124eb8b83f4ac", + "sha256:aab9e522efff3993a9e98ab14263d4e20211e62da088298089a03056980a3e69", + "sha256:ae579143826c6f05a361d9546446c432a165ecf1c0b720bbfd81152645cb897d", + "sha256:ae90b9e50fe1bd115b24785e962b51130340408156d34d67b5f8f3fa6540938e", + "sha256:b18cf68255a476b927910c6873d9ed00da692bb293c5b10b282bd48a0afe3ae2", + "sha256:b7efb12e5071ad8d5b547487bdad489fbd4a5a35a0fc36a1941517a6ad7f23e0", + "sha256:c4d9f15ffe68bcd3898b0ad7233af01b15c57d91cd1667f8d868e0eacbfe3f87", + "sha256:c53100c8ee5a1e102766abde2158077d8c374bee0639201f11d3032e3555dfbc", + "sha256:c57e493a0faea1e4c38f860d6862ba6832723396c884fbf938ff5e9b224200e2", + "sha256:c8319e0bd6a7b45ad76166cc3d5d6a36c97d0c82a196f478c3ee5346566eebfd", + "sha256:caffda619099cfd4f63d48462f6aadbecee3ad9603b4b88b60cb821c1b258576", + "sha256:cc0c316fba3ce72ac3ab7902a888b9dc4979162d320823679da270c2d9ad0cad", + "sha256:cdd02a08205dc90238669f082747612cb3c82bd2c717adc60f9b9ecadb540f80", + "sha256:d50ac34835c6a4a0d456b5db559b82047403c4317b3bc73b3455fefdbdc54b0a", + "sha256:d6b9dd6aa03c812017411734e496c44fef29b43dba1e3dd1fa7361bbacfc1354", + "sha256:da3131ef2b940b99106f29dfbc30d9505643f766704e14c5d5e504e6a480c35e", + "sha256:da43cbe593e3c87d07108d0ebd73771dc414488f1f91ed2e204b0370b94b37ac", + "sha256:dd59638025160056687d598b054b64a79183f8065eae0d3f5ca523cde9943940", + "sha256:e1895e949f8849bc2757c0dbac28422a04be031204df46a56ab34bcf98507342", + "sha256:e1a79ad49f346aa1a2921f31e8dbbab4d64484823e813a002679eaa46cba39e1", + "sha256:e460475719721d59cd54a350c1f71c797c763212c836bf48585478c5514d2854", + "sha256:e64ffaf8f6e17ca15eb48344d86a7a741454526f3a3fa56bc493ad9d7ec63936", + "sha256:e6e3ccebdbd6e53474b0bb7ab8b88e83c0cfe91484b25e058e581348ee5a01a5", + "sha256:e758d271ed0286d146cf7c04c539a5169a888dd0b57026be621547e756af55bc", + "sha256:f087879f1ffde024dd2788a30d55acd67959dcf6c431e9d3682d1c491a0eb474", + "sha256:f477d26183e94eaafc60b983ab25af2a809a1b48ce4debb57b343f671b7a90b6", + "sha256:fc535cb898ef88333cf317777ecdfe0faac1c2a3187ef7eb061b6f7ecf7e6bae" + ], + "markers": "python_version >= '3.8'", + "version": "==2.23.2" + }, + "pydantic-settings": { + "hashes": [ + "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315", + "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88" ], "index": "pypi", - "markers": "python_full_version >= '3.6.1'", - "version": "==1.9.2" + "markers": "python_version >= '3.8'", + "version": "==2.4.0" }, "pyserial": { "hashes": [ @@ -172,22 +251,38 @@ "markers": "python_version >= '3.7'", "version": "==4.2.2" }, + "python-dotenv": { + "hashes": [ + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" + ], + "markers": "python_version >= '3.8'", + "version": "==1.0.1" + }, "setuptools": { "hashes": [ - "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05", - "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78" + "sha256:5f4c08aa4d3ebcb57a50c33b1b07e94315d7fc7230f7115e47fc99776c8ce308", + "sha256:95b40ed940a1c67eb70fc099094bd6e99c6ee7c23aa2306f4d2697ba7916f9c6" ], "markers": "python_version >= '3.8'", - "version": "==69.0.3" + "version": "==74.1.2" }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.12.2" + }, + "tzdata": { + "hashes": [ + "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", + "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.1" }, "wrapt": { "hashes": [ @@ -267,13 +362,21 @@ } }, "develop": { + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "black": { "hashes": [ @@ -315,114 +418,134 @@ }, "contourpy": { "hashes": [ - "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8", - "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956", - "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5", - "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063", - "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286", - "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a", - "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686", - "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9", - "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f", - "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4", - "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e", - "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0", - "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e", - "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488", - "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399", - "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431", - "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779", - "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9", - "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab", - "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0", - "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd", - "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e", - "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc", - "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6", - "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316", - "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808", - "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0", - "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f", - "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843", - "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9", - "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95", - "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9", - "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de", - "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4", - "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4", - "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa", - "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8", - "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776", - "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41", - "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108", - "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e", - "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8", - "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727", - "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a" + "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2", + "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9", + "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9", + "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4", + "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce", + "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7", + "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f", + "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922", + "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4", + "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e", + "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b", + "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619", + "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205", + "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480", + "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965", + "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c", + "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd", + "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5", + "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f", + "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc", + "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec", + "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd", + "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b", + "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9", + "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe", + "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce", + "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609", + "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8", + "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0", + "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f", + "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8", + "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b", + "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364", + "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040", + "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f", + "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083", + "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df", + "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba", + "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445", + "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da", + "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3", + "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72", + "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02", + "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985" ], "markers": "python_version >= '3.9'", - "version": "==1.2.0" + "version": "==1.2.1" }, "coverage": { "extras": [ "toml" ], "hashes": [ - "sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca", - "sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471", - "sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a", - "sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058", - "sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85", - "sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143", - "sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446", - "sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590", - "sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a", - "sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105", - "sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9", - "sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a", - "sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac", - "sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25", - "sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2", - "sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450", - "sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932", - "sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba", - "sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137", - "sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae", - "sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614", - "sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70", - "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e", - "sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505", - "sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870", - "sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc", - "sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451", - "sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7", - "sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e", - "sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566", - "sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5", - "sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26", - "sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2", - "sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42", - "sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555", - "sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43", - "sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed", - "sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa", - "sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516", - "sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952", - "sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd", - "sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09", - "sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c", - "sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f", - "sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6", - "sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1", - "sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0", - "sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e", - "sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9", - "sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9", - "sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e", - "sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06" + "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", + "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", + "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", + "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989", + "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", + "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", + "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", + "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", + "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", + "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", + "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", + "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", + "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", + "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", + "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", + "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8", + "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", + "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", + "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", + "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", + "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", + "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", + "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", + "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", + "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", + "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0", + "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", + "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", + "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", + "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", + "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", + "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", + "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", + "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", + "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de", + "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", + "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", + "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569", + "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", + "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", + "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", + "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", + "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", + "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6", + "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", + "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", + "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", + "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", + "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", + "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b", + "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", + "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", + "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3", + "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", + "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", + "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", + "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", + "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", + "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", + "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", + "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", + "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", + "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7", + "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", + "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", + "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", + "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", + "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", + "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a", + "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", + "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", + "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc" ], "markers": "python_version >= '3.8'", - "version": "==7.4.0" + "version": "==7.6.1" }, "cycler": { "hashes": [ @@ -434,11 +557,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", - "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.0" + "version": "==1.2.2" }, "flake8": { "hashes": [ @@ -478,60 +601,60 @@ }, "fonttools": { "hashes": [ - "sha256:0255dbc128fee75fb9be364806b940ed450dd6838672a150d501ee86523ac61e", - "sha256:0a00bd0e68e88987dcc047ea31c26d40a3c61185153b03457956a87e39d43c37", - "sha256:0a1d313a415eaaba2b35d6cd33536560deeebd2ed758b9bfb89ab5d97dc5deac", - "sha256:0f750037e02beb8b3569fbff701a572e62a685d2a0e840d75816592280e5feae", - "sha256:13819db8445a0cec8c3ff5f243af6418ab19175072a9a92f6cc8ca7d1452754b", - "sha256:254d9a6f7be00212bf0c3159e0a420eb19c63793b2c05e049eb337f3023c5ecc", - "sha256:29495d6d109cdbabe73cfb6f419ce67080c3ef9ea1e08d5750240fd4b0c4763b", - "sha256:32ab2e9702dff0dd4510c7bb958f265a8d3dd5c0e2547e7b5f7a3df4979abb07", - "sha256:3480eeb52770ff75140fe7d9a2ec33fb67b07efea0ab5129c7e0c6a639c40c70", - "sha256:3a808f3c1d1df1f5bf39be869b6e0c263570cdafb5bdb2df66087733f566ea71", - "sha256:3b629108351d25512d4ea1a8393a2dba325b7b7d7308116b605ea3f8e1be88df", - "sha256:3d71606c9321f6701642bd4746f99b6089e53d7e9817fc6b964e90d9c5f0ecc6", - "sha256:3e2b95dce2ead58fb12524d0ca7d63a63459dd489e7e5838c3cd53557f8933e1", - "sha256:4a5a5318ba5365d992666ac4fe35365f93004109d18858a3e18ae46f67907670", - "sha256:4c811d3c73b6abac275babb8aa439206288f56fdb2c6f8835e3d7b70de8937a7", - "sha256:4e743935139aa485fe3253fc33fe467eab6ea42583fa681223ea3f1a93dd01e6", - "sha256:4ec558c543609e71b2275c4894e93493f65d2f41c15fe1d089080c1d0bb4d635", - "sha256:5465df494f20a7d01712b072ae3ee9ad2887004701b95cb2cc6dcb9c2c97a899", - "sha256:5b60e3afa9635e3dfd3ace2757039593e3bd3cf128be0ddb7a1ff4ac45fa5a50", - "sha256:63fbed184979f09a65aa9c88b395ca539c94287ba3a364517698462e13e457c9", - "sha256:69731e8bea0578b3c28fdb43dbf95b9386e2d49a399e9a4ad736b8e479b08085", - "sha256:6dd58cc03016b281bd2c74c84cdaa6bd3ce54c5a7f47478b7657b930ac3ed8eb", - "sha256:740947906590a878a4bde7dd748e85fefa4d470a268b964748403b3ab2aeed6c", - "sha256:7df26dd3650e98ca45f1e29883c96a0b9f5bb6af8d632a6a108bc744fa0bd9b3", - "sha256:7eb7ad665258fba68fd22228a09f347469d95a97fb88198e133595947a20a184", - "sha256:7ee48bd9d6b7e8f66866c9090807e3a4a56cf43ffad48962725a190e0dd774c8", - "sha256:86e0427864c6c91cf77f16d1fb9bf1bbf7453e824589e8fb8461b6ee1144f506", - "sha256:8f57ecd742545362a0f7186774b2d1c53423ed9ece67689c93a1055b236f638c", - "sha256:90f898cdd67f52f18049250a6474185ef6544c91f27a7bee70d87d77a8daf89c", - "sha256:94208ea750e3f96e267f394d5588579bb64cc628e321dbb1d4243ffbc291b18b", - "sha256:a1c154bb85dc9a4cf145250c88d112d88eb414bad81d4cb524d06258dea1bdc0", - "sha256:a5d77479fb885ef38a16a253a2f4096bc3d14e63a56d6246bfdb56365a12b20c", - "sha256:a86a5ab2873ed2575d0fcdf1828143cfc6b977ac448e3dc616bb1e3d20efbafa", - "sha256:ac71e2e201df041a2891067dc36256755b1229ae167edbdc419b16da78732c2f", - "sha256:b3e1304e5f19ca861d86a72218ecce68f391646d85c851742d265787f55457a4", - "sha256:b8be28c036b9f186e8c7eaf8a11b42373e7e4949f9e9f370202b9da4c4c3f56c", - "sha256:c19044256c44fe299d9a73456aabee4b4d06c6b930287be93b533b4737d70aa1", - "sha256:d49ce3ea7b7173faebc5664872243b40cf88814ca3eb135c4a3cdff66af71946", - "sha256:e040f905d542362e07e72e03612a6270c33d38281fd573160e1003e43718d68d", - "sha256:eabae77a07c41ae0b35184894202305c3ad211a93b2eb53837c2a1143c8bc952", - "sha256:f791446ff297fd5f1e2247c188de53c1bfb9dd7f0549eba55b73a3c2087a2703", - "sha256:f83a4daef6d2a202acb9bf572958f91cfde5b10c8ee7fb1d09a4c81e5d851fd8" + "sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122", + "sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397", + "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f", + "sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d", + "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60", + "sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169", + "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8", + "sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31", + "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923", + "sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2", + "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb", + "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab", + "sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb", + "sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a", + "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670", + "sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8", + "sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407", + "sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671", + "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88", + "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f", + "sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f", + "sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0", + "sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb", + "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2", + "sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d", + "sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c", + "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3", + "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719", + "sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749", + "sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4", + "sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f", + "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02", + "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58", + "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1", + "sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41", + "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4", + "sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb", + "sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb", + "sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3", + "sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d", + "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d", + "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2" ], "markers": "python_version >= '3.8'", - "version": "==4.47.2" + "version": "==4.53.1" }, "hypothesis": { "hashes": [ - "sha256:848ea0952f0bdfd02eac59e41b03f1cbba8fa2cffeffa8db328bbd6cfe159974", - "sha256:955a57e56be4607c81c17ca53e594af54aadeed91e07b88bb7f84e8208ea7739" + "sha256:2beb7a148e95a2067563bcca017d71cc286805c792e43ec5cb155ed6d0a1990d", + "sha256:3b0d080bfd3b303e91388507ac7edebd7039ffcc96ac2cfcdc3c45806352c09f" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==6.96.1" + "version": "==6.96.4" }, "iniconfig": { "hashes": [ @@ -543,155 +666,174 @@ }, "jsonschema": { "hashes": [ - "sha256:5f9c0a719ca2ce14c5de2fd350a64fd2d13e8539db29836a86adc990bb1a068f", - "sha256:8d4a2b7b6c2237e0199c8ea1a6d3e05bf118e289ae2b9d7ba444182a2959560d" + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" ], - "version": "==3.0.2" + "markers": "python_version >= '3.8'", + "version": "==4.23.0" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc", + "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" + ], + "markers": "python_version >= '3.8'", + "version": "==2023.12.1" }, "kiwisolver": { "hashes": [ - "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf", - "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e", - "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af", - "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f", - "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046", - "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3", - "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5", - "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71", - "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee", - "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3", - "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9", - "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b", - "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985", - "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea", - "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16", - "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89", - "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c", - "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9", - "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712", - "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342", - "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a", - "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958", - "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d", - "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a", - "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130", - "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff", - "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898", - "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b", - "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f", - "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265", - "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93", - "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929", - "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635", - "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709", - "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b", - "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb", - "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a", - "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920", - "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e", - "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544", - "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45", - "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390", - "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77", - "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355", - "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff", - "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4", - "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7", - "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20", - "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c", - "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162", - "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228", - "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437", - "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc", - "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a", - "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901", - "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4", - "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770", - "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525", - "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad", - "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a", - "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29", - "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90", - "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250", - "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d", - "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3", - "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54", - "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f", - "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1", - "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da", - "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238", - "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa", - "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523", - "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0", - "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205", - "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3", - "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4", - "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac", - "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9", - "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb", - "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced", - "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd", - "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0", - "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da", - "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18", - "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9", - "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276", - "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333", - "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b", - "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db", - "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126", - "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9", - "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09", - "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0", - "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec", - "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7", - "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff", - "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9", - "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192", - "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8", - "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d", - "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6", - "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797", - "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892", - "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f" + "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a", + "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95", + "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5", + "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0", + "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d", + "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18", + "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b", + "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258", + "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95", + "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e", + "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383", + "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02", + "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b", + "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523", + "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee", + "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88", + "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd", + "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb", + "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4", + "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e", + "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c", + "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935", + "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee", + "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e", + "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038", + "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d", + "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b", + "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5", + "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107", + "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f", + "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2", + "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17", + "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb", + "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674", + "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706", + "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327", + "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3", + "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a", + "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2", + "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f", + "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948", + "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3", + "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e", + "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545", + "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc", + "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f", + "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650", + "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a", + "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8", + "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750", + "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b", + "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34", + "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225", + "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51", + "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c", + "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3", + "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde", + "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599", + "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c", + "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76", + "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6", + "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39", + "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9", + "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933", + "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad", + "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520", + "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1", + "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503", + "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b", + "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36", + "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a", + "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643", + "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60", + "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483", + "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf", + "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d", + "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6", + "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644", + "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2", + "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9", + "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2", + "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640", + "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade", + "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a", + "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c", + "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6", + "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00", + "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27", + "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2", + "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4", + "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379", + "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54", + "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09", + "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a", + "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c", + "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89", + "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407", + "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904", + "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376", + "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583", + "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278", + "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a", + "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d", + "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935", + "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb", + "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895", + "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b", + "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417", + "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608", + "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07", + "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05", + "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a", + "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d", + "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052" ], - "markers": "python_version >= '3.7'", - "version": "==1.4.5" + "markers": "python_version >= '3.8'", + "version": "==1.4.7" }, "matplotlib": { "hashes": [ - "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1", - "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0", - "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4", - "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7", - "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630", - "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89", - "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d", - "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717", - "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a", - "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627", - "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31", - "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213", - "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843", - "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788", - "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367", - "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4", - "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a", - "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8", - "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b", - "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18", - "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6", - "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa", - "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917", - "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20", - "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331", - "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63", - "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f", - "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8" + "sha256:1c13f041a7178f9780fb61cc3a2b10423d5e125480e4be51beaf62b172413b67", + "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c", + "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94", + "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb", + "sha256:606e3b90897554c989b1e38a258c626d46c873523de432b1462f295db13de6f9", + "sha256:6209e5c9aaccc056e63b547a8152661324404dd92340a6e479b3a7f24b42a5d0", + "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616", + "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa", + "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661", + "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a", + "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae", + "sha256:843cbde2f0946dadd8c5c11c6d91847abd18ec76859dc319362a0964493f0ba6", + "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea", + "sha256:8f65c9f002d281a6e904976007b2d46a1ee2bcea3a68a8c12dda24709ddc9106", + "sha256:90df07db7b599fe7035d2f74ab7e438b656528c68ba6bb59b7dc46af39ee48ef", + "sha256:9bb0189011785ea794ee827b68777db3ca3f93f3e339ea4d920315a0e5a78d54", + "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f", + "sha256:abc9d838f93583650c35eca41cfcec65b2e7cb50fd486da6f0c49b5e1ed23014", + "sha256:ac24233e8f2939ac4fd2919eed1e9c0871eac8057666070e94cbf0b33dd9c338", + "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25", + "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b", + "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35", + "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732", + "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71", + "sha256:ce1edd9f5383b504dbc26eeea404ed0a00656c526638129028b758fd43fc5f10", + "sha256:ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0", + "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30", + "sha256:fb44f53af0a62dc80bba4443d9b27f2fde6acfdac281d95bc872dc148a6509cc" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==3.8.2" + "version": "==3.8.4" }, "mccabe": { "hashes": [ @@ -712,37 +854,37 @@ }, "mypy": { "hashes": [ - "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6", - "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d", - "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02", - "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d", - "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3", - "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3", - "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", - "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66", - "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259", - "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", - "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd", - "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", - "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8", - "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", - "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b", - "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e", - "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6", - "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", - "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9", - "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", - "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a", - "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592", - "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218", - "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", - "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4", - "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410", - "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" + "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", + "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095", + "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac", + "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6", + "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", + "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", + "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00", + "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", + "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7", + "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13", + "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be", + "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", + "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850", + "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287", + "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", + "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229", + "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", + "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c", + "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac", + "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", + "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", + "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", + "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9", + "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", + "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf", + "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe", + "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.8.0" + "version": "==1.11.0" }, "mypy-extensions": { "hashes": [ @@ -781,16 +923,16 @@ }, "opentrons-shared-data": { "editable": true, - "markers": "python_version >= '3.7'", + "markers": "python_version >= '3.10'", "path": "../shared-data/python" }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==23.2" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pathspec": { "hashes": [ @@ -802,93 +944,105 @@ }, "pillow": { "hashes": [ - "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8", - "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39", - "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac", - "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869", - "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e", - "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04", - "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9", - "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e", - "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe", - "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef", - "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56", - "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa", - "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f", - "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f", - "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e", - "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a", - "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2", - "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2", - "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5", - "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a", - "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2", - "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213", - "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563", - "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591", - "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c", - "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2", - "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb", - "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757", - "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0", - "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452", - "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad", - "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01", - "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f", - "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5", - "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61", - "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e", - "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b", - "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068", - "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9", - "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588", - "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483", - "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f", - "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67", - "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7", - "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311", - "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6", - "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72", - "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6", - "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129", - "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13", - "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67", - "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c", - "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516", - "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e", - "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e", - "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364", - "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023", - "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1", - "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04", - "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d", - "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a", - "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7", - "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb", - "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4", - "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e", - "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1", - "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48", - "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868" + "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", + "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", + "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df", + "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", + "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c", + "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d", + "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd", + "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", + "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908", + "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", + "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be", + "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0", + "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b", + "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80", + "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a", + "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e", + "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9", + "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696", + "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b", + "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309", + "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", + "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab", + "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", + "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", + "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d", + "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", + "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", + "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3", + "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6", + "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb", + "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94", + "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", + "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496", + "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0", + "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319", + "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b", + "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", + "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef", + "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680", + "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b", + "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", + "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", + "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597", + "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", + "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8", + "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3", + "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736", + "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", + "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126", + "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd", + "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5", + "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b", + "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", + "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b", + "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", + "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", + "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2", + "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c", + "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe", + "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", + "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a", + "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70", + "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca", + "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b", + "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91", + "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3", + "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84", + "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1", + "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", + "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be", + "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", + "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc", + "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", + "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e", + "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", + "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef", + "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22", + "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27", + "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", + "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1" ], "markers": "python_version >= '3.8'", - "version": "==10.2.0" + "version": "==10.4.0" }, "platformdirs": { "hashes": [ - "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380", - "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420" + "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", + "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" ], "markers": "python_version >= '3.8'", - "version": "==4.1.0" + "version": "==4.2.2" }, "pluggy": { "hashes": [ - "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", - "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.3.0" + "version": "==1.5.0" }, "pycodestyle": { "hashes": [ @@ -900,45 +1054,107 @@ }, "pydantic": { "hashes": [ - "sha256:1061c6ee6204f4f5a27133126854948e3b3d51fcc16ead2e5d04378c199b2f44", - "sha256:19b5686387ea0d1ea52ecc4cffb71abb21702c5e5b2ac626fd4dbaa0834aa49d", - "sha256:2bd446bdb7755c3a94e56d7bdfd3ee92396070efa8ef3a34fab9579fe6aa1d84", - "sha256:328558c9f2eed77bd8fffad3cef39dbbe3edc7044517f4625a769d45d4cf7555", - "sha256:32e0b4fb13ad4db4058a7c3c80e2569adbd810c25e6ca3bbd8b2a9cc2cc871d7", - "sha256:3ee0d69b2a5b341fc7927e92cae7ddcfd95e624dfc4870b32a85568bd65e6131", - "sha256:4aafd4e55e8ad5bd1b19572ea2df546ccace7945853832bb99422a79c70ce9b8", - "sha256:4b3946f87e5cef3ba2e7bd3a4eb5a20385fe36521d6cc1ebf3c08a6697c6cfb3", - "sha256:4de71c718c9756d679420c69f216776c2e977459f77e8f679a4a961dc7304a56", - "sha256:5565a49effe38d51882cb7bac18bda013cdb34d80ac336428e8908f0b72499b0", - "sha256:5803ad846cdd1ed0d97eb00292b870c29c1f03732a010e66908ff48a762f20e4", - "sha256:5da164119602212a3fe7e3bc08911a89db4710ae51444b4224c2382fd09ad453", - "sha256:615661bfc37e82ac677543704437ff737418e4ea04bef9cf11c6d27346606044", - "sha256:78a4d6bdfd116a559aeec9a4cfe77dda62acc6233f8b56a716edad2651023e5e", - "sha256:7d0f183b305629765910eaad707800d2f47c6ac5bcfb8c6397abdc30b69eeb15", - "sha256:7ead3cd020d526f75b4188e0a8d71c0dbbe1b4b6b5dc0ea775a93aca16256aeb", - "sha256:84d76ecc908d917f4684b354a39fd885d69dd0491be175f3465fe4b59811c001", - "sha256:8cb0bc509bfb71305d7a59d00163d5f9fc4530f0881ea32c74ff4f74c85f3d3d", - "sha256:91089b2e281713f3893cd01d8e576771cd5bfdfbff5d0ed95969f47ef6d676c3", - "sha256:9c9e04a6cdb7a363d7cb3ccf0efea51e0abb48e180c0d31dca8d247967d85c6e", - "sha256:a8c5360a0297a713b4123608a7909e6869e1b56d0e96eb0d792c27585d40757f", - "sha256:afacf6d2a41ed91fc631bade88b1d319c51ab5418870802cedb590b709c5ae3c", - "sha256:b34ba24f3e2d0b39b43f0ca62008f7ba962cff51efa56e64ee25c4af6eed987b", - "sha256:bd67cb2c2d9602ad159389c29e4ca964b86fa2f35c2faef54c3eb28b4efd36c8", - "sha256:c0f5e142ef8217019e3eef6ae1b6b55f09a7a15972958d44fbd228214cede567", - "sha256:cdb4272678db803ddf94caa4f94f8672e9a46bae4a44f167095e4d06fec12979", - "sha256:d70916235d478404a3fa8c997b003b5f33aeac4686ac1baa767234a0f8ac2326", - "sha256:d8ce3fb0841763a89322ea0432f1f59a2d3feae07a63ea2c958b2315e1ae8adb", - "sha256:e0b214e57623a535936005797567231a12d0da0c29711eb3514bc2b3cd008d0f", - "sha256:e631c70c9280e3129f071635b81207cad85e6c08e253539467e4ead0e5b219aa", - "sha256:e78578f0c7481c850d1c969aca9a65405887003484d24f6110458fb02cca7747", - "sha256:f0ca86b525264daa5f6b192f216a0d1e860b7383e3da1c65a1908f9c02f42801", - "sha256:f1a68f4f65a9ee64b6ccccb5bf7e17db07caebd2730109cb8a95863cfa9c4e55", - "sha256:fafe841be1103f340a24977f61dee76172e4ae5f647ab9e7fd1e1fca51524f08", - "sha256:ff68fc85355532ea77559ede81f35fff79a6a5543477e168ab3a381887caea76" + "sha256:c7a8a9fdf7d100afa49647eae340e2d23efa382466a8d177efcd1381e9be5598", + "sha256:f66a7073abd93214a20c5f7b32d56843137a7a2e70d02111f3be287035c45370" ], "index": "pypi", - "markers": "python_full_version >= '3.6.1'", - "version": "==1.9.2" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" + }, + "pydantic-core": { + "hashes": [ + "sha256:0102e49ac7d2df3379ef8d658d3bc59d3d769b0bdb17da189b75efa861fc07b4", + "sha256:0123655fedacf035ab10c23450163c2f65a4174f2bb034b188240a6cf06bb123", + "sha256:043ef8469f72609c4c3a5e06a07a1f713d53df4d53112c6d49207c0bd3c3bd9b", + "sha256:0448b81c3dfcde439551bb04a9f41d7627f676b12701865c8a2574bcea034437", + "sha256:05b366fb8fe3d8683b11ac35fa08947d7b92be78ec64e3277d03bd7f9b7cda79", + "sha256:07049ec9306ec64e955b2e7c40c8d77dd78ea89adb97a2013d0b6e055c5ee4c5", + "sha256:084414ffe9a85a52940b49631321d636dadf3576c30259607b75516d131fecd0", + "sha256:086c5db95157dc84c63ff9d96ebb8856f47ce113c86b61065a066f8efbe80acf", + "sha256:12625e69b1199e94b0ae1c9a95d000484ce9f0182f9965a26572f054b1537e44", + "sha256:16b25a4a120a2bb7dab51b81e3d9f3cde4f9a4456566c403ed29ac81bf49744f", + "sha256:19f1352fe4b248cae22a89268720fc74e83f008057a652894f08fa931e77dced", + "sha256:1a2ab4f410f4b886de53b6bddf5dd6f337915a29dd9f22f20f3099659536b2f6", + "sha256:1c7b81beaf7c7ebde978377dc53679c6cba0e946426fc7ade54251dfe24a7604", + "sha256:1cf842265a3a820ebc6388b963ead065f5ce8f2068ac4e1c713ef77a67b71f7c", + "sha256:1eb37f7d6a8001c0f86dc8ff2ee8d08291a536d76e49e78cda8587bb54d8b329", + "sha256:23af245b8f2f4ee9e2c99cb3f93d0e22fb5c16df3f2f643f5a8da5caff12a653", + "sha256:257d6a410a0d8aeb50b4283dea39bb79b14303e0fab0f2b9d617701331ed1515", + "sha256:276ae78153a94b664e700ac362587c73b84399bd1145e135287513442e7dfbc7", + "sha256:2b1a195efd347ede8bcf723e932300292eb13a9d2a3c1f84eb8f37cbbc905b7f", + "sha256:329a721253c7e4cbd7aad4a377745fbcc0607f9d72a3cc2102dd40519be75ed2", + "sha256:358331e21a897151e54d58e08d0219acf98ebb14c567267a87e971f3d2a3be59", + "sha256:3649bd3ae6a8ebea7dc381afb7f3c6db237fc7cebd05c8ac36ca8a4187b03b30", + "sha256:3713dc093d5048bfaedbba7a8dbc53e74c44a140d45ede020dc347dda18daf3f", + "sha256:3ef71ec876fcc4d3bbf2ae81961959e8d62f8d74a83d116668409c224012e3af", + "sha256:41ae8537ad371ec018e3c5da0eb3f3e40ee1011eb9be1da7f965357c4623c501", + "sha256:4a801c5e1e13272e0909c520708122496647d1279d252c9e6e07dac216accc41", + "sha256:4c83c64d05ffbbe12d4e8498ab72bdb05bcc1026340a4a597dc647a13c1605ec", + "sha256:4cebb9794f67266d65e7e4cbe5dcf063e29fc7b81c79dc9475bd476d9534150e", + "sha256:5668b3173bb0b2e65020b60d83f5910a7224027232c9f5dc05a71a1deac9f960", + "sha256:56e6a12ec8d7679f41b3750ffa426d22b44ef97be226a9bab00a03365f217b2b", + "sha256:582871902e1902b3c8e9b2c347f32a792a07094110c1bca6c2ea89b90150caac", + "sha256:5c8aa40f6ca803f95b1c1c5aeaee6237b9e879e4dfb46ad713229a63651a95fb", + "sha256:5d813fd871b3d5c3005157622ee102e8908ad6011ec915a18bd8fde673c4360e", + "sha256:5dd0ec5f514ed40e49bf961d49cf1bc2c72e9b50f29a163b2cc9030c6742aa73", + "sha256:5f3cf3721eaf8741cffaf092487f1ca80831202ce91672776b02b875580e174a", + "sha256:6294907eaaccf71c076abdd1c7954e272efa39bb043161b4b8aa1cd76a16ce43", + "sha256:64d094ea1aa97c6ded4748d40886076a931a8bf6f61b6e43e4a1041769c39dd2", + "sha256:6650a7bbe17a2717167e3e23c186849bae5cef35d38949549f1c116031b2b3aa", + "sha256:67b6655311b00581914aba481729971b88bb8bc7996206590700a3ac85e457b8", + "sha256:6b06c5d4e8701ac2ba99a2ef835e4e1b187d41095a9c619c5b185c9068ed2a49", + "sha256:6ce883906810b4c3bd90e0ada1f9e808d9ecf1c5f0b60c6b8831d6100bcc7dd6", + "sha256:6db09153d8438425e98cdc9a289c5fade04a5d2128faff8f227c459da21b9703", + "sha256:6f80fba4af0cb1d2344869d56430e304a51396b70d46b91a55ed4959993c0589", + "sha256:743e5811b0c377eb830150d675b0847a74a44d4ad5ab8845923d5b3a756d8100", + "sha256:753294d42fb072aa1775bfe1a2ba1012427376718fa4c72de52005a3d2a22178", + "sha256:7568f682c06f10f30ef643a1e8eec4afeecdafde5c4af1b574c6df079e96f96c", + "sha256:7706e15cdbf42f8fab1e6425247dfa98f4a6f8c63746c995d6a2017f78e619ae", + "sha256:785e7f517ebb9890813d31cb5d328fa5eda825bb205065cde760b3150e4de1f7", + "sha256:7a05c0240f6c711eb381ac392de987ee974fa9336071fb697768dfdb151345ce", + "sha256:7ce7eaf9a98680b4312b7cebcdd9352531c43db00fca586115845df388f3c465", + "sha256:7ce8e26b86a91e305858e018afc7a6e932f17428b1eaa60154bd1f7ee888b5f8", + "sha256:7d0324a35ab436c9d768753cbc3c47a865a2cbc0757066cb864747baa61f6ece", + "sha256:7e9b24cca4037a561422bf5dc52b38d390fb61f7bfff64053ce1b72f6938e6b2", + "sha256:810ca06cca91de9107718dc83d9ac4d2e86efd6c02cba49a190abcaf33fb0472", + "sha256:820f6ee5c06bc868335e3b6e42d7ef41f50dfb3ea32fbd523ab679d10d8741c0", + "sha256:82764c0bd697159fe9947ad59b6db6d7329e88505c8f98990eb07e84cc0a5d81", + "sha256:8ae65fdfb8a841556b52935dfd4c3f79132dc5253b12c0061b96415208f4d622", + "sha256:8d5b0ff3218858859910295df6953d7bafac3a48d5cd18f4e3ed9999efd2245f", + "sha256:95d6bf449a1ac81de562d65d180af5d8c19672793c81877a2eda8fde5d08f2fd", + "sha256:964c7aa318da542cdcc60d4a648377ffe1a2ef0eb1e996026c7f74507b720a78", + "sha256:96ef39add33ff58cd4c112cbac076726b96b98bb8f1e7f7595288dcfb2f10b57", + "sha256:a6612c2a844043e4d10a8324c54cdff0042c558eef30bd705770793d70b224aa", + "sha256:a8031074a397a5925d06b590121f8339d34a5a74cfe6970f8a1124eb8b83f4ac", + "sha256:aab9e522efff3993a9e98ab14263d4e20211e62da088298089a03056980a3e69", + "sha256:ae579143826c6f05a361d9546446c432a165ecf1c0b720bbfd81152645cb897d", + "sha256:ae90b9e50fe1bd115b24785e962b51130340408156d34d67b5f8f3fa6540938e", + "sha256:b18cf68255a476b927910c6873d9ed00da692bb293c5b10b282bd48a0afe3ae2", + "sha256:b7efb12e5071ad8d5b547487bdad489fbd4a5a35a0fc36a1941517a6ad7f23e0", + "sha256:c4d9f15ffe68bcd3898b0ad7233af01b15c57d91cd1667f8d868e0eacbfe3f87", + "sha256:c53100c8ee5a1e102766abde2158077d8c374bee0639201f11d3032e3555dfbc", + "sha256:c57e493a0faea1e4c38f860d6862ba6832723396c884fbf938ff5e9b224200e2", + "sha256:c8319e0bd6a7b45ad76166cc3d5d6a36c97d0c82a196f478c3ee5346566eebfd", + "sha256:caffda619099cfd4f63d48462f6aadbecee3ad9603b4b88b60cb821c1b258576", + "sha256:cc0c316fba3ce72ac3ab7902a888b9dc4979162d320823679da270c2d9ad0cad", + "sha256:cdd02a08205dc90238669f082747612cb3c82bd2c717adc60f9b9ecadb540f80", + "sha256:d50ac34835c6a4a0d456b5db559b82047403c4317b3bc73b3455fefdbdc54b0a", + "sha256:d6b9dd6aa03c812017411734e496c44fef29b43dba1e3dd1fa7361bbacfc1354", + "sha256:da3131ef2b940b99106f29dfbc30d9505643f766704e14c5d5e504e6a480c35e", + "sha256:da43cbe593e3c87d07108d0ebd73771dc414488f1f91ed2e204b0370b94b37ac", + "sha256:dd59638025160056687d598b054b64a79183f8065eae0d3f5ca523cde9943940", + "sha256:e1895e949f8849bc2757c0dbac28422a04be031204df46a56ab34bcf98507342", + "sha256:e1a79ad49f346aa1a2921f31e8dbbab4d64484823e813a002679eaa46cba39e1", + "sha256:e460475719721d59cd54a350c1f71c797c763212c836bf48585478c5514d2854", + "sha256:e64ffaf8f6e17ca15eb48344d86a7a741454526f3a3fa56bc493ad9d7ec63936", + "sha256:e6e3ccebdbd6e53474b0bb7ab8b88e83c0cfe91484b25e058e581348ee5a01a5", + "sha256:e758d271ed0286d146cf7c04c539a5169a888dd0b57026be621547e756af55bc", + "sha256:f087879f1ffde024dd2788a30d55acd67959dcf6c431e9d3682d1c491a0eb474", + "sha256:f477d26183e94eaafc60b983ab25af2a809a1b48ce4debb57b343f671b7a90b6", + "sha256:fc535cb898ef88333cf317777ecdfe0faac1c2a3187ef7eb061b6f7ecf7e6bae" + ], + "markers": "python_version >= '3.8'", + "version": "==2.23.2" }, "pydocstyle": { "hashes": [ @@ -958,49 +1174,11 @@ }, "pyparsing": { "hashes": [ - "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb", - "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db" + "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c", + "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032" ], "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.1" - }, - "pyrsistent": { - "hashes": [ - "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", - "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", - "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", - "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", - "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca", - "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", - "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", - "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", - "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714", - "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf", - "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", - "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", - "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", - "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d", - "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054", - "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", - "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", - "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423", - "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", - "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", - "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", - "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0", - "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", - "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", - "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce", - "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", - "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", - "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86", - "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f", - "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", - "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98", - "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022" - ], - "markers": "python_version >= '3.8'", - "version": "==0.20.0" + "version": "==3.1.4" }, "pytest": { "hashes": [ @@ -1013,12 +1191,12 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:37a9d912e8338ee7b4a3e917381d1c95bfc8682048cb0fbc35baba316ec1faba", - "sha256:af313ce900a62fbe2b1aed18e37ad757f1ef9940c6b6a88e2954de38d6b1fb9f" + "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", + "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.23.3" + "version": "==0.23.8" }, "pytest-cov": { "hashes": [ @@ -1039,19 +1217,128 @@ }, "python-dateutil": { "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" + "version": "==2.9.0.post0" }, - "setuptools": { + "referencing": { "hashes": [ - "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05", - "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78" + "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", + "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" ], "markers": "python_version >= '3.8'", - "version": "==69.0.3" + "version": "==0.35.1" + }, + "rpds-py": { + "hashes": [ + "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c", + "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585", + "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5", + "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6", + "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef", + "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2", + "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29", + "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318", + "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b", + "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399", + "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739", + "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee", + "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174", + "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a", + "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344", + "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2", + "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03", + "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5", + "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22", + "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e", + "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96", + "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91", + "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752", + "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075", + "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253", + "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee", + "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad", + "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5", + "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce", + "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7", + "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b", + "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8", + "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57", + "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3", + "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec", + "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209", + "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921", + "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045", + "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074", + "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580", + "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7", + "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5", + "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3", + "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0", + "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24", + "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139", + "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db", + "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc", + "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789", + "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f", + "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2", + "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c", + "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232", + "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6", + "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c", + "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29", + "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489", + "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94", + "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751", + "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2", + "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda", + "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9", + "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51", + "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c", + "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8", + "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989", + "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511", + "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1", + "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2", + "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150", + "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c", + "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965", + "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f", + "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58", + "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b", + "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f", + "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d", + "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821", + "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de", + "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121", + "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855", + "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272", + "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60", + "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02", + "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1", + "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140", + "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879", + "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940", + "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364", + "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4", + "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e", + "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420", + "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5", + "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24", + "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c", + "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf", + "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f", + "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e", + "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab", + "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08", + "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92", + "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a", + "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8" + ], + "markers": "python_version >= '3.8'", + "version": "==0.20.0" }, "six": { "hashes": [ @@ -1085,21 +1372,29 @@ }, "types-mock": { "hashes": [ - "sha256:13ca379d5710ccb3f18f69ade5b08881874cb83383d8fb49b1d4dac9d5c5d090", - "sha256:3d116955495935b0bcba14954b38d97e507cd43eca3e3700fc1b8e4f5c6bf2c7" + "sha256:5281a645d72e827d70043e3cc144fe33b1c003db084f789dc203aa90e812a5a4", + "sha256:d586a01d39ad919d3ddcd73de6cde73ca7f3c69707219f722d1b8d7733641ad7" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==5.1.0.20240106" + "version": "==5.1.0.20240425" }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.12.2" + }, + "tzdata": { + "hashes": [ + "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", + "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.1" } } } diff --git a/hardware/mypy.ini b/hardware/mypy.ini index 0fd2feea554..e92fb180b4f 100644 --- a/hardware/mypy.ini +++ b/hardware/mypy.ini @@ -2,6 +2,3 @@ show_error_codes = True warn_unused_configs = True strict = True - -[mypy-can.*] -ignore_missing_imports = True diff --git a/hardware/opentrons_hardware/drivers/can_bus/settings.py b/hardware/opentrons_hardware/drivers/can_bus/settings.py index c36bd791fb9..21ab27cda2d 100644 --- a/hardware/opentrons_hardware/drivers/can_bus/settings.py +++ b/hardware/opentrons_hardware/drivers/can_bus/settings.py @@ -1,11 +1,12 @@ """Driver settings.""" from typing_extensions import Final, TypedDict from typing import Optional -from pydantic import BaseSettings, Field +from pydantic import Field from opentrons_shared_data.errors.exceptions import CANBusConfigurationError from math import floor +from pydantic_settings import BaseSettings, SettingsConfigDict DEFAULT_INTERFACE: Final = "socketcan" @@ -50,24 +51,22 @@ class DriverSettings(BaseSettings): """Settings for driver building.""" interface: str = Field( - DEFAULT_INTERFACE, + default=DEFAULT_INTERFACE, description=f"Can either be {OPENTRONS_INTERFACE} for simple socket " f"or a python can interface.", ) bit_rate: int = Field( - DEFAULT_BITRATE, + default=DEFAULT_BITRATE, description=f"Bit rate. Not applicable to {OPENTRONS_INTERFACE} interface.", ) - channel: str = Field(DEFAULT_CHANNEL, description="The SocketCan channel.") - - host: str = Field(DEFAULT_HOST, description=f"{OPENTRONS_INTERFACE} only.") - port: int = Field(DEFAULT_PORT, description=f"{OPENTRONS_INTERFACE} only.") - fcan_clock: int = Field(DEFAULT_FDCAN_CLK, description="pcan only.") - sample_rate: float = Field(DEFAULT_SAMPLE_RATE, description="pcan only.") - jump_width: int = Field(DEFAULT_JUMP_WIDTH_SEG, descript="pcan only.") - - class Config: # noqa: D106 - env_prefix = "OT3_CAN_DRIVER_" + channel: str = Field(default=DEFAULT_CHANNEL, description="The SocketCan channel.") + + host: str = Field(default=DEFAULT_HOST, description=f"{OPENTRONS_INTERFACE} only.") + port: int = Field(default=DEFAULT_PORT, description=f"{OPENTRONS_INTERFACE} only.") + fcan_clock: int = Field(default=DEFAULT_FDCAN_CLK, description="pcan only.") + sample_rate: float = Field(default=DEFAULT_SAMPLE_RATE, description="pcan only.") + jump_width: int = Field(default=DEFAULT_JUMP_WIDTH_SEG, description="pcan only.") + model_config = SettingsConfigDict(env_prefix="OT3_CAN_DRIVER_") def _check_calculated_bit_timing_values( diff --git a/hardware/setup.py b/hardware/setup.py index b463a3fbd20..8d0f621e67c 100644 --- a/hardware/setup.py +++ b/hardware/setup.py @@ -48,6 +48,8 @@ def get_version() -> str: PACKAGES = find_packages(where=".", exclude=["tests.*", "tests"]) INSTALL_REQUIRES = [ "pyserial==3.5", + "pydantic>=2,<3", + "pydantic-settings>=2,<3", f"opentrons_shared_data=={VERSION}", ] diff --git a/performance-metrics/Pipfile b/performance-metrics/Pipfile index b57cd339814..79a023f1dcf 100644 --- a/performance-metrics/Pipfile +++ b/performance-metrics/Pipfile @@ -6,7 +6,7 @@ name = "pypi" [packages] performance-metrics = {file = ".", editable = true} psutil = "==6.0.0" -systemd-python = "234" +systemd-python = {version="==234", markers="sys_platform=='linux'" } [dev-packages] pytest = "==7.4.4" diff --git a/performance-metrics/Pipfile.lock b/performance-metrics/Pipfile.lock index 9bb77d23330..3a70b502d5a 100644 --- a/performance-metrics/Pipfile.lock +++ b/performance-metrics/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a123325c3bebd1451774ebfadc532a4ca78a92897b80cf1d20ded030e145bac2" + "sha256": "259baa6d557d8069c945cca566e64d0135576284244f14461c67e044366535b5" }, "pipfile-spec": 6, "requires": { @@ -48,18 +48,18 @@ "hashes": [ "sha256:fd0e44bf70eadae45aadc292cb0a7eb5b0b6372cd1b391228047d33895db83e7" ], - "index": "pypi", + "markers": "sys_platform == 'linux'", "version": "==234" } }, "develop": { "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "black": { "hashes": [ @@ -101,11 +101,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", - "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.1" + "version": "==1.2.2" }, "flake8": { "hashes": [ @@ -203,11 +203,11 @@ }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "pathspec": { "hashes": [ @@ -219,11 +219,11 @@ }, "platformdirs": { "hashes": [ - "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", - "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" ], "markers": "python_version >= '3.8'", - "version": "==4.2.2" + "version": "==4.3.6" }, "pluggy": { "hashes": [ @@ -268,12 +268,12 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b", - "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268" + "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", + "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.23.7" + "version": "==0.23.8" }, "snowballstemmer": { "hashes": [ @@ -284,11 +284,41 @@ }, "tomli": { "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", + "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", + "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", + "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", + "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", + "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", + "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", + "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", + "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", + "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", + "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", + "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", + "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", + "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", + "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", + "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", + "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", + "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", + "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", + "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", + "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", + "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" ], "markers": "python_version < '3.11'", - "version": "==2.0.1" + "version": "==2.2.1" }, "types-psutil": { "hashes": [ diff --git a/performance-metrics/src/performance_metrics/system_resource_tracker/__main__.py b/performance-metrics/src/performance_metrics/system_resource_tracker/__main__.py index e810175bfb0..37c15337eba 100644 --- a/performance-metrics/src/performance_metrics/system_resource_tracker/__main__.py +++ b/performance-metrics/src/performance_metrics/system_resource_tracker/__main__.py @@ -2,7 +2,7 @@ import logging import time -import systemd.daemon # type: ignore [import-untyped] +import systemd.daemon # type: ignore [import-untyped,import-not-found,unused-ignore] from .._logging_config import log_init, LOGGER_NAME from ._config import SystemResourceTrackerConfiguration from ._system_resource_tracker import SystemResourceTracker diff --git a/robot-server/Config.in b/robot-server/Config.in index 359b031d79c..3d6c5ee8c82 100644 --- a/robot-server/Config.in +++ b/robot-server/Config.in @@ -14,6 +14,7 @@ config BR2_PACKAGE_PYTHON_OPENTRONS_ROBOT_SERVER select BR2_PACKAGE_PYTHON_UVICORN # runtime select BR2_PACKAGE_PYTHON_WSPROTO # runtime select BR2_PACKAGE_PYTHON_PAHO_MQTT # runtime + select BR2_PACKAGE_PYTHON_PYDANTIC_SETTINGS # runtime help Opentrons HTTP server. Controls an OT-2 robot. diff --git a/robot-server/Pipfile b/robot-server/Pipfile index c66f132ecd4..541cd8bca90 100755 --- a/robot-server/Pipfile +++ b/robot-server/Pipfile @@ -22,7 +22,7 @@ pytest-xdist = "~=2.5.0" requests = "==2.27.1" graphviz = "==0.19" mock = "~=5.0.1" -mypy = "==1.8.0" +mypy = "==1.11.0" flake8 = "==7.0.0" flake8-annotations = "~=3.0.1" flake8-docstrings = "~=1.7.0" @@ -37,18 +37,14 @@ sqlalchemy2-stubs = "==0.0.2a21" python-box = "==6.1.0" types-paho-mqtt = "==1.6.0.20240106" pyusb = "==1.2.1" -performance-metrics = {file = "../performance-metrics", editable = true} [packages] anyio = "==3.7.1" aiohttp = "==3.8.1" -# fastapi >=0.100.0 is intended for use with pydantic 2.x, and while it theoretically is -# backwards compatible, best to be sure -fastapi = "==0.99.1" +fastapi = "==0.100.0" python-dotenv = "==1.0.1" python-multipart = "==0.0.6" -# pydantic 2.x has many breaking api changes -pydantic = "==1.10.12" +pydantic = "==2.9.0" typing-extensions = ">=4.0.0,<5" uvicorn = "==0.27.0.post1" wsproto = "==1.2.0" @@ -63,4 +59,10 @@ opentrons-hardware = {editable = true, path='../hardware', extras=['FLEX']} opentrons = { editable = true, path = "../api"} opentrons-shared-data = { editable = true, path = "../shared-data/python" } server-utils = {editable = true, path = "./../server-utils"} +performance-metrics = {editable = true, path = "../performance-metrics" } robot-server = { editable = true, path = "."} +pydantic-settings = "==2.4.0" +# this is a dependency of jsonschema (which requires just >0.7.0). +# versions above 0.18.1 require a version of triomphe that requires a version of +# rust too new for openembedded +rpds-py = "==0.18.1" diff --git a/robot-server/Pipfile.lock b/robot-server/Pipfile.lock index 0f33283b0ee..df7ec2c7a92 100644 --- a/robot-server/Pipfile.lock +++ b/robot-server/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f43123500e774f5b9a92f2be8ae39a04af8df7ba2ae4b2a505f1bb4b751cc30a" + "sha256": "d1bb17b5871fccc0c2b2aebc24507d29016a8078c3a3894271fb4c2a920fb37a" }, "pipfile-spec": 6, "requires": { @@ -100,15 +100,24 @@ "sha256:25816a9eef030c774beaee22189a24e29bc43f81cebe574ef723851eaf89ddee", "sha256:9651e1373873c75786101330e302e114f85b6e8b5ad70b491497c8b3609a8449" ], + "markers": "python_version >= '3.8'", "version": "==0.3.1" }, "aiosignal": { "hashes": [ - "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", - "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17" + "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", + "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54" ], - "markers": "python_version >= '3.7'", - "version": "==1.3.1" + "markers": "python_version >= '3.9'", + "version": "==1.3.2" + }, + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" }, "anyio": { "hashes": [ @@ -129,11 +138,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", + "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" ], - "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "markers": "python_version >= '3.8'", + "version": "==24.3.0" }, "charset-normalizer": { "hashes": [ @@ -154,167 +163,197 @@ }, "exceptiongroup": { "hashes": [ - "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", - "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.1" + "version": "==1.2.2" }, "fastapi": { "hashes": [ - "sha256:976df7bab51ac7beda9f68c4513b8c4490b5c1135c72aafd0a5ee4023ec5282e", - "sha256:ac78f717cd80d657bd183f94d33b9bda84aa376a46a9dab513586b8eef1dc6fc" + "sha256:271662daf986da8fa98dc2b7c7f61c4abdfdccfb4786d79ed8b2878f172c6d5f", + "sha256:acb5f941ea8215663283c10018323ba7ea737c571b67fc7e88e9469c7eb1d12e" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.99.1" + "version": "==0.100.0" }, "frozenlist": { "hashes": [ - "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", - "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98", - "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad", - "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5", - "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae", - "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e", - "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a", - "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701", - "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d", - "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6", - "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6", - "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106", - "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75", - "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868", - "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a", - "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0", - "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1", - "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826", - "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec", - "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6", - "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950", - "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19", - "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0", - "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8", - "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a", - "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09", - "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86", - "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c", - "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5", - "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b", - "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b", - "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d", - "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0", - "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea", - "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776", - "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a", - "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897", - "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7", - "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09", - "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9", - "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe", - "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd", - "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742", - "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09", - "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0", - "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932", - "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1", - "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a", - "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49", - "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d", - "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7", - "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480", - "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89", - "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e", - "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b", - "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82", - "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb", - "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068", - "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8", - "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b", - "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb", - "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2", - "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11", - "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b", - "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc", - "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0", - "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497", - "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17", - "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0", - "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2", - "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439", - "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5", - "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac", - "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825", - "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887", - "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced", - "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74" + "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", + "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf", + "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6", + "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a", + "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d", + "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f", + "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", + "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", + "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", + "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", + "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec", + "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2", + "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c", + "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336", + "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4", + "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d", + "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b", + "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c", + "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10", + "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08", + "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942", + "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", + "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f", + "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10", + "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5", + "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", + "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", + "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", + "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d", + "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923", + "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", + "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", + "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17", + "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0", + "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", + "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", + "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c", + "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a", + "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0", + "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", + "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab", + "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", + "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3", + "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", + "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", + "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604", + "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", + "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5", + "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", + "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", + "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", + "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", + "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d", + "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", + "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3", + "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", + "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", + "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9", + "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf", + "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76", + "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba", + "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171", + "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb", + "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", + "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", + "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972", + "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d", + "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869", + "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9", + "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411", + "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723", + "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2", + "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b", + "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99", + "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e", + "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", + "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3", + "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb", + "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", + "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", + "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca", + "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45", + "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", + "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f", + "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5", + "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307", + "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e", + "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2", + "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778", + "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a", + "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30", + "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a" ], "markers": "python_version >= '3.8'", - "version": "==1.4.1" + "version": "==1.5.0" }, "greenlet": { "hashes": [ - "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67", - "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6", - "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257", - "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4", - "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676", - "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61", - "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc", - "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca", - "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7", - "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728", - "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305", - "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6", - "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379", - "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414", - "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04", - "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a", - "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf", - "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491", - "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559", - "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e", - "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274", - "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb", - "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b", - "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9", - "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b", - "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be", - "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506", - "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405", - "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113", - "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f", - "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5", - "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230", - "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d", - "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f", - "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a", - "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e", - "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61", - "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6", - "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d", - "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71", - "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22", - "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2", - "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3", - "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067", - "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc", - "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881", - "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3", - "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e", - "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac", - "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53", - "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0", - "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b", - "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83", - "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41", - "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c", - "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf", - "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da", - "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33" + "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e", + "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7", + "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01", + "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1", + "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159", + "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563", + "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83", + "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9", + "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395", + "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa", + "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942", + "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1", + "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441", + "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22", + "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9", + "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0", + "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba", + "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3", + "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1", + "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", + "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291", + "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39", + "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d", + "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467", + "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475", + "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef", + "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c", + "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511", + "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c", + "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822", + "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a", + "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8", + "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d", + "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01", + "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145", + "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80", + "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13", + "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e", + "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b", + "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1", + "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef", + "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc", + "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff", + "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120", + "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437", + "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd", + "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981", + "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36", + "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a", + "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798", + "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7", + "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761", + "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0", + "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e", + "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af", + "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa", + "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c", + "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42", + "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e", + "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81", + "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e", + "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617", + "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc", + "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de", + "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111", + "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383", + "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70", + "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6", + "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4", + "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011", + "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803", + "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79", + "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f" ], "markers": "python_version >= '3' and platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))", - "version": "==3.0.3" + "version": "==3.1.1" }, "h11": { "hashes": [ @@ -405,99 +444,101 @@ }, "multidict": { "hashes": [ - "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556", - "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c", - "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29", - "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b", - "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8", - "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7", - "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd", - "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40", - "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6", - "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3", - "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c", - "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9", - "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5", - "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae", - "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442", - "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9", - "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc", - "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c", - "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea", - "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5", - "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50", - "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182", - "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453", - "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e", - "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600", - "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733", - "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda", - "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241", - "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461", - "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e", - "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e", - "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b", - "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e", - "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7", - "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386", - "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd", - "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9", - "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf", - "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee", - "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5", - "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a", - "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271", - "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54", - "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4", - "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496", - "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb", - "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319", - "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3", - "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f", - "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527", - "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed", - "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604", - "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef", - "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8", - "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5", - "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5", - "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626", - "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c", - "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d", - "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c", - "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc", - "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc", - "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b", - "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38", - "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450", - "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1", - "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f", - "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3", - "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755", - "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226", - "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a", - "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046", - "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf", - "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479", - "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e", - "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1", - "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a", - "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83", - "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929", - "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93", - "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a", - "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c", - "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44", - "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89", - "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba", - "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e", - "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da", - "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24", - "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423", - "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef" + "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", + "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", + "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", + "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", + "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", + "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", + "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", + "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", + "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", + "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", + "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", + "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", + "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", + "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", + "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", + "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", + "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", + "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", + "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", + "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", + "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", + "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", + "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", + "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", + "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", + "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", + "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", + "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", + "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", + "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", + "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", + "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", + "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", + "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", + "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", + "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", + "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", + "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", + "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", + "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", + "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", + "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", + "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", + "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", + "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", + "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", + "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", + "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", + "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", + "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", + "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", + "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", + "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", + "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", + "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", + "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", + "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", + "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", + "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", + "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", + "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", + "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", + "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", + "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", + "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", + "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", + "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", + "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", + "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", + "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", + "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", + "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", + "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", + "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", + "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", + "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", + "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", + "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", + "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", + "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", + "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", + "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", + "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", + "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", + "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", + "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", + "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", + "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", + "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", + "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", + "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", + "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" ], - "markers": "python_version >= '3.7'", - "version": "==6.0.5" + "markers": "python_version >= '3.8'", + "version": "==6.1.0" }, "numpy": { "hashes": [ @@ -545,11 +586,11 @@ }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "paho-mqtt": { "hashes": [ @@ -557,48 +598,210 @@ ], "version": "==1.6.1" }, + "performance-metrics": { + "editable": true, + "path": "../performance-metrics" + }, + "propcache": { + "hashes": [ + "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4", + "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", + "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", + "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f", + "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9", + "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", + "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e", + "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", + "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf", + "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034", + "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", + "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16", + "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30", + "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba", + "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95", + "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d", + "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae", + "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", + "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2", + "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", + "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce", + "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54", + "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629", + "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", + "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1", + "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b", + "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf", + "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b", + "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587", + "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097", + "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea", + "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", + "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7", + "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541", + "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6", + "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634", + "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3", + "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d", + "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034", + "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465", + "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2", + "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf", + "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1", + "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04", + "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", + "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583", + "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb", + "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b", + "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c", + "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958", + "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc", + "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4", + "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82", + "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e", + "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce", + "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9", + "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", + "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536", + "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505", + "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052", + "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", + "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", + "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f", + "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681", + "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347", + "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af", + "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", + "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787", + "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", + "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", + "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439", + "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3", + "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6", + "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca", + "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", + "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d", + "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3", + "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16", + "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717", + "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", + "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd", + "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212" + ], + "markers": "python_version >= '3.9'", + "version": "==0.2.1" + }, "pydantic": { "hashes": [ - "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303", - "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe", - "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47", - "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494", - "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33", - "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86", - "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d", - "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c", - "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a", - "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565", - "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb", - "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62", - "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62", - "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0", - "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523", - "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d", - "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405", - "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f", - "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b", - "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718", - "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed", - "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb", - "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5", - "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc", - "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942", - "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe", - "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246", - "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350", - "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303", - "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09", - "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33", - "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8", - "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a", - "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1", - "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6", - "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d" + "sha256:c7a8a9fdf7d100afa49647eae340e2d23efa382466a8d177efcd1381e9be5598", + "sha256:f66a7073abd93214a20c5f7b32d56843137a7a2e70d02111f3be287035c45370" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.10.12" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" + }, + "pydantic-core": { + "hashes": [ + "sha256:0102e49ac7d2df3379ef8d658d3bc59d3d769b0bdb17da189b75efa861fc07b4", + "sha256:0123655fedacf035ab10c23450163c2f65a4174f2bb034b188240a6cf06bb123", + "sha256:043ef8469f72609c4c3a5e06a07a1f713d53df4d53112c6d49207c0bd3c3bd9b", + "sha256:0448b81c3dfcde439551bb04a9f41d7627f676b12701865c8a2574bcea034437", + "sha256:05b366fb8fe3d8683b11ac35fa08947d7b92be78ec64e3277d03bd7f9b7cda79", + "sha256:07049ec9306ec64e955b2e7c40c8d77dd78ea89adb97a2013d0b6e055c5ee4c5", + "sha256:084414ffe9a85a52940b49631321d636dadf3576c30259607b75516d131fecd0", + "sha256:086c5db95157dc84c63ff9d96ebb8856f47ce113c86b61065a066f8efbe80acf", + "sha256:12625e69b1199e94b0ae1c9a95d000484ce9f0182f9965a26572f054b1537e44", + "sha256:16b25a4a120a2bb7dab51b81e3d9f3cde4f9a4456566c403ed29ac81bf49744f", + "sha256:19f1352fe4b248cae22a89268720fc74e83f008057a652894f08fa931e77dced", + "sha256:1a2ab4f410f4b886de53b6bddf5dd6f337915a29dd9f22f20f3099659536b2f6", + "sha256:1c7b81beaf7c7ebde978377dc53679c6cba0e946426fc7ade54251dfe24a7604", + "sha256:1cf842265a3a820ebc6388b963ead065f5ce8f2068ac4e1c713ef77a67b71f7c", + "sha256:1eb37f7d6a8001c0f86dc8ff2ee8d08291a536d76e49e78cda8587bb54d8b329", + "sha256:23af245b8f2f4ee9e2c99cb3f93d0e22fb5c16df3f2f643f5a8da5caff12a653", + "sha256:257d6a410a0d8aeb50b4283dea39bb79b14303e0fab0f2b9d617701331ed1515", + "sha256:276ae78153a94b664e700ac362587c73b84399bd1145e135287513442e7dfbc7", + "sha256:2b1a195efd347ede8bcf723e932300292eb13a9d2a3c1f84eb8f37cbbc905b7f", + "sha256:329a721253c7e4cbd7aad4a377745fbcc0607f9d72a3cc2102dd40519be75ed2", + "sha256:358331e21a897151e54d58e08d0219acf98ebb14c567267a87e971f3d2a3be59", + "sha256:3649bd3ae6a8ebea7dc381afb7f3c6db237fc7cebd05c8ac36ca8a4187b03b30", + "sha256:3713dc093d5048bfaedbba7a8dbc53e74c44a140d45ede020dc347dda18daf3f", + "sha256:3ef71ec876fcc4d3bbf2ae81961959e8d62f8d74a83d116668409c224012e3af", + "sha256:41ae8537ad371ec018e3c5da0eb3f3e40ee1011eb9be1da7f965357c4623c501", + "sha256:4a801c5e1e13272e0909c520708122496647d1279d252c9e6e07dac216accc41", + "sha256:4c83c64d05ffbbe12d4e8498ab72bdb05bcc1026340a4a597dc647a13c1605ec", + "sha256:4cebb9794f67266d65e7e4cbe5dcf063e29fc7b81c79dc9475bd476d9534150e", + "sha256:5668b3173bb0b2e65020b60d83f5910a7224027232c9f5dc05a71a1deac9f960", + "sha256:56e6a12ec8d7679f41b3750ffa426d22b44ef97be226a9bab00a03365f217b2b", + "sha256:582871902e1902b3c8e9b2c347f32a792a07094110c1bca6c2ea89b90150caac", + "sha256:5c8aa40f6ca803f95b1c1c5aeaee6237b9e879e4dfb46ad713229a63651a95fb", + "sha256:5d813fd871b3d5c3005157622ee102e8908ad6011ec915a18bd8fde673c4360e", + "sha256:5dd0ec5f514ed40e49bf961d49cf1bc2c72e9b50f29a163b2cc9030c6742aa73", + "sha256:5f3cf3721eaf8741cffaf092487f1ca80831202ce91672776b02b875580e174a", + "sha256:6294907eaaccf71c076abdd1c7954e272efa39bb043161b4b8aa1cd76a16ce43", + "sha256:64d094ea1aa97c6ded4748d40886076a931a8bf6f61b6e43e4a1041769c39dd2", + "sha256:6650a7bbe17a2717167e3e23c186849bae5cef35d38949549f1c116031b2b3aa", + "sha256:67b6655311b00581914aba481729971b88bb8bc7996206590700a3ac85e457b8", + "sha256:6b06c5d4e8701ac2ba99a2ef835e4e1b187d41095a9c619c5b185c9068ed2a49", + "sha256:6ce883906810b4c3bd90e0ada1f9e808d9ecf1c5f0b60c6b8831d6100bcc7dd6", + "sha256:6db09153d8438425e98cdc9a289c5fade04a5d2128faff8f227c459da21b9703", + "sha256:6f80fba4af0cb1d2344869d56430e304a51396b70d46b91a55ed4959993c0589", + "sha256:743e5811b0c377eb830150d675b0847a74a44d4ad5ab8845923d5b3a756d8100", + "sha256:753294d42fb072aa1775bfe1a2ba1012427376718fa4c72de52005a3d2a22178", + "sha256:7568f682c06f10f30ef643a1e8eec4afeecdafde5c4af1b574c6df079e96f96c", + "sha256:7706e15cdbf42f8fab1e6425247dfa98f4a6f8c63746c995d6a2017f78e619ae", + "sha256:785e7f517ebb9890813d31cb5d328fa5eda825bb205065cde760b3150e4de1f7", + "sha256:7a05c0240f6c711eb381ac392de987ee974fa9336071fb697768dfdb151345ce", + "sha256:7ce7eaf9a98680b4312b7cebcdd9352531c43db00fca586115845df388f3c465", + "sha256:7ce8e26b86a91e305858e018afc7a6e932f17428b1eaa60154bd1f7ee888b5f8", + "sha256:7d0324a35ab436c9d768753cbc3c47a865a2cbc0757066cb864747baa61f6ece", + "sha256:7e9b24cca4037a561422bf5dc52b38d390fb61f7bfff64053ce1b72f6938e6b2", + "sha256:810ca06cca91de9107718dc83d9ac4d2e86efd6c02cba49a190abcaf33fb0472", + "sha256:820f6ee5c06bc868335e3b6e42d7ef41f50dfb3ea32fbd523ab679d10d8741c0", + "sha256:82764c0bd697159fe9947ad59b6db6d7329e88505c8f98990eb07e84cc0a5d81", + "sha256:8ae65fdfb8a841556b52935dfd4c3f79132dc5253b12c0061b96415208f4d622", + "sha256:8d5b0ff3218858859910295df6953d7bafac3a48d5cd18f4e3ed9999efd2245f", + "sha256:95d6bf449a1ac81de562d65d180af5d8c19672793c81877a2eda8fde5d08f2fd", + "sha256:964c7aa318da542cdcc60d4a648377ffe1a2ef0eb1e996026c7f74507b720a78", + "sha256:96ef39add33ff58cd4c112cbac076726b96b98bb8f1e7f7595288dcfb2f10b57", + "sha256:a6612c2a844043e4d10a8324c54cdff0042c558eef30bd705770793d70b224aa", + "sha256:a8031074a397a5925d06b590121f8339d34a5a74cfe6970f8a1124eb8b83f4ac", + "sha256:aab9e522efff3993a9e98ab14263d4e20211e62da088298089a03056980a3e69", + "sha256:ae579143826c6f05a361d9546446c432a165ecf1c0b720bbfd81152645cb897d", + "sha256:ae90b9e50fe1bd115b24785e962b51130340408156d34d67b5f8f3fa6540938e", + "sha256:b18cf68255a476b927910c6873d9ed00da692bb293c5b10b282bd48a0afe3ae2", + "sha256:b7efb12e5071ad8d5b547487bdad489fbd4a5a35a0fc36a1941517a6ad7f23e0", + "sha256:c4d9f15ffe68bcd3898b0ad7233af01b15c57d91cd1667f8d868e0eacbfe3f87", + "sha256:c53100c8ee5a1e102766abde2158077d8c374bee0639201f11d3032e3555dfbc", + "sha256:c57e493a0faea1e4c38f860d6862ba6832723396c884fbf938ff5e9b224200e2", + "sha256:c8319e0bd6a7b45ad76166cc3d5d6a36c97d0c82a196f478c3ee5346566eebfd", + "sha256:caffda619099cfd4f63d48462f6aadbecee3ad9603b4b88b60cb821c1b258576", + "sha256:cc0c316fba3ce72ac3ab7902a888b9dc4979162d320823679da270c2d9ad0cad", + "sha256:cdd02a08205dc90238669f082747612cb3c82bd2c717adc60f9b9ecadb540f80", + "sha256:d50ac34835c6a4a0d456b5db559b82047403c4317b3bc73b3455fefdbdc54b0a", + "sha256:d6b9dd6aa03c812017411734e496c44fef29b43dba1e3dd1fa7361bbacfc1354", + "sha256:da3131ef2b940b99106f29dfbc30d9505643f766704e14c5d5e504e6a480c35e", + "sha256:da43cbe593e3c87d07108d0ebd73771dc414488f1f91ed2e204b0370b94b37ac", + "sha256:dd59638025160056687d598b054b64a79183f8065eae0d3f5ca523cde9943940", + "sha256:e1895e949f8849bc2757c0dbac28422a04be031204df46a56ab34bcf98507342", + "sha256:e1a79ad49f346aa1a2921f31e8dbbab4d64484823e813a002679eaa46cba39e1", + "sha256:e460475719721d59cd54a350c1f71c797c763212c836bf48585478c5514d2854", + "sha256:e64ffaf8f6e17ca15eb48344d86a7a741454526f3a3fa56bc493ad9d7ec63936", + "sha256:e6e3ccebdbd6e53474b0bb7ab8b88e83c0cfe91484b25e058e581348ee5a01a5", + "sha256:e758d271ed0286d146cf7c04c539a5169a888dd0b57026be621547e756af55bc", + "sha256:f087879f1ffde024dd2788a30d55acd67959dcf6c431e9d3682d1c491a0eb474", + "sha256:f477d26183e94eaafc60b983ab25af2a809a1b48ce4debb57b343f671b7a90b6", + "sha256:fc535cb898ef88333cf317777ecdfe0faac1c2a3187ef7eb061b6f7ecf7e6bae" + ], + "markers": "python_version >= '3.8'", + "version": "==2.23.2" + }, + "pydantic-settings": { + "hashes": [ + "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315", + "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.4.0" }, "pyrsistent": { "hashes": [ @@ -671,21 +874,135 @@ "markers": "python_version >= '3.7'", "version": "==0.0.6" }, + "pyusb": { + "hashes": [ + "sha256:2b4c7cb86dbadf044dfb9d3a4ff69fd217013dbe78a792177a3feb172449ea36", + "sha256:a4cc7404a203144754164b8b40994e2849fde1cfff06b08492f12fff9d9de7b9" + ], + "markers": "python_full_version >= '3.6.0'", + "version": "==1.2.1" + }, "robot-server": { "editable": true, "path": "." }, + "rpds-py": { + "hashes": [ + "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee", + "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc", + "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc", + "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944", + "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20", + "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7", + "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4", + "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6", + "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6", + "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93", + "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633", + "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0", + "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360", + "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8", + "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139", + "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7", + "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a", + "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9", + "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26", + "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724", + "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72", + "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b", + "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09", + "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100", + "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3", + "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261", + "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3", + "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9", + "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b", + "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3", + "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de", + "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d", + "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e", + "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8", + "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff", + "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5", + "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c", + "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e", + "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e", + "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4", + "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8", + "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922", + "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338", + "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d", + "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8", + "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2", + "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72", + "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80", + "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644", + "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae", + "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163", + "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104", + "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d", + "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60", + "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a", + "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d", + "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07", + "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49", + "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10", + "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f", + "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2", + "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8", + "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7", + "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88", + "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65", + "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0", + "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909", + "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8", + "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c", + "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184", + "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397", + "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a", + "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346", + "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590", + "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333", + "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb", + "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74", + "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e", + "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d", + "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa", + "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f", + "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53", + "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1", + "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac", + "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0", + "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd", + "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611", + "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f", + "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c", + "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5", + "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab", + "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc", + "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43", + "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da", + "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac", + "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843", + "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e", + "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89", + "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.18.1" + }, "server-utils": { "editable": true, "path": "./../server-utils" }, "setuptools": { "hashes": [ - "sha256:937a48c7cdb7a21eb53cd7f9b59e525503aa8abaf3584c730dc5f7a5bec3a650", - "sha256:a58a8fde0541dab0419750bcc521fbdf8585f6e5cb41909df3a472ef7b81ca95" + "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", + "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d" ], - "markers": "python_version >= '3.8'", - "version": "==70.1.1" + "markers": "python_version >= '3.9'", + "version": "==75.6.0" }, "sniffio": { "hashes": [ @@ -772,6 +1089,14 @@ "markers": "python_version >= '3.8'", "version": "==4.12.2" }, + "tzdata": { + "hashes": [ + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.2" + }, "uvicorn": { "hashes": [ "sha256:4b85ba02b8a20429b9b205d015cbeb788a12da527f731811b643fd739ef90d5f", @@ -783,79 +1108,74 @@ }, "wrapt": { "hashes": [ - "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc", - "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81", - "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09", - "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e", - "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca", - "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0", - "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb", - "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487", - "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40", - "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c", - "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060", - "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202", - "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41", - "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9", - "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b", - "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664", - "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d", - "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362", - "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00", - "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc", - "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1", - "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267", - "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956", - "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966", - "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1", - "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228", - "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72", - "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d", - "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292", - "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0", - "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0", - "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36", - "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c", - "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5", - "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f", - "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73", - "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b", - "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2", - "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593", - "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39", - "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389", - "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf", - "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf", - "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89", - "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c", - "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c", - "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f", - "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440", - "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465", - "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136", - "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b", - "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8", - "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3", - "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8", - "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6", - "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e", - "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f", - "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c", - "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e", - "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8", - "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2", - "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020", - "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35", - "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d", - "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3", - "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537", - "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809", - "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d", - "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a", - "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4" + "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d", + "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301", + "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635", + "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a", + "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed", + "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721", + "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801", + "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b", + "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1", + "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88", + "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8", + "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0", + "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f", + "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578", + "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7", + "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045", + "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada", + "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d", + "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b", + "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a", + "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977", + "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea", + "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346", + "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13", + "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22", + "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339", + "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9", + "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181", + "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c", + "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90", + "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a", + "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489", + "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f", + "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504", + "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea", + "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569", + "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4", + "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce", + "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab", + "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a", + "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f", + "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c", + "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9", + "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf", + "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d", + "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627", + "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d", + "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4", + "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c", + "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d", + "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad", + "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b", + "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33", + "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371", + "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1", + "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393", + "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106", + "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df", + "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379", + "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451", + "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b", + "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575", + "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed", + "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb", + "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838" ], - "markers": "python_version >= '3.6'", - "version": "==1.16.0" + "markers": "python_version >= '3.8'", + "version": "==1.17.0" }, "wsproto": { "hashes": [ @@ -868,99 +1188,91 @@ }, "yarl": { "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" - ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" + "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", + "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193", + "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318", + "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee", + "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e", + "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1", + "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a", + "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", + "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1", + "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", + "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", + "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb", + "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", + "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc", + "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5", + "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", + "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", + "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", + "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24", + "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b", + "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910", + "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", + "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", + "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed", + "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1", + "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04", + "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", + "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5", + "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d", + "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889", + "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae", + "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b", + "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c", + "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", + "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34", + "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", + "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990", + "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", + "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", + "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069", + "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", + "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6", + "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", + "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", + "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", + "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", + "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8", + "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e", + "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e", + "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985", + "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8", + "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", + "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5", + "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690", + "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", + "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789", + "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", + "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca", + "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", + "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5", + "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59", + "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9", + "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8", + "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db", + "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde", + "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7", + "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", + "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3", + "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", + "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", + "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", + "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8", + "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", + "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd", + "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", + "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760", + "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", + "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", + "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", + "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", + "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719", + "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62" + ], + "markers": "python_version >= '3.9'", + "version": "==1.18.3" }, "zipp": { "hashes": [ @@ -992,11 +1304,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", + "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" ], - "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "markers": "python_version >= '3.8'", + "version": "==24.3.0" }, "black": { "hashes": [ @@ -1030,11 +1342,11 @@ }, "certifi": { "hashes": [ - "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", - "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" + "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", + "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" ], "markers": "python_version >= '3.6'", - "version": "==2024.6.2" + "version": "==2024.12.14" }, "charset-normalizer": { "hashes": [ @@ -1066,61 +1378,71 @@ "toml" ], "hashes": [ - "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f", - "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d", - "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747", - "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f", - "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d", - "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f", - "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47", - "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e", - "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba", - "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c", - "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b", - "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4", - "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7", - "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555", - "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233", - "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace", - "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805", - "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136", - "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4", - "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d", - "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806", - "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99", - "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8", - "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b", - "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5", - "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da", - "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0", - "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078", - "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f", - "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029", - "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353", - "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638", - "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9", - "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f", - "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7", - "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3", - "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e", - "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016", - "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088", - "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4", - "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882", - "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7", - "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53", - "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d", - "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080", - "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5", - "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d", - "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c", - "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8", - "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633", - "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9", - "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c" - ], - "markers": "python_version >= '3.8'", - "version": "==7.5.4" + "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4", + "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c", + "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f", + "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b", + "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6", + "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae", + "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692", + "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4", + "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4", + "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717", + "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d", + "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198", + "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1", + "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3", + "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb", + "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d", + "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08", + "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf", + "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b", + "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710", + "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c", + "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae", + "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077", + "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00", + "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb", + "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664", + "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014", + "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9", + "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6", + "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e", + "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9", + "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa", + "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", + "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b", + "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a", + "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8", + "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030", + "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678", + "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015", + "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902", + "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97", + "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845", + "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419", + "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464", + "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be", + "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9", + "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7", + "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be", + "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1", + "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba", + "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5", + "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073", + "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4", + "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a", + "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a", + "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3", + "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599", + "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0", + "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b", + "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec", + "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1", + "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3" + ], + "markers": "python_version >= '3.9'", + "version": "==7.6.9" }, "decoy": { "hashes": [ @@ -1139,11 +1461,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", - "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.1" + "version": "==1.2.2" }, "execnet": { "hashes": [ @@ -1208,11 +1530,11 @@ }, "httpcore": { "hashes": [ - "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61", - "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5" + "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", + "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd" ], "markers": "python_version >= '3.8'", - "version": "==1.0.5" + "version": "==1.0.7" }, "httpx": { "hashes": [ @@ -1258,11 +1580,11 @@ }, "jsonschema-specifications": { "hashes": [ - "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc", - "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" + "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", + "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" ], - "markers": "python_version >= '3.8'", - "version": "==2023.12.1" + "markers": "python_version >= '3.9'", + "version": "==2024.10.1" }, "mccabe": { "hashes": [ @@ -1283,37 +1605,37 @@ }, "mypy": { "hashes": [ - "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6", - "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d", - "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02", - "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d", - "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3", - "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3", - "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", - "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66", - "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259", - "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", - "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd", - "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", - "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8", - "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", - "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b", - "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e", - "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6", - "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", - "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9", - "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", - "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a", - "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592", - "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218", - "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", - "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4", - "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410", - "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" + "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", + "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095", + "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac", + "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6", + "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", + "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", + "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00", + "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", + "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7", + "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13", + "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be", + "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", + "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850", + "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287", + "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", + "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229", + "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", + "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c", + "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac", + "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", + "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", + "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", + "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9", + "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", + "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf", + "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe", + "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.8.0" + "version": "==1.11.0" }, "mypy-extensions": { "hashes": [ @@ -1325,11 +1647,11 @@ }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "paho-mqtt": { "hashes": [ @@ -1347,23 +1669,19 @@ }, "pbr": { "hashes": [ - "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda", - "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9" + "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24", + "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a" ], "markers": "python_version >= '2.6'", - "version": "==6.0.0" - }, - "performance-metrics": { - "editable": true, - "file": "../performance-metrics" + "version": "==6.1.0" }, "platformdirs": { "hashes": [ - "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", - "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" ], "markers": "python_version >= '3.8'", - "version": "==4.2.2" + "version": "==4.3.6" }, "pluggy": { "hashes": [ @@ -1407,11 +1725,11 @@ }, "pyjwt": { "hashes": [ - "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", - "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" + "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", + "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb" ], - "markers": "python_version >= '3.7'", - "version": "==2.8.0" + "markers": "python_version >= '3.9'", + "version": "==2.10.1" }, "pykwalify": { "hashes": [ @@ -1431,12 +1749,12 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b", - "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268" + "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", + "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.23.7" + "version": "==0.23.8" }, "pytest-cov": { "hashes": [ @@ -1509,66 +1827,67 @@ "sha256:2b4c7cb86dbadf044dfb9d3a4ff69fd217013dbe78a792177a3feb172449ea36", "sha256:a4cc7404a203144754164b8b40994e2849fde1cfff06b08492f12fff9d9de7b9" ], - "index": "pypi", "markers": "python_full_version >= '3.6.0'", "version": "==1.2.1" }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "referencing": { "hashes": [ @@ -1689,6 +2008,7 @@ "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89", "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64" ], + "index": "pypi", "markers": "python_version >= '3.8'", "version": "==0.18.1" }, @@ -1702,67 +2022,63 @@ }, "ruamel.yaml.clib": { "hashes": [ - "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d", - "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001", - "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462", - "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9", - "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe", - "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b", - "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b", - "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615", - "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62", - "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15", - "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b", - "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1", - "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9", - "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675", - "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899", - "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7", - "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7", - "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312", - "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa", - "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91", - "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b", - "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6", - "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3", - "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334", - "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5", - "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3", - "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe", - "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c", - "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed", - "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337", - "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880", - "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f", - "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d", - "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248", - "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d", - "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf", - "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512", - "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069", - "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb", - "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942", - "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d", - "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31", - "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92", - "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5", - "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28", - "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d", - "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1", - "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2", - "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875", - "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412" + "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b", + "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4", + "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef", + "sha256:11f891336688faf5156a36293a9c362bdc7c88f03a8a027c2c1d8e0bcde998e5", + "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3", + "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632", + "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6", + "sha256:2c59aa6170b990d8d2719323e628aaf36f3bfbc1c26279c0eeeb24d05d2d11c7", + "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680", + "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf", + "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da", + "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6", + "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a", + "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01", + "sha256:5a0e060aace4c24dcaf71023bbd7d42674e3b230f7e7b97317baf1e953e5b519", + "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6", + "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f", + "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd", + "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2", + "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52", + "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd", + "sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d", + "sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c", + "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6", + "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb", + "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a", + "sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969", + "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28", + "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d", + "sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e", + "sha256:bc5f1e1c28e966d61d2519f2a3d451ba989f9ea0f2307de7bc45baa526de9e45", + "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4", + "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12", + "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31", + "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642", + "sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e", + "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285", + "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed", + "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1", + "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7", + "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3", + "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475", + "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5", + "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76", + "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987", + "sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df" ], "markers": "python_version < '3.13' and platform_python_implementation == 'CPython'", - "version": "==0.2.8" + "version": "==0.2.12" }, "six": { "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" + "version": "==1.17.0" }, "sniffio": { "hashes": [ @@ -1807,11 +2123,41 @@ }, "tomli": { "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", + "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", + "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", + "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", + "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", + "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", + "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", + "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", + "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", + "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", + "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", + "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", + "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", + "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", + "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", + "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", + "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", + "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", + "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", + "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", + "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", + "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" ], "markers": "python_version < '3.11'", - "version": "==2.0.1" + "version": "==2.2.1" }, "types-mock": { "hashes": [ @@ -1857,11 +2203,11 @@ }, "urllib3": { "hashes": [ - "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3", - "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429" + "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", + "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.19" + "version": "==1.26.20" } } } diff --git a/robot-server/opentrons-robot-server.service b/robot-server/opentrons-robot-server.service index dbdbdc68046..e452da339e5 100644 --- a/robot-server/opentrons-robot-server.service +++ b/robot-server/opentrons-robot-server.service @@ -27,7 +27,7 @@ Environment=RUNNING_ON_PI=true Environment=OT_ROBOT_SERVER_persistence_directory=/data/opentrons_robot_server Restart=on-failure -TimeoutStartSec=3min +TimeoutStartSec=10min [Install] diff --git a/robot-server/robot_server/errors/error_responses.py b/robot-server/robot_server/errors/error_responses.py index 410fa9d46ab..73f8a97f445 100644 --- a/robot-server/robot_server/errors/error_responses.py +++ b/robot-server/robot_server/errors/error_responses.py @@ -1,6 +1,5 @@ """JSON API errors and response models.""" from pydantic import BaseModel, Field -from pydantic.generics import GenericModel from typing import Any, Dict, Generic, Optional, Sequence, TypeVar, Type from robot_server.service.json_api import BaseResponseBody, ResourceLinks @@ -26,27 +25,24 @@ class BaseErrorBody(BaseResponseBody): def as_error(self, status_code: int) -> ApiError: """Serialize the response as an API error to raise in a handler.""" - return ApiError( - status_code=status_code, - content=self.dict(), - ) + return ApiError(status_code=status_code, content=self.dict()) class ErrorSource(BaseModel): """An object containing references to the source of the error.""" pointer: Optional[str] = Field( - None, + default=None, description=( "A JSON Pointer [RFC6901] to the associated entity in the request document." ), ) parameter: Optional[str] = Field( - None, + default=None, description="a string indicating which URI query parameter caused the error.", ) header: Optional[str] = Field( - None, + default=None, description="A string indicating which header caused the error.", ) @@ -96,18 +92,18 @@ def get_some_model(): ), ) source: Optional[ErrorSource] = Field( - None, + default=None, description="An object containing references to the source of the error.", ) meta: Optional[Dict[str, Any]] = Field( - None, + default=None, description=( "An object containing non-standard information about this " "occurrence of the error" ), ) errorCode: str = Field( - ErrorCodes.GENERAL_ERROR.value.code, + default=ErrorCodes.GENERAL_ERROR.value.code, description=("The Opentrons error code associated with the error"), ) @@ -175,12 +171,12 @@ def from_exc( ) -class ErrorBody(BaseErrorBody, GenericModel, Generic[ErrorDetailsT]): +class ErrorBody(BaseErrorBody, Generic[ErrorDetailsT]): """A response body for a single error.""" errors: Sequence[ErrorDetailsT] = Field(..., description="Error details.") links: Optional[ResourceLinks] = Field( - None, + default=None, description=( "Links that leads to further details about " "this particular occurrence of the problem." @@ -188,12 +184,12 @@ class ErrorBody(BaseErrorBody, GenericModel, Generic[ErrorDetailsT]): ) -class MultiErrorResponse(BaseErrorBody, GenericModel, Generic[ErrorDetailsT]): +class MultiErrorResponse(BaseErrorBody, Generic[ErrorDetailsT]): """An response body for multiple errors.""" errors: Sequence[ErrorDetailsT] = Field(..., description="Error details.") links: Optional[ResourceLinks] = Field( - None, + default=None, description=( "Links that leads to further details about " "this particular occurrence of the problem." diff --git a/robot-server/robot_server/health/models.py b/robot-server/robot_server/health/models.py index ce8a0c2a56f..c0b01385402 100644 --- a/robot-server/robot_server/health/models.py +++ b/robot-server/robot_server/health/models.py @@ -16,7 +16,7 @@ class HealthLinks(BaseModel): " or refer to the OpenAPI specification of the `/logs` endpoint, instead." ), examples=["/logs/api.log"], - deprecated=True, + json_schema_extra={"deprecated": True}, ) serialLog: str = Field( ..., @@ -26,7 +26,7 @@ class HealthLinks(BaseModel): " or refer to the OpenAPI specification of the `/logs` endpoint, instead." ), examples=["/logs/serial.log"], - deprecated=True, + json_schema_extra={"deprecated": True}, ) serverLog: str = Field( ..., @@ -36,10 +36,10 @@ class HealthLinks(BaseModel): " or refer to the OpenAPI specification of the `/logs` endpoint, instead." ), examples=["/logs/server.log"], - deprecated=True, + json_schema_extra={"deprecated": True}, ) oddLog: typing.Optional[str] = Field( - None, + default=None, description=( "The path to the on-device display app logs endpoint" " (only present on the Opentrons Flex)." @@ -47,7 +47,7 @@ class HealthLinks(BaseModel): " or refer to the OpenAPI specification of the `/logs` endpoint, instead." ), examples=["/logs/touchscreen.log"], - deprecated=True, + json_schema_extra={"deprecated": True}, ) apiSpec: str = Field( ..., @@ -103,16 +103,16 @@ class Health(BaseResponseBody): ..., description="The system's maximum supported Protocol API version, " "in the format `[major_version, minor_version]`", - min_items=2, - max_items=2, + min_length=2, + max_length=2, examples=[[2, 8]], ) minimum_protocol_api_version: typing.List[int] = Field( ..., description="The system's minimum supported Protocol API version, " "in the format `[major_version, minor_version]`", - min_items=2, - max_items=2, + min_length=2, + max_length=2, examples=[[2, 0]], ) robot_serial: typing.Optional[str] = Field( diff --git a/robot-server/robot_server/health/router.py b/robot-server/robot_server/health/router.py index a4ca84bd2c1..20f02f0803b 100644 --- a/robot-server/robot_server/health/router.py +++ b/robot-server/robot_server/health/router.py @@ -122,6 +122,10 @@ def _system_version_or_fallback() -> str: "description": "Robot motor controller is not ready", } }, + # response_model_exclude_none=True preserves behavior from older FastAPI and/or + # Pydantic versions. It's unclear exactly what changed and why this is only + # necessary for this endpoint in particular. + response_model_exclude_none=True, ) async def get_health( hardware: Annotated[HardwareControlAPI, Depends(get_hardware)], diff --git a/robot-server/robot_server/instruments/instrument_models.py b/robot-server/robot_server/instruments/instrument_models.py index f6a8ed0f82f..544ff774e54 100644 --- a/robot-server/robot_server/instruments/instrument_models.py +++ b/robot-server/robot_server/instruments/instrument_models.py @@ -5,7 +5,6 @@ from typing import Optional, TypeVar, Union, Generic, Dict, List from datetime import datetime from pydantic import BaseModel, Field -from pydantic.generics import GenericModel from opentrons.calibration_storage.types import SourceType @@ -41,7 +40,7 @@ class InconsistentCalibrationFailure(BaseModel): limit: float -class _GenericInstrument(GenericModel, Generic[InstrumentModelT, InstrumentDataT]): +class _GenericInstrument(BaseModel, Generic[InstrumentModelT, InstrumentDataT]): """Base instrument response.""" mount: str = Field(..., description="The mount this instrument is attached to.") @@ -51,14 +50,15 @@ class _GenericInstrument(GenericModel, Generic[InstrumentModelT, InstrumentDataT instrumentModel: InstrumentModelT = Field(..., description="Instrument model.") serialNumber: str = Field(..., description="Instrument hardware serial number.") subsystem: Optional[SubSystem] = Field( - None, + default=None, description="The subsystem corresponding to this instrument.", ) ok: Literal[True] = Field( ..., description="Whether this instrument is OK and ready to go" ) firmwareVersion: Optional[str] = Field( - None, description="The firmware version of this instrument (if applicable)" + default=None, + description="The firmware version of this instrument (if applicable)", ) data: InstrumentDataT @@ -77,7 +77,7 @@ class GripperData(BaseModel): jawState: str = Field(..., description="Gripper Jaw state.") calibratedOffset: Optional[InstrumentCalibrationData] = Field( - None, description="Calibrated gripper offset." + default=None, description="Calibrated gripper offset." ) @@ -88,7 +88,7 @@ class PipetteData(BaseModel): min_volume: float = Field(..., description="Minimum pipette volume.") max_volume: float = Field(..., description="Maximum pipette volume.") calibratedOffset: Optional[InstrumentCalibrationData] = Field( - None, description="Calibrated pipette offset." + default=None, description="Calibrated pipette offset." ) @@ -109,7 +109,7 @@ class Pipette(_GenericInstrument[PipetteModel, PipetteData]): instrumentName: PipetteName instrumentModel: PipetteModel data: PipetteData - state: Optional[PipetteState] + state: Optional[PipetteState] = None class Gripper(_GenericInstrument[GripperModelStr, GripperData]): diff --git a/robot-server/robot_server/modules/module_models.py b/robot-server/robot_server/modules/module_models.py index f9acaf59a8b..7b6da4925ac 100644 --- a/robot-server/robot_server/modules/module_models.py +++ b/robot-server/robot_server/modules/module_models.py @@ -1,7 +1,6 @@ """Request and response models for /modules endpoints.""" from datetime import datetime from pydantic import BaseModel, Field -from pydantic.generics import GenericModel from typing import Generic, List, Optional, TypeVar, Union from typing_extensions import Literal @@ -72,7 +71,7 @@ class UsbPort(BaseModel): ) -class _GenericModule(GenericModel, Generic[ModuleT, ModuleModelT, ModuleDataT]): +class _GenericModule(BaseModel, Generic[ModuleT, ModuleModelT, ModuleDataT]): """Base module response.""" id: str = Field( diff --git a/robot-server/robot_server/persistence/_migrations/_up_to_3_worker.py b/robot-server/robot_server/persistence/_migrations/_up_to_3_worker.py index 7e94476d87a..eb916a0a6f7 100644 --- a/robot-server/robot_server/persistence/_migrations/_up_to_3_worker.py +++ b/robot-server/robot_server/persistence/_migrations/_up_to_3_worker.py @@ -86,11 +86,7 @@ def migrate_commands_for_run( ) parsed_commands: typing.Iterable[commands.Command] = ( - pydantic.parse_obj_as( - commands.Command, # type: ignore[arg-type] - c, - ) - for c in old_commands + commands.CommandAdapter.validate_python(c) for c in old_commands ) new_command_rows = [ diff --git a/robot-server/robot_server/persistence/pydantic.py b/robot-server/robot_server/persistence/pydantic.py index c56312ec166..8c6383f0ae1 100644 --- a/robot-server/robot_server/persistence/pydantic.py +++ b/robot-server/robot_server/persistence/pydantic.py @@ -1,11 +1,12 @@ """Store Pydantic objects in the SQL database.""" import json -from typing import Type, TypeVar, List, Sequence -from pydantic import BaseModel, parse_raw_as, parse_obj_as +from typing import Type, TypeVar, Sequence, overload +from pydantic import BaseModel, TypeAdapter _BaseModelT = TypeVar("_BaseModelT", bound=BaseModel) +_TypeAdapterArgT = TypeVar("_TypeAdapterArgT") def pydantic_to_json(obj: BaseModel) -> str: @@ -23,11 +24,23 @@ def pydantic_list_to_json(obj_list: Sequence[BaseModel]) -> str: return json.dumps([obj.dict(by_alias=True, exclude_none=True) for obj in obj_list]) +@overload def json_to_pydantic(model: Type[_BaseModelT], json_str: str) -> _BaseModelT: - """Parse a Pydantic object stored in the SQL database.""" - return parse_raw_as(model, json_str) + ... + +@overload +def json_to_pydantic( + model: TypeAdapter[_TypeAdapterArgT], json_str: str +) -> _TypeAdapterArgT: + ... -def json_to_pydantic_list(model: Type[_BaseModelT], json_str: str) -> List[_BaseModelT]: - """Parse a list of Pydantic objects stored in the SQL database.""" - return [parse_obj_as(model, obj_dict) for obj_dict in json.loads(json_str)] + +def json_to_pydantic( + model: Type[_BaseModelT] | TypeAdapter[_TypeAdapterArgT], json_str: str +) -> _BaseModelT | _TypeAdapterArgT: + """Parse a Pydantic object stored in the SQL database.""" + if isinstance(model, TypeAdapter): + return model.validate_json(json_str) + else: + return model.model_validate_json(json_str) diff --git a/robot-server/robot_server/protocols/protocol_models.py b/robot-server/robot_server/protocols/protocol_models.py index c7841f25776..c20bd1ae5ed 100644 --- a/robot-server/robot_server/protocols/protocol_models.py +++ b/robot-server/robot_server/protocols/protocol_models.py @@ -1,7 +1,7 @@ """Protocol file models.""" from datetime import datetime -from pydantic import BaseModel, Extra, Field +from pydantic import ConfigDict, BaseModel, Field from typing import Any, List, Optional from enum import Enum @@ -49,13 +49,7 @@ class Metadata(BaseModel): this should be considered an exception to the rule. """ - # todo(mm, 2021-09-17): Revise these docs after specifying - # metadata more. github.com/Opentrons/opentrons/issues/8334 - - class Config: - """Tell Pydantic that metadata objects can have arbitrary fields.""" - - extra = Extra.allow + model_config = ConfigDict(extra="allow") class Protocol(ResourceModel): diff --git a/robot-server/robot_server/robot/calibration/check/models.py b/robot-server/robot_server/robot/calibration/check/models.py index 0574a51aced..4b7fbf783a8 100644 --- a/robot-server/robot_server/robot/calibration/check/models.py +++ b/robot-server/robot_server/robot/calibration/check/models.py @@ -1,7 +1,7 @@ from typing import Any, Dict, Optional, List from typing_extensions import Literal from functools import partial -from pydantic import BaseModel, Field +from pydantic import ConfigDict, BaseModel, Field from ..helper_classes import RequiredLabware, AttachedPipette @@ -14,8 +14,8 @@ Field, ..., description="An offset vector in deck coordinates (x, y, z)", - min_items=3, - max_items=3, + min_length=3, + max_length=3, ) @@ -75,9 +75,9 @@ class TipComparisonMap(BaseModel): class ComparisonStatePerCalibration(BaseModel): - tipLength: Optional[TipComparisonMap] - pipetteOffset: Optional[PipetteOffsetComparisonMap] - deck: Optional[DeckComparisonMap] + tipLength: Optional[TipComparisonMap] = None + pipetteOffset: Optional[PipetteOffsetComparisonMap] = None + deck: Optional[DeckComparisonMap] = None class ComparisonStatePerPipette(BaseModel): @@ -123,10 +123,9 @@ class CalibrationCheckSessionStatus(BaseModel): supportedCommands: List[str] = Field( ..., description="A list of supported commands for this user flow" ) - - class Config: - arbitrary_types_allowed = True - schema_extra = { + model_config = ConfigDict( + arbitrary_types_allowed=True, + json_schema_extra={ "examples": [ { "instruments": [ @@ -154,4 +153,5 @@ class Config: }, } ] - } + }, + ) diff --git a/robot-server/robot_server/robot/calibration/deck/models.py b/robot-server/robot_server/robot/calibration/deck/models.py index 6a444e31682..7e1f1fa5fee 100644 --- a/robot-server/robot_server/robot/calibration/deck/models.py +++ b/robot-server/robot_server/robot/calibration/deck/models.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field +from pydantic import ConfigDict, BaseModel, Field from typing import List from ..helper_classes import AttachedPipette, RequiredLabware @@ -15,9 +15,8 @@ class DeckCalibrationSessionStatus(BaseModel): supportedCommands: List[str] = Field( ..., description="A list of supported commands for this user flow" ) - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "example": [ { "instrument": { @@ -41,3 +40,4 @@ class Config: } ] } + ) diff --git a/robot-server/robot_server/robot/calibration/pipette_offset/models.py b/robot-server/robot_server/robot/calibration/pipette_offset/models.py index d6aa245943f..26d70046d1f 100644 --- a/robot-server/robot_server/robot/calibration/pipette_offset/models.py +++ b/robot-server/robot_server/robot/calibration/pipette_offset/models.py @@ -1,5 +1,5 @@ from typing import Optional, List -from pydantic import BaseModel, Field +from pydantic import ConfigDict, BaseModel, Field from ..helper_classes import AttachedPipette, RequiredLabware, NextSteps @@ -23,9 +23,8 @@ class PipetteOffsetCalibrationSessionStatus(BaseModel): nextSteps: Optional[NextSteps] = Field( None, description="Next Available Steps in Session" ) - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "examples": [ { "instrument": { @@ -51,3 +50,4 @@ class Config: } ] } + ) diff --git a/robot-server/robot_server/robot/calibration/tip_length/models.py b/robot-server/robot_server/robot/calibration/tip_length/models.py index 0149b0a65ee..30d698abb5d 100644 --- a/robot-server/robot_server/robot/calibration/tip_length/models.py +++ b/robot-server/robot_server/robot/calibration/tip_length/models.py @@ -1,5 +1,5 @@ from typing import Optional, List -from pydantic import BaseModel, Field +from pydantic import ConfigDict, BaseModel, Field from ..helper_classes import AttachedPipette, RequiredLabware, NextSteps @@ -18,9 +18,8 @@ class TipCalibrationSessionStatus(BaseModel): supportedCommands: List[str] = Field( ..., description="A list of supported commands for this user flow" ) - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "examples": [ { "instrument": { @@ -53,3 +52,4 @@ class Config: } ] } + ) diff --git a/robot-server/robot_server/robot/calibration/util.py b/robot-server/robot_server/robot/calibration/util.py index 60192aaa74b..dbb2ea5236b 100644 --- a/robot-server/robot_server/robot/calibration/util.py +++ b/robot-server/robot_server/robot/calibration/util.py @@ -13,7 +13,7 @@ from opentrons.types import Point, Location from robot_server.service.errors import RobotServerError -from ...service.session.models.command_definitions import CommandDefinition +from robot_server.service.session.models.command_definitions import CommandDefinition from .constants import ( STATE_WILDCARD, MOVE_TO_REF_POINT_SAFETY_BUFFER, diff --git a/robot-server/robot_server/runs/router/labware_router.py b/robot-server/robot_server/runs/router/labware_router.py index 16924fd4ae8..5d244e5438b 100644 --- a/robot-server/robot_server/runs/router/labware_router.py +++ b/robot-server/robot_server/runs/router/labware_router.py @@ -1,4 +1,5 @@ """Router for /runs endpoints dealing with labware offsets and definitions.""" + import logging from typing import Annotated, Union diff --git a/robot-server/robot_server/runs/run_store.py b/robot-server/robot_server/runs/run_store.py index 0148f20058b..446a7a96482 100644 --- a/robot-server/robot_server/runs/run_store.py +++ b/robot-server/robot_server/runs/run_store.py @@ -1,4 +1,5 @@ """Runs' on-db store.""" + import logging from collections import defaultdict from dataclasses import dataclass @@ -7,8 +8,8 @@ from typing import Dict, List, Optional, Literal, Union import sqlalchemy +from pydantic import TypeAdapter, ValidationError from sqlalchemy import and_ -from pydantic import ValidationError from opentrons.util.helpers import utc_now from opentrons.protocol_engine import ( @@ -38,7 +39,6 @@ from robot_server.persistence.pydantic import ( json_to_pydantic, pydantic_to_json, - json_to_pydantic_list, pydantic_list_to_json, ) from robot_server.protocols.protocol_store import ProtocolNotFoundError @@ -433,7 +433,7 @@ def get_run_time_parameters(self, run_id: str) -> List[RunTimeParameter]: try: return ( - json_to_pydantic_list(RunTimeParameter, row.run_time_parameters) # type: ignore[arg-type] + json_to_pydantic(_rtp_list_adapter, row.run_time_parameters) if row.run_time_parameters is not None else [] ) @@ -515,8 +515,7 @@ def get_commands_slice( slice_result = transaction.execute(select_slice).all() sliced_commands: List[Command] = [ - json_to_pydantic(Command, row.command) # type: ignore[arg-type] - for row in slice_result + _parse_command(row.command) for row in slice_result ] return CommandSlice( @@ -680,7 +679,7 @@ def get_command(self, run_id: str, command_id: str) -> Command: if command is None: raise CommandNotFoundError(command_id=command_id) - return json_to_pydantic(Command, command) # type: ignore[arg-type] + return _parse_command(command) def remove(self, run_id: str) -> None: """Remove a run by its unique identifier. @@ -829,6 +828,15 @@ def _convert_state_to_sql_values( } +_command_type_adapter: TypeAdapter[Command] = TypeAdapter(Command) +_rtp_list_adapter = TypeAdapter(list[RunTimeParameter]) + + +def _parse_command(json_str: str) -> Command: + """Parse a JSON string from the database into a `Command`.""" + return json_to_pydantic(_command_type_adapter, json_str) + + def _convert_commands_status_to_sql_command_status( status: CommandStatus, ) -> CommandStatusSQLEnum: diff --git a/robot-server/robot_server/service/json_api/request.py b/robot-server/robot_server/service/json_api/request.py index 9f716cb66e3..26ad5c882f6 100644 --- a/robot-server/robot_server/service/json_api/request.py +++ b/robot-server/robot_server/service/json_api/request.py @@ -1,12 +1,11 @@ from typing import Generic, TypeVar -from pydantic import Field -from pydantic.generics import GenericModel +from pydantic import BaseModel, Field RequestDataT = TypeVar("RequestDataT") -class RequestModel(GenericModel, Generic[RequestDataT]): +class RequestModel(BaseModel, Generic[RequestDataT]): """ """ data: RequestDataT = Field(..., description="the document’s 'primary data'") diff --git a/robot-server/robot_server/service/json_api/response.py b/robot-server/robot_server/service/json_api/response.py index 8764d8edd53..0d2500b5297 100644 --- a/robot-server/robot_server/service/json_api/response.py +++ b/robot-server/robot_server/service/json_api/response.py @@ -11,9 +11,8 @@ ParamSpec, Callable, ) +from typing_extensions import get_args, override from pydantic import Field, BaseModel -from pydantic.generics import GenericModel -from pydantic.typing import get_args from fastapi.responses import JSONResponse from fastapi.dependencies.utils import get_typed_return_annotation from .resource_links import ResourceLinks as DeprecatedResourceLinks @@ -41,29 +40,38 @@ class BaseResponseBody(BaseModel): JSON responses adhere to the server's generated OpenAPI Spec. """ + @override def dict(self, *args: Any, **kwargs: Any) -> Dict[str, Any]: """Always exclude `None` when serializing to an object. - The OpenAPI spec marks `Optional` BaseModel fields as omittable, but - not nullable. This `dict` method override ensures that `null` is never - returned in a response, which would violate the spec. + With Pydantic v1, the OpenAPI spec described `Optional`(i.e., possibly + `None`-valued) fields as omittable, but not nullable. This did not match + Pydantic's actual serialization behavior, which serialized Python `None` to + JSON `null` by default. This method override fixed the mismatch by making + Pydantic omit the field from serialization instead. + + With Pydantic v2, the OpenAPI spec does describe `Optional` fields as nullable, + matching Pydantic's serialization behavior. We therefore no longer need this + override to make them match. However, removing this override and changing + serialization behavior at this point would risk breaking things on the client. """ kwargs["exclude_none"] = True return super().dict(*args, **kwargs) + @override def json(self, *args: Any, **kwargs: Any) -> str: """See notes in `.dict()`.""" kwargs["exclude_none"] = True return super().json(*args, **kwargs) -class SimpleBody(BaseResponseBody, GenericModel, Generic[ResponseDataT]): +class SimpleBody(BaseResponseBody, Generic[ResponseDataT]): """A response that returns a single resource.""" data: ResponseDataT = Field(..., description=DESCRIPTION_DATA) -class Body(BaseResponseBody, GenericModel, Generic[ResponseDataT, ResponseLinksT]): +class Body(BaseResponseBody, Generic[ResponseDataT, ResponseLinksT]): """A response that returns a single resource and stateful links.""" data: ResponseDataT = Field(..., description=DESCRIPTION_DATA) @@ -74,7 +82,7 @@ class SimpleEmptyBody(BaseResponseBody): """A response that returns no data and no links.""" -class EmptyBody(BaseResponseBody, GenericModel, Generic[ResponseLinksT]): +class EmptyBody(BaseResponseBody, Generic[ResponseLinksT]): """A response that returns no data except stateful links.""" links: ResponseLinksT = Field(..., description=DESCRIPTION_LINKS) @@ -94,7 +102,7 @@ class MultiBodyMeta(BaseModel): ) -class SimpleMultiBody(BaseResponseBody, GenericModel, Generic[ResponseDataT]): +class SimpleMultiBody(BaseResponseBody, Generic[ResponseDataT]): """A response that returns multiple resources.""" data: Sequence[ResponseDataT] = Field(..., description=DESCRIPTION_DATA) @@ -114,11 +122,7 @@ class SimpleMultiBody(BaseResponseBody, GenericModel, Generic[ResponseDataT]): ) -class MultiBody( - BaseResponseBody, - GenericModel, - Generic[ResponseDataT, ResponseLinksT], -): +class MultiBody(BaseResponseBody, Generic[ResponseDataT, ResponseLinksT]): """A response that returns multiple resources and stateful links.""" data: List[ResponseDataT] = Field(..., description=DESCRIPTION_DATA) @@ -240,7 +244,7 @@ class DeprecatedResponseDataModel(BaseModel): # TODO(mc, 2021-12-09): remove this model -class DeprecatedResponseModel(GenericModel, Generic[ResponseDataT]): +class DeprecatedResponseModel(BaseModel, Generic[ResponseDataT]): """A response that returns a single resource and stateful links. This deprecated response model may serialize `Optional` fields to `null`, @@ -259,7 +263,7 @@ class DeprecatedResponseModel(GenericModel, Generic[ResponseDataT]): # TODO(mc, 2021-12-09): remove this model class DeprecatedMultiResponseModel( - GenericModel, + BaseModel, Generic[ResponseDataT], ): """A response that returns multiple resources and stateful links. diff --git a/robot-server/robot_server/service/labware/models.py b/robot-server/robot_server/service/labware/models.py index 97222e635cf..89d140ced61 100644 --- a/robot-server/robot_server/service/labware/models.py +++ b/robot-server/robot_server/service/labware/models.py @@ -2,7 +2,7 @@ from datetime import datetime from functools import partial -from pydantic import BaseModel, Field +from pydantic import ConfigDict, BaseModel, Field from robot_server.service.json_api import ( DeprecatedResponseDataModel, @@ -73,9 +73,8 @@ class LabwareCalibration(DeprecatedResponseDataModel): definitionHash: str = Field( ..., description="The sha256 hash of key labware definition details" ) - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "examples": [ { "calibrationData": { @@ -111,6 +110,7 @@ class Config: }, ] } + ) MultipleCalibrationsResponse = DeprecatedMultiResponseModel[LabwareCalibration] diff --git a/robot-server/robot_server/service/legacy/models/control.py b/robot-server/robot_server/service/legacy/models/control.py index 923ba29eb30..c375ed9d949 100644 --- a/robot-server/robot_server/service/legacy/models/control.py +++ b/robot-server/robot_server/service/legacy/models/control.py @@ -3,7 +3,7 @@ from enum import Enum from opentrons import types -from pydantic import BaseModel, Field, root_validator +from pydantic import model_validator, ConfigDict, BaseModel, Field class MotionTarget(str, Enum): @@ -28,8 +28,8 @@ class HomeTarget(str, Enum): Field, ..., description="A point in deck coordinates (x, y, z)", - min_items=3, - max_items=3, + min_length=3, + max_length=3, ) @@ -51,9 +51,8 @@ class RobotPositions(BaseModel): class RobotPositionsResponse(BaseModel): positions: RobotPositions - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "example": { "positions": { "change_pipette": { @@ -65,6 +64,7 @@ class Config: } } } + ) class Mount(str, Enum): @@ -95,7 +95,8 @@ class RobotMoveTarget(BaseModel): "if target is pipette", ) - @root_validator(pre=True) + @model_validator(mode="before") + @classmethod def root_validator(cls, values): points = values.get("point", []) target = values.get("target") @@ -108,8 +109,8 @@ def root_validator(cls, values): ) return values - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "examples": [ { "target": "mount", @@ -124,6 +125,7 @@ class Config: }, ] } + ) class RobotHomeTarget(BaseModel): @@ -141,17 +143,19 @@ class RobotHomeTarget(BaseModel): " in that case)", ) - @root_validator(pre=True) + @model_validator(mode="before") + @classmethod def root_validate(cls, values): # Make sure that mount is present if target is pipette if values.get("target") == HomeTarget.pipette.value and not values.get("mount"): raise ValueError("mount must be specified if target is pipette") return values - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "examples": [{"target": "robot"}, {"target": "pipette", "mount": "right"}] } + ) class RobotLightState(BaseModel): diff --git a/robot-server/robot_server/service/legacy/models/deck_calibration.py b/robot-server/robot_server/service/legacy/models/deck_calibration.py index a1db8eef866..f424ee4fb07 100644 --- a/robot-server/robot_server/service/legacy/models/deck_calibration.py +++ b/robot-server/robot_server/service/legacy/models/deck_calibration.py @@ -31,19 +31,19 @@ class InstrumentOffset(BaseModel): single: Offset = Field( ..., - deprecated=True, description=( "This will always be `[0, 0, 0]`." " Use the `GET /calibration/pipette_offset` endpoint instead." ), + json_schema_extra={"deprecated": True}, ) multi: Offset = Field( ..., - deprecated=True, description=( "This will always be `[0, 0, 0]`." " Use the `GET /calibration/pipette_offset` endpoint instead." ), + json_schema_extra={"deprecated": True}, ) @@ -78,7 +78,7 @@ class DeckCalibrationData(BaseModel): " was used in this calibration." " This is deprecated because it was prone to bugs where semantically identical" " definitions had different hashes.", - deprecated=True, + json_schema_extra={"deprecated": True}, ) source: typing.Optional[SourceType] = Field( None, description="The calibration source" diff --git a/robot-server/robot_server/service/legacy/models/modules.py b/robot-server/robot_server/service/legacy/models/modules.py index 992c109591a..e15419b7397 100644 --- a/robot-server/robot_server/service/legacy/models/modules.py +++ b/robot-server/robot_server/service/legacy/models/modules.py @@ -1,5 +1,5 @@ import typing -from pydantic import BaseModel, Field +from pydantic import ConfigDict, BaseModel, Field class TemperatureModuleLiveData(BaseModel): @@ -168,9 +168,8 @@ class Modules(BaseModel): """A list of all attached modules and the status of each one""" modules: typing.List[Module] - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "examples": [ {"modules": []}, { @@ -270,6 +269,7 @@ class Config: }, ] } + ) class ModuleSerial(BaseModel): @@ -288,9 +288,11 @@ class SerialCommand(BaseModel): args: typing.Optional[typing.List[typing.Any]] = Field( None, description="The ordered args list for the call" ) - - class Config: - schema_extra = {"examples": [{"command_type": "set_Temperature", "args": [60]}]} + model_config = ConfigDict( + json_schema_extra={ + "examples": [{"command_type": "set_Temperature", "args": [60]}] + } + ) class SerialCommandResponse(BaseModel): @@ -300,6 +302,6 @@ class SerialCommandResponse(BaseModel): returnValue: typing.Optional[str] = Field( None, description="The return value from the call" ) - - class Config: - schema_extra = {"examples": [{"message": "Success", "returnValue": None}]} + model_config = ConfigDict( + json_schema_extra={"examples": [{"message": "Success", "returnValue": None}]} + ) diff --git a/robot-server/robot_server/service/legacy/models/motors.py b/robot-server/robot_server/service/legacy/models/motors.py index b27b4260131..2242185d6cc 100644 --- a/robot-server/robot_server/service/legacy/models/motors.py +++ b/robot-server/robot_server/service/legacy/models/motors.py @@ -1,7 +1,7 @@ from enum import Enum import typing -from pydantic import BaseModel, Field, validator +from pydantic import field_validator, BaseModel, Field from opentrons.hardware_control import types @@ -38,8 +38,10 @@ class EngagedMotors(BaseModel): z_r: EngagedMotor p_l: EngagedMotor p_r: EngagedMotor - q: typing.Optional[EngagedMotor] # Optional since OT2 doesn't have these axes - g: typing.Optional[EngagedMotor] + q: typing.Optional[ + EngagedMotor + ] = None # Optional since OT2 doesn't have these axes + g: typing.Optional[EngagedMotor] = None class Axes(BaseModel): @@ -47,6 +49,7 @@ class Axes(BaseModel): axes: typing.List[MotorName] - @validator("axes", pre=True) + @field_validator("axes", mode="before") + @classmethod def lower_case_motor_name(cls, v): return [m.lower() for m in v] diff --git a/robot-server/robot_server/service/legacy/models/networking.py b/robot-server/robot_server/service/legacy/models/networking.py index 5b3351fdb3f..53a666719f7 100644 --- a/robot-server/robot_server/service/legacy/models/networking.py +++ b/robot-server/robot_server/service/legacy/models/networking.py @@ -1,7 +1,14 @@ import typing from enum import Enum -from pydantic import BaseModel, Field, SecretStr, validator, root_validator +from pydantic import ( + field_validator, + model_validator, + ConfigDict, + BaseModel, + Field, + SecretStr, +) from opentrons.system import wifi @@ -53,9 +60,8 @@ class NetworkingStatus(BaseModel): description="Per-interface networking status. Properties are " "named for network interfaces", ) - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "example": { "status": "full", "interfaces": { @@ -76,6 +82,7 @@ class Config: }, } } + ) class NetworkingSecurityType(str, Enum): @@ -111,9 +118,8 @@ class WifiNetworks(BaseModel): """The list of networks""" list: typing.List[WifiNetworkFull] - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "example": { "list": [ { @@ -126,6 +132,7 @@ class Config: ] } } + ) class WifiConfiguration(BaseModel): @@ -141,7 +148,7 @@ class WifiConfiguration(BaseModel): "`false` (default if key is not " "present) otherwise.", ) - securityType: typing.Optional[NetworkingSecurityType] + securityType: typing.Optional[NetworkingSecurityType] = None psk: typing.Optional[SecretStr] = Field( None, @@ -160,10 +167,11 @@ class WifiConfiguration(BaseModel): 'and it may also have `"anonymousIdentity"` and ' '`"caCert"` properties, both of which are identified' " as present but not required.", - required=["eapType"], + json_schema_extra={"required": ["eapType"]}, ) - @validator("eapConfig") + @field_validator("eapConfig") + @classmethod def eap_config_validate(cls, v): """Custom validator for the eapConfig field""" if v is not None: @@ -176,7 +184,8 @@ def eap_config_validate(cls, v): return v - @root_validator(pre=True) + @model_validator(mode="before") + @classmethod def validate_configuration(cls, values): """Validate the configuration""" security_type = values.get("securityType") @@ -199,8 +208,8 @@ def validate_configuration(cls, values): raise ValueError("If securityType is wpa-eap, eapConfig must be specified") return values - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "examples": [ {"ssid": "linksys"}, { @@ -225,6 +234,7 @@ class Config: }, ] } + ) class WifiConfigurationResponse(BaseModel): @@ -257,7 +267,7 @@ class WifiKeyFile(BaseModel): class AddWifiKeyFileResponse(WifiKeyFile): """Response to add wifi key file""" - message: typing.Optional[str] + message: typing.Optional[str] = None class WifiKeyFiles(BaseModel): @@ -266,9 +276,8 @@ class WifiKeyFiles(BaseModel): wifi_keys: typing.List[WifiKeyFile] = Field( [], alias="keys", description="A list of keys in the system" ) - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "example": { "keys": [ { @@ -279,6 +288,7 @@ class Config: ] } } + ) class EapConfigOptionType(str, Enum): @@ -327,9 +337,8 @@ class EapOptions(BaseModel): """An object describing all supported EAP variants and their parameters""" options: typing.List[EapVariant] - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "example": { "options": [ { @@ -365,3 +374,4 @@ class Config: ] } } + ) diff --git a/robot-server/robot_server/service/legacy/models/pipettes.py b/robot-server/robot_server/service/legacy/models/pipettes.py index 3c43ac3fec4..cff8c01307f 100644 --- a/robot-server/robot_server/service/legacy/models/pipettes.py +++ b/robot-server/robot_server/service/legacy/models/pipettes.py @@ -1,6 +1,6 @@ import typing -from pydantic import BaseModel, Field +from pydantic import ConfigDict, BaseModel, Field class AttachedPipette(BaseModel): @@ -36,9 +36,8 @@ class PipettesByMount(BaseModel): left: AttachedPipette right: AttachedPipette - - class Config: - schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "example": { "left": { "model": "p300_single_v1.5", @@ -58,3 +57,4 @@ class Config: }, } } + ) diff --git a/robot-server/robot_server/service/legacy/models/settings.py b/robot-server/robot_server/service/legacy/models/settings.py index f77977dbe3a..980610f8ef5 100644 --- a/robot-server/robot_server/service/legacy/models/settings.py +++ b/robot-server/robot_server/service/legacy/models/settings.py @@ -3,7 +3,7 @@ from typing import Optional, List, Dict, Any, Union -from pydantic import BaseModel, Field, create_model, validator +from pydantic import field_validator, BaseModel, Field, create_model from opentrons_shared_data.pipette import model_constants from opentrons.config.reset import ResetOptionId @@ -17,7 +17,7 @@ class AdvancedSetting(BaseModel): ..., description="The ID by which the property used to be known; not" " useful now and may contain spaces or hyphens", - deprecated=True, + json_schema_extra={"deprecated": True}, ) title: str = Field( ..., @@ -99,7 +99,8 @@ class LogLevel(BaseModel): None, description="The value to set (conforming to Python log levels)" ) - @validator("log_level", pre=True) + @field_validator("log_level", mode="before") + @classmethod def lower_case_log_keys(cls, value): return value if value is None else LogLevels(value.lower(), None) @@ -136,7 +137,7 @@ class PipetteSettingsField(BaseModel): units: Optional[str] = Field( None, description="The physical units this value is in (e.g. mm, uL)" ) - type: Optional[PipetteSettingsFieldType] + type: Optional[PipetteSettingsFieldType] = None min: float = Field(..., description="The minimum acceptable value of the property") max: float = Field(..., description="The maximum acceptable value of the property") default: float = Field(..., description="The default value of the property") @@ -184,11 +185,9 @@ class BasePipetteSettingFields(BaseModel): class PipetteSettings(BaseModel): - info: PipetteSettingsInfo - setting_fields: PipetteSettingsFields # type: ignore - class Config: - fields = {"setting_fields": "fields"} + info: PipetteSettingsInfo + setting_fields: PipetteSettingsFields = Field(..., alias="fields") # type: ignore MultiPipetteSettings = Dict[str, PipetteSettings] @@ -208,7 +207,8 @@ class PipetteSettingsUpdate(BaseModel): None, alias="fields" ) - @validator("setting_fields") + @field_validator("setting_fields") + @classmethod def validate_fields(cls, v): """A validator to ensure that values for mutable configs are floats and booleans for quirks.""" diff --git a/robot-server/robot_server/service/legacy/routers/networking.py b/robot-server/robot_server/service/legacy/routers/networking.py index b47cf283ddf..3c9ea08be2c 100644 --- a/robot-server/robot_server/service/legacy/routers/networking.py +++ b/robot-server/robot_server/service/legacy/routers/networking.py @@ -90,7 +90,7 @@ async def get_wifi_networks( "letting the system decide when to do a rescan." ), ), - ] = False + ] = False, ) -> WifiNetworks: networks = await nmcli.available_ssids(rescan) return WifiNetworks(list=[WifiNetworkFull(**n) for n in networks]) @@ -210,7 +210,7 @@ async def delete_wifi_key( description="The ID of key to delete, as determined by a previous" " call to GET /wifi/keys", ), - ] + ], ) -> V1BasicResponse: """Delete wifi key handler""" deleted_file = wifi.remove_key(key_uuid) diff --git a/robot-server/robot_server/service/legacy/routers/settings.py b/robot-server/robot_server/service/legacy/routers/settings.py index f1c7c77dc72..12589748283 100644 --- a/robot-server/robot_server/service/legacy/routers/settings.py +++ b/robot-server/robot_server/service/legacy/routers/settings.py @@ -424,7 +424,7 @@ def _pipette_settings_from_mutable_configs( # TODO(mc, 2020-09-17): s/fields/setting_fields (?) # need model and name? - return PipetteSettings( # type: ignore[call-arg] + return PipetteSettings( info=PipetteSettingsInfo( name=cast(str, mutable_configs.get("name", "")), model=cast(str, mutable_configs.get("model", "")), diff --git a/robot-server/robot_server/service/pipette_offset/models.py b/robot-server/robot_server/service/pipette_offset/models.py index 401afc29273..f5b7af12452 100644 --- a/robot-server/robot_server/service/pipette_offset/models.py +++ b/robot-server/robot_server/service/pipette_offset/models.py @@ -31,7 +31,7 @@ class PipetteOffsetCalibration(DeprecatedResponseDataModel): pipette: str = Field(..., description="The pipette ID") mount: str = Field(..., description="The pipette mount") offset: typing.List[float] = Field( - ..., description="The pipette offset vector", max_items=3, min_items=3 + ..., description="The pipette offset vector", max_length=3, min_length=3 ) tiprack: str = Field( ..., diff --git a/robot-server/robot_server/service/session/models/command.py b/robot-server/robot_server/service/session/models/command.py index 6c33f219e05..0f68eb996e0 100644 --- a/robot-server/robot_server/service/session/models/command.py +++ b/robot-server/robot_server/service/session/models/command.py @@ -22,7 +22,6 @@ from typing_extensions import Literal from pydantic import BaseModel, Field -from pydantic.generics import GenericModel from opentrons.util.helpers import utc_now from opentrons.protocol_engine import commands @@ -70,7 +69,7 @@ class CommandStatus(str, Enum): class SessionCommandRequest( - GenericModel, typing.Generic[CommandT, RequestDataT, ResponseDataT] + BaseModel, typing.Generic[CommandT, RequestDataT, ResponseDataT] ): """A session command request.""" @@ -101,7 +100,6 @@ def make_response( class SessionCommandResponse( DeprecatedResponseDataModel, - GenericModel, typing.Generic[CommandT, RequestDataT, ResponseDataT], ): """A session command response.""" @@ -110,8 +108,8 @@ class SessionCommandResponse( data: RequestDataT status: CommandStatus createdAt: datetime = Field(default_factory=utc_now) - startedAt: typing.Optional[datetime] - completedAt: typing.Optional[datetime] + startedAt: typing.Optional[datetime] = None + completedAt: typing.Optional[datetime] = None result: typing.Optional[ResponseDataT] = None diff --git a/robot-server/robot_server/service/session/models/common.py b/robot-server/robot_server/service/session/models/common.py index add30e47d3e..f61f7d0a5bd 100644 --- a/robot-server/robot_server/service/session/models/common.py +++ b/robot-server/robot_server/service/session/models/common.py @@ -22,4 +22,4 @@ class EmptyModel(BaseModel): class JogPosition(BaseModel): - vector: OffsetVector = Field(..., min_items=3, max_items=3) + vector: OffsetVector = Field(..., min_length=3, max_length=3) diff --git a/robot-server/robot_server/service/session/models/session.py b/robot-server/robot_server/service/session/models/session.py index 4587c99f046..7724865e9e4 100644 --- a/robot-server/robot_server/service/session/models/session.py +++ b/robot-server/robot_server/service/session/models/session.py @@ -52,7 +52,7 @@ class SessionCreateAttributes(BaseModel): class SessionCreateAttributesNoParams(SessionCreateAttributes): """The base model of request that has no createParams.""" - createParams: typing.Optional[BaseModel] + createParams: typing.Optional[BaseModel] = None class CalibrationCheckCreateAttributes(SessionCreateAttributesNoParams): diff --git a/robot-server/robot_server/service/session/router.py b/robot-server/robot_server/service/session/router.py index 3b9da7ba88a..d950572ce8a 100644 --- a/robot-server/robot_server/service/session/router.py +++ b/robot-server/robot_server/service/session/router.py @@ -169,7 +169,7 @@ async def session_command_execute_handler( log.debug(f"Command result: {command_result}") - return CommandResponse( + return CommandResponse.construct( data=command_result, links=get_valid_session_links(sessionId, router) ) diff --git a/robot-server/robot_server/service/tip_length/models.py b/robot-server/robot_server/service/tip_length/models.py index 2ff8f81b5ef..eca3757be5c 100644 --- a/robot-server/robot_server/service/tip_length/models.py +++ b/robot-server/robot_server/service/tip_length/models.py @@ -24,7 +24,7 @@ class TipLengthCalibration(DeprecatedResponseDataModel): " This is deprecated because it was prone to bugs where semantically identical" " definitions had different hashes." " Use `uri` instead.", - deprecated=True, + json_schema_extra={"deprecated": True}, ) pipette: str = Field(..., description="The pipette ID") lastModified: datetime = Field( diff --git a/robot-server/robot_server/settings.py b/robot-server/robot_server/settings.py index 40b0ed663bb..d67e1040fef 100644 --- a/robot-server/robot_server/settings.py +++ b/robot-server/robot_server/settings.py @@ -4,10 +4,11 @@ from functools import lru_cache from pathlib import Path -from pydantic import BaseSettings, Field +from pydantic import Field from dotenv import load_dotenv from opentrons.config import infer_config_base_dir +from pydantic_settings import BaseSettings, SettingsConfigDict log = logging.getLogger(__name__) @@ -28,9 +29,7 @@ class Environment(BaseSettings): """Environment related settings""" dot_env_path: Path = infer_config_base_dir() / "robot.env" - - class Config: - env_prefix = "OT_ROBOT_SERVER_" + model_config = SettingsConfigDict(env_prefix="OT_ROBOT_SERVER_") # If you update this, also update the generated settings_schema.json. @@ -94,6 +93,8 @@ class RobotServerSettings(BaseSettings): ), ) + model_config = SettingsConfigDict(env_prefix="OT_ROBOT_SERVER_") + maximum_quick_transfer_protocols: int = Field( default=20, gt=0, @@ -110,6 +111,3 @@ class RobotServerSettings(BaseSettings): "The maximum number of uploaded data files to allow before auto-deleting old ones." ), ) - - class Config: - env_prefix = "OT_ROBOT_SERVER_" diff --git a/robot-server/scripts/spec_generator.py b/robot-server/scripts/spec_generator.py index 8f2a807c771..f3253f2471b 100755 --- a/robot-server/scripts/spec_generator.py +++ b/robot-server/scripts/spec_generator.py @@ -21,7 +21,7 @@ def write_api_spec(output: TextIOBase) -> None: spec_dict = get_openapi( title="Opentrons HTTP API Spec", - version=API_VERSION, + version=str(API_VERSION), description=( "This OpenAPI spec describes the HTTP API for Opentrons " "robots. It may be retrieved from a robot on port 31950 at " @@ -34,7 +34,7 @@ def write_api_spec(output: TextIOBase) -> None: json.dump(spec_dict, output) -def _run_cmdline() -> None: +def _run_cmdline() -> int: parser = ArgumentParser( description="Generate a static openapi spec. Note: robot-server must be importable when you run this." ) @@ -45,12 +45,8 @@ def _run_cmdline() -> None: help="Where to write the file (will be json)", ) args = parser.parse_args() - try: - write_api_spec(args.output) - return 0 - except Exception as e: - sys.stderr.write(str(e) + "\n") - return -1 + write_api_spec(args.output) + return 0 if __name__ == "__main__": diff --git a/robot-server/setup.py b/robot-server/setup.py index 7fcdabade82..1866f478dbc 100755 --- a/robot-server/setup.py +++ b/robot-server/setup.py @@ -56,10 +56,11 @@ def get_version(): f"opentrons-shared-data=={VERSION}", f"server-utils=={VERSION}", "anyio==3.7.1", - "fastapi==0.99.1", + "fastapi==0.100.0", "python-dotenv==1.0.1", "python-multipart==0.0.6", - "pydantic==1.10.12", + "pydantic==2.9.0", + "pydantic-settings==2.4.0", "typing-extensions>=4.0.0,<5", "uvicorn==0.27.0.post1", "wsproto==1.2.0", diff --git a/robot-server/tests/conftest.py b/robot-server/tests/conftest.py index aed43626a2b..125e695a134 100644 --- a/robot-server/tests/conftest.py +++ b/robot-server/tests/conftest.py @@ -398,3 +398,24 @@ def sql_engine(tmp_path: Path) -> Generator[SQLEngine, None, None]: with sql_engine_ctx(db_file_path) as engine: metadata.create_all(engine) yield engine + + +def datetime_to_zulu_iso8601(dt: datetime) -> str: + """Serialize a datetime to an ISO8601 string. + + If the timezone is UTC, represent that with "Z", which matches what Pydantic does, + instead instead of with "+00:00", which is Python's default. + + e.g. "2024-12-10T19:40:55.984327Z" vs. "2024-12-10T19:40:55.984327+00:00". + """ + return dt.isoformat().replace("+00:00", "Z") + + +# todo(mm, 2024-12-10): +# In Python 3.11+, we can replace this with just datetime.fromisoformat(). +def zulu_iso8601_to_datetime(iso8601_str: str) -> datetime: + """Parse an ISO8601 datetime string with a "Z" timezone. + + See `datetime_to_zulu_iso8601()`. + """ + return datetime.fromisoformat(iso8601_str.replace("Z", "+00:00")) diff --git a/robot-server/tests/errors/test_exception_handlers.py b/robot-server/tests/errors/test_exception_handlers.py index eff6b5e041c..45cbf27321e 100644 --- a/robot-server/tests/errors/test_exception_handlers.py +++ b/robot-server/tests/errors/test_exception_handlers.py @@ -22,13 +22,7 @@ class Item(BaseModel): @pytest.fixture def app() -> FastAPI: """Get a FastAPI app with our exception handlers.""" - app = FastAPI() - - # TODO(mc, 2021-05-10): upgrade to FastAPI > 0.61.2 to use `exception_handlers` arg - # see https://github.com/tiangolo/fastapi/pull/1924 - for exc_cls, handler in exception_handlers.items(): - app.add_exception_handler(exc_cls, handler) - + app = FastAPI(exception_handlers=exception_handlers) return app @@ -159,21 +153,23 @@ def create_item(item: Item) -> Item: "errorCode": "4000", "id": "InvalidRequest", "title": "Invalid Request", - "detail": "field required", + "detail": "Field required", "source": {"pointer": "/string_field"}, }, { "errorCode": "4000", "id": "InvalidRequest", "title": "Invalid Request", - "detail": "value is not a valid integer", + "detail": "Input should be a valid integer, unable to parse " + "string as an integer", "source": {"pointer": "/int_field"}, }, { "errorCode": "4000", "id": "InvalidRequest", "title": "Invalid Request", - "detail": "value could not be parsed to a boolean", + "detail": "Input should be a valid boolean, unable to interpret " + "input", "source": {"pointer": "/array_field/0"}, }, ] @@ -196,7 +192,8 @@ def get_item(count: int) -> Item: "errorCode": "4000", "id": "InvalidRequest", "title": "Invalid Request", - "detail": "value is not a valid integer", + "detail": "Input should be a valid integer, unable to parse " + "string as an integer", "source": {"parameter": "count"}, }, ] @@ -219,7 +216,7 @@ def get_item(header_name: str = Header(...)) -> Item: "errorCode": "4000", "id": "InvalidRequest", "title": "Invalid Request", - "detail": "field required", + "detail": "Field required", "source": {"header": "header-name"}, }, ] @@ -242,8 +239,9 @@ def create_item_legacy(item: Item) -> Item: assert response.json() == { "errorCode": "4000", "message": ( - "body.string_field: none is not an allowed value; " - "body.int_field: value is not a valid integer; " - "body.array_field.0: value could not be parsed to a boolean" + "body.string_field: Input should be a valid string; " + "body.int_field: Input should be a valid integer, unable to parse " + "string as an integer; body.array_field.0: Input should be a valid " + "boolean, unable to interpret input" ), } diff --git a/robot-server/tests/integration/http_api/runs/test_persistence.py b/robot-server/tests/integration/http_api/runs/test_persistence.py index 943f644e8d3..84b5f28aeb6 100644 --- a/robot-server/tests/integration/http_api/runs/test_persistence.py +++ b/robot-server/tests/integration/http_api/runs/test_persistence.py @@ -6,6 +6,7 @@ import anyio import pytest +from tests.conftest import zulu_iso8601_to_datetime from tests.integration.dev_server import DevServer from tests.integration.robot_client import RobotClient @@ -298,13 +299,13 @@ async def test_runs_completed_started_at_persist_via_actions_router( get_run_response = await client.get_run(run_id=run_id) run_data = get_run_response.json()["data"] - assert datetime.fromisoformat(run_data["startedAt"]).timestamp() == pytest.approx( + assert zulu_iso8601_to_datetime(run_data["startedAt"]).timestamp() == pytest.approx( expected_started_at.timestamp(), abs=2 ) - assert datetime.fromisoformat(run_data["completedAt"]).timestamp() == pytest.approx( - expected_completed_at.timestamp(), abs=2 - ) + assert zulu_iso8601_to_datetime( + run_data["completedAt"] + ).timestamp() == pytest.approx(expected_completed_at.timestamp(), abs=2) # make sure the times are in order assert run_data["startedAt"] < run_data["completedAt"] @@ -332,6 +333,6 @@ async def test_runs_completed_filled_started_at_none_persist( run_data = get_run_response.json()["data"] assert "startedAt" not in run_data - assert datetime.fromisoformat(run_data["completedAt"]).timestamp() == pytest.approx( - expected_completed_at.timestamp(), abs=2 - ) + assert zulu_iso8601_to_datetime( + run_data["completedAt"] + ).timestamp() == pytest.approx(expected_completed_at.timestamp(), abs=2) diff --git a/robot-server/tests/integration/robot_client.py b/robot-server/tests/integration/robot_client.py index 7e6b70c09f6..bda888507bb 100644 --- a/robot-server/tests/integration/robot_client.py +++ b/robot-server/tests/integration/robot_client.py @@ -10,7 +10,7 @@ from httpx import Response -_STARTUP_WAIT = 20 +_STARTUP_WAIT = 40 _SHUTDOWN_WAIT = 20 _RUN_POLL_INTERVAL = 0.1 diff --git a/robot-server/tests/integration/system/test_system_time.tavern.yaml b/robot-server/tests/integration/system/test_system_time.tavern.yaml index 1b78ea1d1f5..bffb3760cc8 100644 --- a/robot-server/tests/integration/system/test_system_time.tavern.yaml +++ b/robot-server/tests/integration/system/test_system_time.tavern.yaml @@ -34,14 +34,6 @@ stages: id: 'time' response: status_code: 422 - json: - errors: - - id: 'InvalidRequest' - title: 'Invalid Request' - detail: 'field required' - errorCode: '4000' - source: - pointer: '/data/systemTime' - name: System Time PUT request on a dev server raises error request: url: '{ot2_server_base_url}/system/time' diff --git a/robot-server/tests/integration/test_identify.tavern.yaml b/robot-server/tests/integration/test_identify.tavern.yaml index b753ef84db7..1ad773c420e 100644 --- a/robot-server/tests/integration/test_identify.tavern.yaml +++ b/robot-server/tests/integration/test_identify.tavern.yaml @@ -7,7 +7,7 @@ stages: - name: Identify a robot by flashing the lights request: method: POST - url: "{ot2_server_base_url}/identify" + url: '{ot2_server_base_url}/identify' params: seconds: 5 response: @@ -23,9 +23,6 @@ stages: - name: Attempt to send identify request without parameters request: method: POST - url: "{ot2_server_base_url}/identify" + url: '{ot2_server_base_url}/identify' response: status_code: 422 - json: - message: "query.seconds: field required" - errorCode: "4000" diff --git a/robot-server/tests/integration/test_settings_log_level.tavern.yaml b/robot-server/tests/integration/test_settings_log_level.tavern.yaml index 0a7c4e6bcf4..9604a821d87 100644 --- a/robot-server/tests/integration/test_settings_log_level.tavern.yaml +++ b/robot-server/tests/integration/test_settings_log_level.tavern.yaml @@ -11,16 +11,16 @@ marks: - warning - error stages: - - name: Set log_level to acceptable values + - name: Set log_level to acceptable values request: method: POST - url: "{ot2_server_base_url}/settings/log_level/local" - json: - log_level: "{log_level}" + url: '{ot2_server_base_url}/settings/log_level/local' + json: + log_level: '{log_level}' response: status_code: 200 json: - message: "log_level set to {log_level}" + message: 'log_level set to {log_level}' --- # Incorect Log Level Requests test_name: POST Set log level to invalid value @@ -28,31 +28,25 @@ marks: - usefixtures: - ot2_server_base_url stages: - - name: Set log_level to error + - name: Set log_level to error request: method: POST - url: "{ot2_server_base_url}/settings/log_level/local" - json: + url: '{ot2_server_base_url}/settings/log_level/local' + json: log_level: bad_level response: status_code: 422 - json: - message: "body.log_level: '{tavern.request_vars.json.log_level}' is not a valid LogLevels" - errorCode: '4000' --- test_name: POST Set log level to nothing marks: - usefixtures: - ot2_server_base_url stages: - - name: Set log_level to nothing + - name: Set log_level to nothing request: method: POST - url: "{ot2_server_base_url}/settings/log_level/local" - json: + url: '{ot2_server_base_url}/settings/log_level/local' + json: log_level: Null response: status_code: 422 - json: - message: "log_level must be set" - errorCode: '4000' diff --git a/robot-server/tests/integration/test_settings_reset_options.tavern.yaml b/robot-server/tests/integration/test_settings_reset_options.tavern.yaml index e6436d2a352..2f6ce05f120 100644 --- a/robot-server/tests/integration/test_settings_reset_options.tavern.yaml +++ b/robot-server/tests/integration/test_settings_reset_options.tavern.yaml @@ -195,6 +195,3 @@ stages: doesNotExist: true response: status_code: 422 - json: - message: !re_search 'value is not a valid enumeration member' - errorCode: '4000' diff --git a/robot-server/tests/maintenance_runs/test_run_data_manager.py b/robot-server/tests/maintenance_runs/test_run_data_manager.py index 07bc9c2e476..634eaab6ce5 100644 --- a/robot-server/tests/maintenance_runs/test_run_data_manager.py +++ b/robot-server/tests/maintenance_runs/test_run_data_manager.py @@ -1,4 +1,5 @@ """Tests for RunDataManager.""" + import pytest from datetime import datetime from decoy import Decoy @@ -62,13 +63,17 @@ def engine_state_summary() -> StateSummary: """Get a StateSummary value object.""" return StateSummary( status=EngineStatus.IDLE, - errors=[ErrorOccurrence.construct(id="some-error-id")], # type: ignore[call-arg] + errors=[ErrorOccurrence.model_construct(id="some-error-id")], # type: ignore[call-arg] hasEverEnteredErrorRecovery=False, - labware=[LoadedLabware.construct(id="some-labware-id")], # type: ignore[call-arg] - labwareOffsets=[LabwareOffset.construct(id="some-labware-offset-id")], # type: ignore[call-arg] - pipettes=[LoadedPipette.construct(id="some-pipette-id")], # type: ignore[call-arg] - modules=[LoadedModule.construct(id="some-module-id")], # type: ignore[call-arg] - liquids=[Liquid(id="some-liquid-id", displayName="liquid", description="desc")], + labware=[LoadedLabware.model_construct(id="some-labware-id")], # type: ignore[call-arg] + labwareOffsets=[LabwareOffset.model_construct(id="some-labware-offset-id")], # type: ignore[call-arg] + pipettes=[LoadedPipette.model_construct(id="some-pipette-id")], # type: ignore[call-arg] + modules=[LoadedModule.model_construct(id="some-module-id")], # type: ignore[call-arg] + liquids=[ + Liquid.model_construct( + id="some-liquid-id", displayName="liquid", description="desc" + ) + ], liquidClasses=[], wells=[], ) diff --git a/robot-server/tests/persistence/test_pydantic.py b/robot-server/tests/persistence/test_pydantic.py new file mode 100644 index 00000000000..4e25b8c0fca --- /dev/null +++ b/robot-server/tests/persistence/test_pydantic.py @@ -0,0 +1,35 @@ +"""Unit tests for `robot_server.persistence.pydantic`.""" + + +from pydantic import BaseModel, Field, TypeAdapter + +from robot_server.persistence import pydantic as subject + + +class _DummyModel(BaseModel): + field: str + aliasedField: str = Field(alias="aliasedFieldAlias") + + +def test_round_trip() -> None: + """Test Python->JSON->Python round trips.""" + original = _DummyModel.construct(field="hello", aliasedField="world") + after_round_trip = subject.json_to_pydantic( + _DummyModel, subject.pydantic_to_json(original) + ) + assert after_round_trip == original + + original_list = [original] * 10 + after_round_trip_list = subject.json_to_pydantic( + TypeAdapter(list[_DummyModel]), subject.pydantic_list_to_json(original_list) + ) + assert after_round_trip_list == original_list + + +def test_field_aliases() -> None: + """The JSON should contain field aliases, not the Python attribute names.""" + original = _DummyModel.construct(field="hello", aliasedField="world") + json = subject.pydantic_to_json(original) + json_list = subject.pydantic_list_to_json([original]) + assert '"aliasedFieldAlias"' in json + assert '"aliasedFieldAlias"' in json_list diff --git a/robot-server/tests/runs/router/test_base_router.py b/robot-server/tests/runs/router/test_base_router.py index ee9b291cc4a..9cf42061faa 100644 --- a/robot-server/tests/runs/router/test_base_router.py +++ b/robot-server/tests/runs/router/test_base_router.py @@ -1,4 +1,5 @@ """Tests for base /runs routes.""" + from opentrons.hardware_control import HardwareControlAPI from opentrons_shared_data.robot.types import RobotTypeEnum import pytest @@ -874,6 +875,7 @@ async def test_get_current_state_success( ) }, tipStates={"mock-pipette-id": TipState(hasTip=True)}, + placeLabwareState=None, ) assert result.content.links == CurrentStateLinks( lastCompleted=CommandLinkNoMeta( diff --git a/robot-server/tests/runs/router/test_labware_router.py b/robot-server/tests/runs/router/test_labware_router.py index 1252d983efb..a81c6726e6d 100644 --- a/robot-server/tests/runs/router/test_labware_router.py +++ b/robot-server/tests/runs/router/test_labware_router.py @@ -1,4 +1,5 @@ """Tests for /runs routes dealing with labware offsets and definitions.""" + import pytest from datetime import datetime from decoy import Decoy @@ -49,7 +50,7 @@ def run() -> Run: @pytest.fixture() def labware_definition(minimal_labware_def: LabwareDefDict) -> LabwareDefinition: """Create a labware definition fixture.""" - return LabwareDefinition.parse_obj(minimal_labware_def) + return LabwareDefinition.model_validate(minimal_labware_def) async def test_add_labware_offset( @@ -162,8 +163,8 @@ async def test_get_run_labware_definition( mock_run_data_manager.get_run_loaded_labware_definitions(run_id="run-id") ).then_return( [ - SD_LabwareDefinition.construct(namespace="test_1"), # type: ignore[call-arg] - SD_LabwareDefinition.construct(namespace="test_2"), # type: ignore[call-arg] + SD_LabwareDefinition.model_construct(namespace="test_1"), # type: ignore[call-arg] + SD_LabwareDefinition.model_construct(namespace="test_2"), # type: ignore[call-arg] ] ) @@ -172,7 +173,7 @@ async def test_get_run_labware_definition( ) assert result.content.data == [ - SD_LabwareDefinition.construct(namespace="test_1"), # type: ignore[call-arg] - SD_LabwareDefinition.construct(namespace="test_2"), # type: ignore[call-arg] + SD_LabwareDefinition.model_construct(namespace="test_1"), # type: ignore[call-arg] + SD_LabwareDefinition.model_construct(namespace="test_2"), # type: ignore[call-arg] ] assert result.status_code == 200 diff --git a/robot-server/tests/runs/test_error_recovery_mapping.py b/robot-server/tests/runs/test_error_recovery_mapping.py index 8b75ff99aad..0212fd0b6ed 100644 --- a/robot-server/tests/runs/test_error_recovery_mapping.py +++ b/robot-server/tests/runs/test_error_recovery_mapping.py @@ -116,9 +116,9 @@ def test_create_error_recovery_policy_defined_error( @pytest.mark.parametrize("enabled", [True, False]) def test_enabled_boolean(enabled: bool) -> None: """enabled=False should override any rules and always fail the run.""" - command = LiquidProbe.construct() # type: ignore[call-arg] + command = LiquidProbe.construct() error_data = DefinedErrorData[LiquidNotFoundError]( - public=LiquidNotFoundError.construct() # type: ignore[call-arg] + public=LiquidNotFoundError.construct() ) rules = [ @@ -160,9 +160,9 @@ def test_enabled_on_flex_disabled_on_ot2( robot_type: RobotType, expect_error_recovery_to_be_enabled: bool ) -> None: """On OT-2s, the run should always fail regardless of any input rules.""" - command = LiquidProbe.construct() # type: ignore[call-arg] + command = LiquidProbe.construct() error_data = DefinedErrorData[LiquidNotFoundError]( - public=LiquidNotFoundError.construct() # type: ignore[call-arg] + public=LiquidNotFoundError.construct() ) rules = [ diff --git a/robot-server/tests/runs/test_run_controller.py b/robot-server/tests/runs/test_run_controller.py index 1aa17ba9932..8b417aff1b2 100644 --- a/robot-server/tests/runs/test_run_controller.py +++ b/robot-server/tests/runs/test_run_controller.py @@ -111,7 +111,7 @@ def command_annotations() -> List[CommandAnnotation]: def protocol_commands() -> List[pe_commands.Command]: """Get a StateSummary value object.""" return [ - pe_commands.WaitForResume.construct( # type: ignore[call-arg] + pe_commands.WaitForResume.model_construct( # type: ignore[call-arg] params=pe_commands.WaitForResumeParams(message="hello world") ) ] diff --git a/robot-server/tests/runs/test_run_data_manager.py b/robot-server/tests/runs/test_run_data_manager.py index a56c8dbc705..31b58f9950a 100644 --- a/robot-server/tests/runs/test_run_data_manager.py +++ b/robot-server/tests/runs/test_run_data_manager.py @@ -1,4 +1,5 @@ """Tests for RunDataManager.""" + from datetime import datetime from typing import Optional, List, Dict from unittest.mock import sentinel @@ -98,13 +99,17 @@ def engine_state_summary() -> StateSummary: """Get a StateSummary value object.""" return StateSummary( status=EngineStatus.IDLE, - errors=[ErrorOccurrence.construct(id="some-error-id")], # type: ignore[call-arg] + errors=[ErrorOccurrence.model_construct(id="some-error-id")], # type: ignore[call-arg] hasEverEnteredErrorRecovery=False, - labware=[LoadedLabware.construct(id="some-labware-id")], # type: ignore[call-arg] - labwareOffsets=[LabwareOffset.construct(id="some-labware-offset-id")], # type: ignore[call-arg] - pipettes=[LoadedPipette.construct(id="some-pipette-id")], # type: ignore[call-arg] - modules=[LoadedModule.construct(id="some-module-id")], # type: ignore[call-arg] - liquids=[Liquid(id="some-liquid-id", displayName="liquid", description="desc")], + labware=[LoadedLabware.model_construct(id="some-labware-id")], # type: ignore[call-arg] + labwareOffsets=[LabwareOffset.model_construct(id="some-labware-offset-id")], # type: ignore[call-arg] + pipettes=[LoadedPipette.model_construct(id="some-pipette-id")], # type: ignore[call-arg] + modules=[LoadedModule.model_construct(id="some-module-id")], # type: ignore[call-arg] + liquids=[ + Liquid.model_construct( + id="some-liquid-id", displayName="liquid", description="desc" + ) + ], liquidClasses=[], wells=[], ) @@ -513,13 +518,17 @@ async def test_get_all_runs( """It should get all runs, including current and historical.""" current_run_data = StateSummary( status=EngineStatus.IDLE, - errors=[ErrorOccurrence.construct(id="current-error-id")], # type: ignore[call-arg] + errors=[ErrorOccurrence.model_construct(id="current-error-id")], # type: ignore[call-arg] hasEverEnteredErrorRecovery=False, - labware=[LoadedLabware.construct(id="current-labware-id")], # type: ignore[call-arg] - labwareOffsets=[LabwareOffset.construct(id="current-labware-offset-id")], # type: ignore[call-arg] - pipettes=[LoadedPipette.construct(id="current-pipette-id")], # type: ignore[call-arg] - modules=[LoadedModule.construct(id="current-module-id")], # type: ignore[call-arg] - liquids=[Liquid(id="some-liquid-id", displayName="liquid", description="desc")], + labware=[LoadedLabware.model_construct(id="current-labware-id")], # type: ignore[call-arg] + labwareOffsets=[LabwareOffset.model_construct(id="current-labware-offset-id")], # type: ignore[call-arg] + pipettes=[LoadedPipette.model_construct(id="current-pipette-id")], # type: ignore[call-arg] + modules=[LoadedModule.model_construct(id="current-module-id")], # type: ignore[call-arg] + liquids=[ + Liquid.model_construct( + id="some-liquid-id", displayName="liquid", description="desc" + ) + ], liquidClasses=[], wells=[], ) @@ -534,12 +543,12 @@ async def test_get_all_runs( historical_run_data = StateSummary( status=EngineStatus.STOPPED, - errors=[ErrorOccurrence.construct(id="old-error-id")], # type: ignore[call-arg] + errors=[ErrorOccurrence.model_construct(id="old-error-id")], # type: ignore[call-arg] hasEverEnteredErrorRecovery=False, - labware=[LoadedLabware.construct(id="old-labware-id")], # type: ignore[call-arg] - labwareOffsets=[LabwareOffset.construct(id="old-labware-offset-id")], # type: ignore[call-arg] - pipettes=[LoadedPipette.construct(id="old-pipette-id")], # type: ignore[call-arg] - modules=[LoadedModule.construct(id="old-module-id")], # type: ignore[call-arg] + labware=[LoadedLabware.model_construct(id="old-labware-id")], # type: ignore[call-arg] + labwareOffsets=[LabwareOffset.model_construct(id="old-labware-offset-id")], # type: ignore[call-arg] + pipettes=[LoadedPipette.model_construct(id="old-pipette-id")], # type: ignore[call-arg] + modules=[LoadedModule.model_construct(id="old-module-id")], # type: ignore[call-arg] liquids=[], liquidClasses=[], wells=[], @@ -958,9 +967,7 @@ def test_get_commands_errors_slice_historical_run( mock_run_store: RunStore, ) -> None: """Should get a sliced command error list from engine store.""" - expected_commands_errors_result = [ - ErrorOccurrence.construct(id="error-id") # type: ignore[call-arg] - ] + expected_commands_errors_result = [ErrorOccurrence.construct(id="error-id")] command_error_slice = CommandErrorSlice( cursor=1, total_length=3, commands_errors=expected_commands_errors_result @@ -985,7 +992,7 @@ def test_get_commands_errors_slice_current_run( ) -> None: """Should get a sliced command error list from engine store.""" expected_commands_errors_result = [ - ErrorOccurrence.construct(id="error-id") # type: ignore[call-arg] + ErrorOccurrence.model_construct(id="error-id") # type: ignore[call-arg] ] command_error_slice = CommandErrorSlice( @@ -1257,16 +1264,16 @@ async def test_get_current_run_labware_definition( mock_run_orchestrator_store.get_loaded_labware_definitions() ).then_return( [ - LabwareDefinition.construct(namespace="test_1"), # type: ignore[call-arg] - LabwareDefinition.construct(namespace="test_2"), # type: ignore[call-arg] + LabwareDefinition.model_construct(namespace="test_1"), # type: ignore[call-arg] + LabwareDefinition.model_construct(namespace="test_2"), # type: ignore[call-arg] ] ) result = subject.get_run_loaded_labware_definitions(run_id="run-id") assert result == [ - LabwareDefinition.construct(namespace="test_1"), # type: ignore[call-arg] - LabwareDefinition.construct(namespace="test_2"), # type: ignore[call-arg] + LabwareDefinition.model_construct(namespace="test_1"), # type: ignore[call-arg] + LabwareDefinition.model_construct(namespace="test_2"), # type: ignore[call-arg] ] diff --git a/robot-server/tests/runs/test_run_store.py b/robot-server/tests/runs/test_run_store.py index ab8e5f10fdf..cfbe89a44e4 100644 --- a/robot-server/tests/runs/test_run_store.py +++ b/robot-server/tests/runs/test_run_store.py @@ -1,4 +1,5 @@ """Tests for robot_server.runs.run_store.""" + from datetime import datetime, timezone from pathlib import Path from typing import List, Optional, Type @@ -241,10 +242,10 @@ def run_time_parameters() -> List[pe_types.RunTimeParameter]: @pytest.fixture def invalid_state_summary() -> StateSummary: """Should fail pydantic validation.""" - analysis_error = pe_errors.ErrorOccurrence.construct( + analysis_error = pe_errors.ErrorOccurrence.model_construct( id="error-id", # Invalid value here should fail analysis - createdAt=MountType.LEFT, # type: ignore + createdAt=MountType.LEFT, # type: ignore[arg-type] errorType="BadError", detail="oh no", ) @@ -737,7 +738,7 @@ def test_get_run_time_parameters_invalid( state_summary: StateSummary, ) -> None: """It should return an empty list if there invalid parameters.""" - bad_parameters = [pe_types.BooleanParameter.construct(foo="bar")] # type: ignore[call-arg] + bad_parameters = [pe_types.BooleanParameter.construct(foo="bar")] subject.insert( run_id="run-id", protocol_id=None, @@ -993,12 +994,12 @@ def test_get_all_commands_as_preserialized_list( run_id="run-id", include_fixit_commands=True ) assert result == [ - '{"id": "pause-1", "createdAt": "2021-01-01T00:00:00", "commandType": "waitForResume",' - ' "key": "command-key", "status": "succeeded", "params": {"message": "hello world"}, "result": {}, "intent": "protocol"}', - '{"id": "pause-2", "createdAt": "2022-02-02T00:00:00", "commandType": "waitForResume",' - ' "key": "command-key", "status": "succeeded", "params": {"message": "hey world"}, "result": {}, "intent": "protocol"}', - '{"id": "pause-3", "createdAt": "2023-03-03T00:00:00", "commandType": "waitForResume", "key": "command-key", "status": "succeeded", "params": {"message": "sup world"}, "result": {}}', - '{"id": "fixit-pause-1", "createdAt": "2021-01-01T00:00:00", "commandType": "waitForResume", "key": "command-key", "status": "succeeded", "params": {"message": "hello world"}, "result": {}, "intent": "fixit"}', + '{"id":"pause-1","createdAt":"2021-01-01T00:00:00","commandType":"waitForResume",' + '"key":"command-key","status":"succeeded","params":{"message":"hello world"},"result":{},"intent":"protocol"}', + '{"id":"pause-2","createdAt":"2022-02-02T00:00:00","commandType":"waitForResume",' + '"key":"command-key","status":"succeeded","params":{"message":"hey world"},"result":{},"intent":"protocol"}', + '{"id":"pause-3","createdAt":"2023-03-03T00:00:00","commandType":"waitForResume","key":"command-key","status":"succeeded","params":{"message":"sup world"},"result":{}}', + '{"id":"fixit-pause-1","createdAt":"2021-01-01T00:00:00","commandType":"waitForResume","key":"command-key","status":"succeeded","params":{"message":"hello world"},"result":{},"intent":"fixit"}', ] @@ -1023,9 +1024,9 @@ def test_get_all_commands_as_preserialized_list_no_fixit( run_id="run-id", include_fixit_commands=False ) assert result == [ - '{"id": "pause-1", "createdAt": "2021-01-01T00:00:00", "commandType": "waitForResume",' - ' "key": "command-key", "status": "succeeded", "params": {"message": "hello world"}, "result": {}, "intent": "protocol"}', - '{"id": "pause-2", "createdAt": "2022-02-02T00:00:00", "commandType": "waitForResume",' - ' "key": "command-key", "status": "succeeded", "params": {"message": "hey world"}, "result": {}, "intent": "protocol"}', - '{"id": "pause-3", "createdAt": "2023-03-03T00:00:00", "commandType": "waitForResume", "key": "command-key", "status": "succeeded", "params": {"message": "sup world"}, "result": {}}', + '{"id":"pause-1","createdAt":"2021-01-01T00:00:00","commandType":"waitForResume",' + '"key":"command-key","status":"succeeded","params":{"message":"hello world"},"result":{},"intent":"protocol"}', + '{"id":"pause-2","createdAt":"2022-02-02T00:00:00","commandType":"waitForResume",' + '"key":"command-key","status":"succeeded","params":{"message":"hey world"},"result":{},"intent":"protocol"}', + '{"id":"pause-3","createdAt":"2023-03-03T00:00:00","commandType":"waitForResume","key":"command-key","status":"succeeded","params":{"message":"sup world"},"result":{}}', ] diff --git a/robot-server/tests/service/json_api/test_request.py b/robot-server/tests/service/json_api/test_request.py index 446c7e32339..71cd3d0cbcc 100644 --- a/robot-server/tests/service/json_api/test_request.py +++ b/robot-server/tests/service/json_api/test_request.py @@ -29,18 +29,24 @@ def test_attributes_as_item_model_empty_dict(): assert e.value.errors() == [ { "loc": ("data", "name"), - "msg": "field required", - "type": "value_error.missing", + "msg": "Field required", + "type": "missing", + "input": {}, + "url": "https://errors.pydantic.dev/2.9/v/missing", }, { "loc": ("data", "quantity"), - "msg": "field required", - "type": "value_error.missing", + "msg": "Field required", + "type": "missing", + "input": {}, + "url": "https://errors.pydantic.dev/2.9/v/missing", }, { "loc": ("data", "price"), - "msg": "field required", - "type": "value_error.missing", + "msg": "Field required", + "type": "missing", + "input": {}, + "url": "https://errors.pydantic.dev/2.9/v/missing", }, ] @@ -54,8 +60,10 @@ def test_attributes_required(): assert e.value.errors() == [ { "loc": ("data",), - "msg": "none is not an allowed value", - "type": "type_error.none.not_allowed", + "msg": "Input should be a valid dictionary", + "input": None, + "url": "https://errors.pydantic.dev/2.9/v/dict_type", + "type": "dict_type", }, ] @@ -69,8 +77,10 @@ def test_data_required(): assert e.value.errors() == [ { "loc": ("data",), - "msg": "none is not an allowed value", - "type": "type_error.none.not_allowed", + "msg": "Input should be a valid dictionary", + "input": None, + "url": "https://errors.pydantic.dev/2.9/v/dict_type", + "type": "dict_type", }, ] diff --git a/robot-server/tests/service/json_api/test_resource_links.py b/robot-server/tests/service/json_api/test_resource_links.py index 5505dfeac21..804fa77b837 100644 --- a/robot-server/tests/service/json_api/test_resource_links.py +++ b/robot-server/tests/service/json_api/test_resource_links.py @@ -27,5 +27,11 @@ def test_must_be_self_key_with_string_value(): with raises(ValidationError) as e: ThingWithLink.parse_obj(invalid_structure_to_validate) assert e.value.errors() == [ - {"loc": ("links",), "msg": "field required", "type": "value_error.missing"} + { + "loc": ("links",), + "msg": "Field required", + "type": "missing", + "input": {"invalid": {"key": "value"}}, + "url": "https://errors.pydantic.dev/2.9/v/missing", + } ] diff --git a/robot-server/tests/service/legacy/models/test_control.py b/robot-server/tests/service/legacy/models/test_control.py index 058ae5c80e4..931d7c0811a 100644 --- a/robot-server/tests/service/legacy/models/test_control.py +++ b/robot-server/tests/service/legacy/models/test_control.py @@ -11,12 +11,12 @@ def test_robot_home_target(): def test_robot_move_target_points_too_few(): - with pytest.raises(ValueError, match="ensure this value has at least 3 items"): + with pytest.raises(ValueError, match="List should have at least 3 items"): control.RobotMoveTarget(target=control.MotionTarget.pipette, point=[1, 2]) def test_robot_move_target_points_too_many(): - with pytest.raises(ValueError, match="ensure this value has at most 3 items"): + with pytest.raises(ValueError, match="List should have at most 3 items"): control.RobotMoveTarget(target=control.MotionTarget.pipette, point=[1, 2, 3, 4]) diff --git a/robot-server/tests/service/legacy/routers/test_settings.py b/robot-server/tests/service/legacy/routers/test_settings.py index 6c9ae8adb56..9c52256b82d 100644 --- a/robot-server/tests/service/legacy/routers/test_settings.py +++ b/robot-server/tests/service/legacy/routers/test_settings.py @@ -598,7 +598,7 @@ def test_reset_invalid_option( assert resp.status_code == 422 body = resp.json() assert "message" in body - assert "not a valid enumeration member" in body["message"] + assert "Input should be" in body["message"] @pytest.fixture() diff --git a/robot-server/tests/subsystems/test_router.py b/robot-server/tests/subsystems/test_router.py index c77e291736c..a5fb9f86ca6 100644 --- a/robot-server/tests/subsystems/test_router.py +++ b/robot-server/tests/subsystems/test_router.py @@ -72,7 +72,7 @@ def thread_manager(decoy: Decoy, ot3_hardware_api: "OT3API") -> ThreadManagedHar from opentrons.hardware_control.ot3api import OT3API except ImportError: pytest.skip("Cannot run on OT-2 (for now)") - manager = decoy.mock(cls=ThreadManagedHardware) # type: ignore[misc] + manager = decoy.mock(cls=ThreadManagedHardware) decoy.when(manager.wrapped()).then_return(ot3_hardware_api) decoy.when(manager.wraps_instance(OT3API)).then_return(True) return cast(ThreadManagedHardware, manager) diff --git a/robot-server/tests/system/test_system_router.py b/robot-server/tests/system/test_system_router.py index 68d2e765460..4b3f32402e3 100644 --- a/robot-server/tests/system/test_system_router.py +++ b/robot-server/tests/system/test_system_router.py @@ -1,13 +1,17 @@ """Tests for the /system router.""" +from typing import Iterator + import pytest from mock import MagicMock, patch from datetime import datetime, timezone from starlette.testclient import TestClient -from typing import Iterator +from pydantic import TypeAdapter from robot_server.service.json_api import ResourceLink, ResourceLinks, ResourceLinkKey from robot_server.system import errors, router +from tests.conftest import datetime_to_zulu_iso8601 + @pytest.fixture def mock_system_time() -> datetime: @@ -22,10 +26,13 @@ def mock_set_system_time(mock_system_time: datetime) -> Iterator[MagicMock]: yield p +ResourceLinksAdapter: TypeAdapter[ResourceLinks] = TypeAdapter(ResourceLinks) + + @pytest.fixture def response_links() -> ResourceLinks: """Get expected /system/time resource links.""" - return {ResourceLinkKey.self: ResourceLink(href="/system/time")} + return {ResourceLinkKey.self.value: ResourceLink(href="/system/time")} def test_raise_system_synchronized_error( @@ -103,7 +110,10 @@ def test_set_system_time( }, ) assert response.json() == { - "data": {"systemTime": mock_system_time.isoformat(), "id": "time"}, - "links": response_links, + "data": { + "systemTime": datetime_to_zulu_iso8601(mock_system_time), + "id": "time", + }, + "links": ResourceLinksAdapter.dump_python(response_links), } assert response.status_code == 200 diff --git a/server-utils/Pipfile b/server-utils/Pipfile index b54d6962543..537a0a670f7 100755 --- a/server-utils/Pipfile +++ b/server-utils/Pipfile @@ -19,7 +19,7 @@ pytest-lazy-fixture = "==0.6.3" pytest-xdist = "~=2.5.0" requests = "==2.31.0" mock = "==5.1.0" -mypy = "==1.8.0" +mypy = "==1.11.0" flake8 = "==7.0.0" flake8-annotations = "==3.0.1" flake8-docstrings = "~=1.7.0" diff --git a/server-utils/Pipfile.lock b/server-utils/Pipfile.lock index c9060279ba2..768034d5cb4 100644 --- a/server-utils/Pipfile.lock +++ b/server-utils/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5c9bee178723885363cdb4a226e6c1b7988731c23ae83fdde921d4ebb510090e" + "sha256": "6410a533fa68be2f8ba9ee2d77fd5f5d63653019d1a256ee8026ac52536d022e" }, "pipfile-spec": 6, "requires": { @@ -27,6 +27,14 @@ } }, "develop": { + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "anyio": { "hashes": [ "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780", @@ -45,11 +53,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "black": { "hashes": [ @@ -83,11 +91,11 @@ }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.8.30" }, "charset-normalizer": { "hashes": [ @@ -206,61 +214,81 @@ "toml" ], "hashes": [ - "sha256:0193657651f5399d433c92f8ae264aff31fc1d066deee4b831549526433f3f61", - "sha256:02f2edb575d62172aa28fe00efe821ae31f25dc3d589055b3fb64d51e52e4ab1", - "sha256:0491275c3b9971cdbd28a4595c2cb5838f08036bca31765bad5e17edf900b2c7", - "sha256:077d366e724f24fc02dbfe9d946534357fda71af9764ff99d73c3c596001bbd7", - "sha256:10e88e7f41e6197ea0429ae18f21ff521d4f4490aa33048f6c6f94c6045a6a75", - "sha256:18e961aa13b6d47f758cc5879383d27b5b3f3dcd9ce8cdbfdc2571fe86feb4dd", - "sha256:1a78b656a4d12b0490ca72651fe4d9f5e07e3c6461063a9b6265ee45eb2bdd35", - "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04", - "sha256:23b27b8a698e749b61809fb637eb98ebf0e505710ec46a8aa6f1be7dc0dc43a6", - "sha256:23f5881362dcb0e1a92b84b3c2809bdc90db892332daab81ad8f642d8ed55042", - "sha256:32a8d985462e37cfdab611a6f95b09d7c091d07668fdc26e47a725ee575fe166", - "sha256:3468cc8720402af37b6c6e7e2a9cdb9f6c16c728638a2ebc768ba1ef6f26c3a1", - "sha256:379d4c7abad5afbe9d88cc31ea8ca262296480a86af945b08214eb1a556a3e4d", - "sha256:3cacfaefe6089d477264001f90f55b7881ba615953414999c46cc9713ff93c8c", - "sha256:3e3424c554391dc9ef4a92ad28665756566a28fecf47308f91841f6c49288e66", - "sha256:46342fed0fff72efcda77040b14728049200cbba1279e0bf1188f1f2078c1d70", - "sha256:536d609c6963c50055bab766d9951b6c394759190d03311f3e9fcf194ca909e1", - "sha256:5d6850e6e36e332d5511a48a251790ddc545e16e8beaf046c03985c69ccb2676", - "sha256:6008adeca04a445ea6ef31b2cbaf1d01d02986047606f7da266629afee982630", - "sha256:64e723ca82a84053dd7bfcc986bdb34af8d9da83c521c19d6b472bc6880e191a", - "sha256:6b00e21f86598b6330f0019b40fb397e705135040dbedc2ca9a93c7441178e74", - "sha256:6d224f0c4c9c98290a6990259073f496fcec1b5cc613eecbd22786d398ded3ad", - "sha256:6dceb61d40cbfcf45f51e59933c784a50846dc03211054bd76b421a713dcdf19", - "sha256:7ac8f8eb153724f84885a1374999b7e45734bf93a87d8df1e7ce2146860edef6", - "sha256:85ccc5fa54c2ed64bd91ed3b4a627b9cce04646a659512a051fa82a92c04a448", - "sha256:869b5046d41abfea3e381dd143407b0d29b8282a904a19cb908fa24d090cc018", - "sha256:8bdb0285a0202888d19ec6b6d23d5990410decb932b709f2b0dfe216d031d218", - "sha256:8dfc5e195bbef80aabd81596ef52a1277ee7143fe419efc3c4d8ba2754671756", - "sha256:8e738a492b6221f8dcf281b67129510835461132b03024830ac0e554311a5c54", - "sha256:918440dea04521f499721c039863ef95433314b1db00ff826a02580c1f503e45", - "sha256:9641e21670c68c7e57d2053ddf6c443e4f0a6e18e547e86af3fad0795414a628", - "sha256:9d2f9d4cc2a53b38cabc2d6d80f7f9b7e3da26b2f53d48f05876fef7956b6968", - "sha256:a07f61fc452c43cd5328b392e52555f7d1952400a1ad09086c4a8addccbd138d", - "sha256:a3277f5fa7483c927fe3a7b017b39351610265308f5267ac6d4c2b64cc1d8d25", - "sha256:a4a3907011d39dbc3e37bdc5df0a8c93853c369039b59efa33a7b6669de04c60", - "sha256:aeb2c2688ed93b027eb0d26aa188ada34acb22dceea256d76390eea135083950", - "sha256:b094116f0b6155e36a304ff912f89bbb5067157aff5f94060ff20bbabdc8da06", - "sha256:b8ffb498a83d7e0305968289441914154fb0ef5d8b3157df02a90c6695978295", - "sha256:b9bb62fac84d5f2ff523304e59e5c439955fb3b7f44e3d7b2085184db74d733b", - "sha256:c61f66d93d712f6e03369b6a7769233bfda880b12f417eefdd4f16d1deb2fc4c", - "sha256:ca6e61dc52f601d1d224526360cdeab0d0712ec104a2ce6cc5ccef6ed9a233bc", - "sha256:ca7b26a5e456a843b9b6683eada193fc1f65c761b3a473941efe5a291f604c74", - "sha256:d12c923757de24e4e2110cf8832d83a886a4cf215c6e61ed506006872b43a6d1", - "sha256:d17bbc946f52ca67adf72a5ee783cd7cd3477f8f8796f59b4974a9b59cacc9ee", - "sha256:dfd1e1b9f0898817babf840b77ce9fe655ecbe8b1b327983df485b30df8cc011", - "sha256:e0860a348bf7004c812c8368d1fc7f77fe8e4c095d661a579196a9533778e156", - "sha256:f2f5968608b1fe2a1d00d01ad1017ee27efd99b3437e08b83ded9b7af3f6f766", - "sha256:f3771b23bb3675a06f5d885c3630b1d01ea6cac9e84a01aaf5508706dba546c5", - "sha256:f68ef3660677e6624c8cace943e4765545f8191313a07288a53d3da188bd8581", - "sha256:f86f368e1c7ce897bf2457b9eb61169a44e2ef797099fb5728482b8d69f3f016", - "sha256:f90515974b39f4dea2f27c0959688621b46d96d5a626cf9c53dbc653a895c05c", - "sha256:fe558371c1bdf3b8fa03e097c523fb9645b8730399c14fe7721ee9c9e2a545d3" + "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", + "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", + "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", + "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989", + "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", + "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", + "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", + "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", + "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", + "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", + "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", + "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", + "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", + "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", + "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", + "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8", + "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", + "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", + "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", + "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", + "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", + "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", + "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", + "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", + "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", + "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0", + "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", + "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", + "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", + "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", + "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", + "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", + "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", + "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", + "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de", + "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", + "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", + "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569", + "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", + "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", + "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", + "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", + "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", + "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6", + "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", + "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", + "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", + "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", + "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", + "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b", + "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", + "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", + "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3", + "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", + "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", + "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", + "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", + "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", + "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", + "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", + "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", + "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", + "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7", + "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", + "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", + "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", + "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", + "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", + "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a", + "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", + "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", + "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc" ], "markers": "python_version >= '3.8'", - "version": "==7.4.1" + "version": "==7.6.1" }, "decoy": { "hashes": [ @@ -273,27 +301,27 @@ }, "exceptiongroup": { "hashes": [ - "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", - "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.0" + "version": "==1.2.2" }, "execnet": { "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" + "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", + "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==2.1.1" }, "fastapi": { "hashes": [ - "sha256:976df7bab51ac7beda9f68c4513b8c4490b5c1135c72aafd0a5ee4023ec5282e", - "sha256:ac78f717cd80d657bd183f94d33b9bda84aa376a46a9dab513586b8eef1dc6fc" + "sha256:271662daf986da8fa98dc2b7c7f61c4abdfdccfb4786d79ed8b2878f172c6d5f", + "sha256:acb5f941ea8215663283c10018323ba7ea737c571b67fc7e88e9469c7eb1d12e" ], "markers": "python_version >= '3.7'", - "version": "==0.99.1" + "version": "==0.100.0" }, "flake8": { "hashes": [ @@ -392,37 +420,37 @@ }, "mypy": { "hashes": [ - "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6", - "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d", - "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02", - "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d", - "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3", - "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3", - "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", - "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66", - "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259", - "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", - "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd", - "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", - "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8", - "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", - "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b", - "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e", - "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6", - "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", - "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9", - "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", - "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a", - "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592", - "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218", - "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", - "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4", - "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410", - "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" + "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", + "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095", + "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac", + "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6", + "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", + "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", + "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00", + "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", + "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7", + "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13", + "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be", + "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", + "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850", + "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287", + "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", + "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229", + "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", + "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c", + "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac", + "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", + "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", + "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", + "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9", + "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", + "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf", + "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe", + "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.8.0" + "version": "==1.11.0" }, "mypy-extensions": { "hashes": [ @@ -434,11 +462,11 @@ }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==23.2" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pathspec": { "hashes": [ @@ -450,19 +478,19 @@ }, "platformdirs": { "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", + "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" ], "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.2.2" }, "pluggy": { "hashes": [ - "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", - "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.4.0" + "version": "==1.5.0" }, "py": { "hashes": [ @@ -482,45 +510,106 @@ }, "pydantic": { "hashes": [ - "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303", - "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe", - "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47", - "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494", - "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33", - "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86", - "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d", - "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c", - "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a", - "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565", - "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb", - "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62", - "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62", - "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0", - "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523", - "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d", - "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405", - "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f", - "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b", - "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718", - "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed", - "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb", - "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5", - "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc", - "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942", - "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe", - "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246", - "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350", - "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303", - "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09", - "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33", - "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8", - "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a", - "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1", - "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6", - "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d" + "sha256:c7a8a9fdf7d100afa49647eae340e2d23efa382466a8d177efcd1381e9be5598", + "sha256:f66a7073abd93214a20c5f7b32d56843137a7a2e70d02111f3be287035c45370" ], - "markers": "python_version >= '3.7'", - "version": "==1.10.12" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" + }, + "pydantic-core": { + "hashes": [ + "sha256:0102e49ac7d2df3379ef8d658d3bc59d3d769b0bdb17da189b75efa861fc07b4", + "sha256:0123655fedacf035ab10c23450163c2f65a4174f2bb034b188240a6cf06bb123", + "sha256:043ef8469f72609c4c3a5e06a07a1f713d53df4d53112c6d49207c0bd3c3bd9b", + "sha256:0448b81c3dfcde439551bb04a9f41d7627f676b12701865c8a2574bcea034437", + "sha256:05b366fb8fe3d8683b11ac35fa08947d7b92be78ec64e3277d03bd7f9b7cda79", + "sha256:07049ec9306ec64e955b2e7c40c8d77dd78ea89adb97a2013d0b6e055c5ee4c5", + "sha256:084414ffe9a85a52940b49631321d636dadf3576c30259607b75516d131fecd0", + "sha256:086c5db95157dc84c63ff9d96ebb8856f47ce113c86b61065a066f8efbe80acf", + "sha256:12625e69b1199e94b0ae1c9a95d000484ce9f0182f9965a26572f054b1537e44", + "sha256:16b25a4a120a2bb7dab51b81e3d9f3cde4f9a4456566c403ed29ac81bf49744f", + "sha256:19f1352fe4b248cae22a89268720fc74e83f008057a652894f08fa931e77dced", + "sha256:1a2ab4f410f4b886de53b6bddf5dd6f337915a29dd9f22f20f3099659536b2f6", + "sha256:1c7b81beaf7c7ebde978377dc53679c6cba0e946426fc7ade54251dfe24a7604", + "sha256:1cf842265a3a820ebc6388b963ead065f5ce8f2068ac4e1c713ef77a67b71f7c", + "sha256:1eb37f7d6a8001c0f86dc8ff2ee8d08291a536d76e49e78cda8587bb54d8b329", + "sha256:23af245b8f2f4ee9e2c99cb3f93d0e22fb5c16df3f2f643f5a8da5caff12a653", + "sha256:257d6a410a0d8aeb50b4283dea39bb79b14303e0fab0f2b9d617701331ed1515", + "sha256:276ae78153a94b664e700ac362587c73b84399bd1145e135287513442e7dfbc7", + "sha256:2b1a195efd347ede8bcf723e932300292eb13a9d2a3c1f84eb8f37cbbc905b7f", + "sha256:329a721253c7e4cbd7aad4a377745fbcc0607f9d72a3cc2102dd40519be75ed2", + "sha256:358331e21a897151e54d58e08d0219acf98ebb14c567267a87e971f3d2a3be59", + "sha256:3649bd3ae6a8ebea7dc381afb7f3c6db237fc7cebd05c8ac36ca8a4187b03b30", + "sha256:3713dc093d5048bfaedbba7a8dbc53e74c44a140d45ede020dc347dda18daf3f", + "sha256:3ef71ec876fcc4d3bbf2ae81961959e8d62f8d74a83d116668409c224012e3af", + "sha256:41ae8537ad371ec018e3c5da0eb3f3e40ee1011eb9be1da7f965357c4623c501", + "sha256:4a801c5e1e13272e0909c520708122496647d1279d252c9e6e07dac216accc41", + "sha256:4c83c64d05ffbbe12d4e8498ab72bdb05bcc1026340a4a597dc647a13c1605ec", + "sha256:4cebb9794f67266d65e7e4cbe5dcf063e29fc7b81c79dc9475bd476d9534150e", + "sha256:5668b3173bb0b2e65020b60d83f5910a7224027232c9f5dc05a71a1deac9f960", + "sha256:56e6a12ec8d7679f41b3750ffa426d22b44ef97be226a9bab00a03365f217b2b", + "sha256:582871902e1902b3c8e9b2c347f32a792a07094110c1bca6c2ea89b90150caac", + "sha256:5c8aa40f6ca803f95b1c1c5aeaee6237b9e879e4dfb46ad713229a63651a95fb", + "sha256:5d813fd871b3d5c3005157622ee102e8908ad6011ec915a18bd8fde673c4360e", + "sha256:5dd0ec5f514ed40e49bf961d49cf1bc2c72e9b50f29a163b2cc9030c6742aa73", + "sha256:5f3cf3721eaf8741cffaf092487f1ca80831202ce91672776b02b875580e174a", + "sha256:6294907eaaccf71c076abdd1c7954e272efa39bb043161b4b8aa1cd76a16ce43", + "sha256:64d094ea1aa97c6ded4748d40886076a931a8bf6f61b6e43e4a1041769c39dd2", + "sha256:6650a7bbe17a2717167e3e23c186849bae5cef35d38949549f1c116031b2b3aa", + "sha256:67b6655311b00581914aba481729971b88bb8bc7996206590700a3ac85e457b8", + "sha256:6b06c5d4e8701ac2ba99a2ef835e4e1b187d41095a9c619c5b185c9068ed2a49", + "sha256:6ce883906810b4c3bd90e0ada1f9e808d9ecf1c5f0b60c6b8831d6100bcc7dd6", + "sha256:6db09153d8438425e98cdc9a289c5fade04a5d2128faff8f227c459da21b9703", + "sha256:6f80fba4af0cb1d2344869d56430e304a51396b70d46b91a55ed4959993c0589", + "sha256:743e5811b0c377eb830150d675b0847a74a44d4ad5ab8845923d5b3a756d8100", + "sha256:753294d42fb072aa1775bfe1a2ba1012427376718fa4c72de52005a3d2a22178", + "sha256:7568f682c06f10f30ef643a1e8eec4afeecdafde5c4af1b574c6df079e96f96c", + "sha256:7706e15cdbf42f8fab1e6425247dfa98f4a6f8c63746c995d6a2017f78e619ae", + "sha256:785e7f517ebb9890813d31cb5d328fa5eda825bb205065cde760b3150e4de1f7", + "sha256:7a05c0240f6c711eb381ac392de987ee974fa9336071fb697768dfdb151345ce", + "sha256:7ce7eaf9a98680b4312b7cebcdd9352531c43db00fca586115845df388f3c465", + "sha256:7ce8e26b86a91e305858e018afc7a6e932f17428b1eaa60154bd1f7ee888b5f8", + "sha256:7d0324a35ab436c9d768753cbc3c47a865a2cbc0757066cb864747baa61f6ece", + "sha256:7e9b24cca4037a561422bf5dc52b38d390fb61f7bfff64053ce1b72f6938e6b2", + "sha256:810ca06cca91de9107718dc83d9ac4d2e86efd6c02cba49a190abcaf33fb0472", + "sha256:820f6ee5c06bc868335e3b6e42d7ef41f50dfb3ea32fbd523ab679d10d8741c0", + "sha256:82764c0bd697159fe9947ad59b6db6d7329e88505c8f98990eb07e84cc0a5d81", + "sha256:8ae65fdfb8a841556b52935dfd4c3f79132dc5253b12c0061b96415208f4d622", + "sha256:8d5b0ff3218858859910295df6953d7bafac3a48d5cd18f4e3ed9999efd2245f", + "sha256:95d6bf449a1ac81de562d65d180af5d8c19672793c81877a2eda8fde5d08f2fd", + "sha256:964c7aa318da542cdcc60d4a648377ffe1a2ef0eb1e996026c7f74507b720a78", + "sha256:96ef39add33ff58cd4c112cbac076726b96b98bb8f1e7f7595288dcfb2f10b57", + "sha256:a6612c2a844043e4d10a8324c54cdff0042c558eef30bd705770793d70b224aa", + "sha256:a8031074a397a5925d06b590121f8339d34a5a74cfe6970f8a1124eb8b83f4ac", + "sha256:aab9e522efff3993a9e98ab14263d4e20211e62da088298089a03056980a3e69", + "sha256:ae579143826c6f05a361d9546446c432a165ecf1c0b720bbfd81152645cb897d", + "sha256:ae90b9e50fe1bd115b24785e962b51130340408156d34d67b5f8f3fa6540938e", + "sha256:b18cf68255a476b927910c6873d9ed00da692bb293c5b10b282bd48a0afe3ae2", + "sha256:b7efb12e5071ad8d5b547487bdad489fbd4a5a35a0fc36a1941517a6ad7f23e0", + "sha256:c4d9f15ffe68bcd3898b0ad7233af01b15c57d91cd1667f8d868e0eacbfe3f87", + "sha256:c53100c8ee5a1e102766abde2158077d8c374bee0639201f11d3032e3555dfbc", + "sha256:c57e493a0faea1e4c38f860d6862ba6832723396c884fbf938ff5e9b224200e2", + "sha256:c8319e0bd6a7b45ad76166cc3d5d6a36c97d0c82a196f478c3ee5346566eebfd", + "sha256:caffda619099cfd4f63d48462f6aadbecee3ad9603b4b88b60cb821c1b258576", + "sha256:cc0c316fba3ce72ac3ab7902a888b9dc4979162d320823679da270c2d9ad0cad", + "sha256:cdd02a08205dc90238669f082747612cb3c82bd2c717adc60f9b9ecadb540f80", + "sha256:d50ac34835c6a4a0d456b5db559b82047403c4317b3bc73b3455fefdbdc54b0a", + "sha256:d6b9dd6aa03c812017411734e496c44fef29b43dba1e3dd1fa7361bbacfc1354", + "sha256:da3131ef2b940b99106f29dfbc30d9505643f766704e14c5d5e504e6a480c35e", + "sha256:da43cbe593e3c87d07108d0ebd73771dc414488f1f91ed2e204b0370b94b37ac", + "sha256:dd59638025160056687d598b054b64a79183f8065eae0d3f5ca523cde9943940", + "sha256:e1895e949f8849bc2757c0dbac28422a04be031204df46a56ab34bcf98507342", + "sha256:e1a79ad49f346aa1a2921f31e8dbbab4d64484823e813a002679eaa46cba39e1", + "sha256:e460475719721d59cd54a350c1f71c797c763212c836bf48585478c5514d2854", + "sha256:e64ffaf8f6e17ca15eb48344d86a7a741454526f3a3fa56bc493ad9d7ec63936", + "sha256:e6e3ccebdbd6e53474b0bb7ab8b88e83c0cfe91484b25e058e581348ee5a01a5", + "sha256:e758d271ed0286d146cf7c04c539a5169a888dd0b57026be621547e756af55bc", + "sha256:f087879f1ffde024dd2788a30d55acd67959dcf6c431e9d3682d1c491a0eb474", + "sha256:f477d26183e94eaafc60b983ab25af2a809a1b48ce4debb57b343f671b7a90b6", + "sha256:fc535cb898ef88333cf317777ecdfe0faac1c2a3187ef7eb061b6f7ecf7e6bae" + ], + "markers": "python_version >= '3.8'", + "version": "==2.23.2" }, "pydocstyle": { "hashes": [ @@ -549,12 +638,12 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2", - "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef" + "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", + "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.23.4" + "version": "==0.23.8" }, "pytest-cov": { "hashes": [ @@ -655,11 +744,11 @@ }, "sniffio": { "hashes": [ - "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", - "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" + "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", + "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" ], "markers": "python_version >= '3.7'", - "version": "==1.3.0" + "version": "==1.3.1" }, "snowballstemmer": { "hashes": [ @@ -747,37 +836,45 @@ }, "types-mock": { "hashes": [ - "sha256:13ca379d5710ccb3f18f69ade5b08881874cb83383d8fb49b1d4dac9d5c5d090", - "sha256:3d116955495935b0bcba14954b38d97e507cd43eca3e3700fc1b8e4f5c6bf2c7" + "sha256:5281a645d72e827d70043e3cc144fe33b1c003db084f789dc203aa90e812a5a4", + "sha256:d586a01d39ad919d3ddcd73de6cde73ca7f3c69707219f722d1b8d7733641ad7" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==5.1.0.20240106" + "version": "==5.1.0.20240425" }, "types-requests": { "hashes": [ - "sha256:03a28ce1d7cd54199148e043b2079cdded22d6795d19a2c2a6791a4b2b5e2eb5", - "sha256:9592a9a4cb92d6d75d9b491a41477272b710e021011a2a3061157e2fb1f1a5d1" + "sha256:4428df33c5503945c74b3f42e82b181e86ec7b724620419a2966e2de604ce1a1", + "sha256:6216cdac377c6b9a040ac1c0404f7284bd13199c0e1bb235f4324627e8898cf5" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.31.0.20240125" + "version": "==2.31.0.20240406" }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.12.2" + }, + "tzdata": { + "hashes": [ + "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", + "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.1" }, "urllib3": { "hashes": [ - "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20", - "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224" + "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", + "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" ], "markers": "python_version >= '3.8'", - "version": "==2.2.0" + "version": "==2.2.2" }, "uvicorn": { "hashes": [ diff --git a/server-utils/setup.py b/server-utils/setup.py index 41cab81de03..13e87a15c99 100755 --- a/server-utils/setup.py +++ b/server-utils/setup.py @@ -52,10 +52,10 @@ def get_version(): PACKAGES = find_packages(where=".", exclude=["tests.*", "tests"]) INSTALL_REQUIRES = [ "anyio==3.7.1", - "fastapi==0.99.1", + "fastapi==0.100.0", "python-dotenv==1.0.1", "python-multipart==0.0.6", - "pydantic==1.10.12", + "pydantic>2.0.0,<3", "typing-extensions>=4.0.0,<5", "uvicorn==0.27.0.post1", "wsproto==1.2.0", diff --git a/shared-data/command/schemas/11.json b/shared-data/command/schemas/11.json index 5bfd3569c0c..ac5dd17eeb3 100644 --- a/shared-data/command/schemas/11.json +++ b/shared-data/command/schemas/11.json @@ -1,6374 +1,5880 @@ { - "title": "CreateCommandUnion", - "description": "Model that validates a union of all CommandCreate models.", - "discriminator": { - "propertyName": "commandType", - "mapping": { - "airGapInPlace": "#/definitions/AirGapInPlaceCreate", - "aspirate": "#/definitions/AspirateCreate", - "aspirateInPlace": "#/definitions/AspirateInPlaceCreate", - "comment": "#/definitions/CommentCreate", - "configureForVolume": "#/definitions/ConfigureForVolumeCreate", - "configureNozzleLayout": "#/definitions/ConfigureNozzleLayoutCreate", - "custom": "#/definitions/CustomCreate", - "dispense": "#/definitions/DispenseCreate", - "dispenseInPlace": "#/definitions/DispenseInPlaceCreate", - "blowout": "#/definitions/BlowOutCreate", - "blowOutInPlace": "#/definitions/BlowOutInPlaceCreate", - "dropTip": "#/definitions/DropTipCreate", - "dropTipInPlace": "#/definitions/DropTipInPlaceCreate", - "home": "#/definitions/HomeCreate", - "retractAxis": "#/definitions/RetractAxisCreate", - "loadLabware": "#/definitions/LoadLabwareCreate", - "reloadLabware": "#/definitions/ReloadLabwareCreate", - "loadLiquid": "#/definitions/LoadLiquidCreate", - "loadLiquidClass": "#/definitions/LoadLiquidClassCreate", - "loadModule": "#/definitions/LoadModuleCreate", - "loadPipette": "#/definitions/LoadPipetteCreate", - "moveLabware": "#/definitions/MoveLabwareCreate", - "moveRelative": "#/definitions/MoveRelativeCreate", - "moveToCoordinates": "#/definitions/MoveToCoordinatesCreate", - "moveToWell": "#/definitions/MoveToWellCreate", - "moveToAddressableArea": "#/definitions/MoveToAddressableAreaCreate", - "moveToAddressableAreaForDropTip": "#/definitions/MoveToAddressableAreaForDropTipCreate", - "prepareToAspirate": "#/definitions/PrepareToAspirateCreate", - "waitForResume": "#/definitions/WaitForResumeCreate", - "pause": "#/definitions/WaitForResumeCreate", - "waitForDuration": "#/definitions/WaitForDurationCreate", - "pickUpTip": "#/definitions/PickUpTipCreate", - "savePosition": "#/definitions/SavePositionCreate", - "setRailLights": "#/definitions/SetRailLightsCreate", - "touchTip": "#/definitions/TouchTipCreate", - "setStatusBar": "#/definitions/SetStatusBarCreate", - "verifyTipPresence": "#/definitions/VerifyTipPresenceCreate", - "getTipPresence": "#/definitions/GetTipPresenceCreate", - "getNextTip": "#/definitions/GetNextTipCreate", - "liquidProbe": "#/definitions/LiquidProbeCreate", - "tryLiquidProbe": "#/definitions/TryLiquidProbeCreate", - "heaterShaker/waitForTemperature": "#/definitions/opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureCreate", - "heaterShaker/setTargetTemperature": "#/definitions/opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureCreate", - "heaterShaker/deactivateHeater": "#/definitions/DeactivateHeaterCreate", - "heaterShaker/setAndWaitForShakeSpeed": "#/definitions/SetAndWaitForShakeSpeedCreate", - "heaterShaker/deactivateShaker": "#/definitions/DeactivateShakerCreate", - "heaterShaker/openLabwareLatch": "#/definitions/OpenLabwareLatchCreate", - "heaterShaker/closeLabwareLatch": "#/definitions/CloseLabwareLatchCreate", - "magneticModule/disengage": "#/definitions/DisengageCreate", - "magneticModule/engage": "#/definitions/EngageCreate", - "temperatureModule/setTargetTemperature": "#/definitions/opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureCreate", - "temperatureModule/waitForTemperature": "#/definitions/opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureCreate", - "temperatureModule/deactivate": "#/definitions/DeactivateTemperatureCreate", - "thermocycler/setTargetBlockTemperature": "#/definitions/SetTargetBlockTemperatureCreate", - "thermocycler/waitForBlockTemperature": "#/definitions/WaitForBlockTemperatureCreate", - "thermocycler/setTargetLidTemperature": "#/definitions/SetTargetLidTemperatureCreate", - "thermocycler/waitForLidTemperature": "#/definitions/WaitForLidTemperatureCreate", - "thermocycler/deactivateBlock": "#/definitions/DeactivateBlockCreate", - "thermocycler/deactivateLid": "#/definitions/DeactivateLidCreate", - "thermocycler/openLid": "#/definitions/opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidCreate", - "thermocycler/closeLid": "#/definitions/opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidCreate", - "thermocycler/runProfile": "#/definitions/RunProfileCreate", - "thermocycler/runExtendedProfile": "#/definitions/RunExtendedProfileCreate", - "absorbanceReader/closeLid": "#/definitions/opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidCreate", - "absorbanceReader/openLid": "#/definitions/opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidCreate", - "absorbanceReader/initialize": "#/definitions/InitializeCreate", - "absorbanceReader/read": "#/definitions/ReadAbsorbanceCreate", - "calibration/calibrateGripper": "#/definitions/CalibrateGripperCreate", - "calibration/calibratePipette": "#/definitions/CalibratePipetteCreate", - "calibration/calibrateModule": "#/definitions/CalibrateModuleCreate", - "calibration/moveToMaintenancePosition": "#/definitions/MoveToMaintenancePositionCreate", - "unsafe/blowOutInPlace": "#/definitions/UnsafeBlowOutInPlaceCreate", - "unsafe/dropTipInPlace": "#/definitions/UnsafeDropTipInPlaceCreate", - "unsafe/updatePositionEstimators": "#/definitions/UpdatePositionEstimatorsCreate", - "unsafe/engageAxes": "#/definitions/UnsafeEngageAxesCreate", - "unsafe/ungripLabware": "#/definitions/UnsafeUngripLabwareCreate", - "unsafe/placeLabware": "#/definitions/UnsafePlaceLabwareCreate", - "robot/moveAxesRelative": "#/definitions/MoveAxesRelativeCreate", - "robot/moveAxesTo": "#/definitions/MoveAxesToCreate", - "robot/moveTo": "#/definitions/MoveToCreate", - "robot/openGripperJaw": "#/definitions/openGripperJawCreate", - "robot/closeGripperJaw": "#/definitions/closeGripperJawCreate" - } - }, - "oneOf": [ - { - "$ref": "#/definitions/AirGapInPlaceCreate" - }, - { - "$ref": "#/definitions/AspirateCreate" - }, - { - "$ref": "#/definitions/AspirateInPlaceCreate" - }, - { - "$ref": "#/definitions/CommentCreate" - }, - { - "$ref": "#/definitions/ConfigureForVolumeCreate" - }, - { - "$ref": "#/definitions/ConfigureNozzleLayoutCreate" - }, - { - "$ref": "#/definitions/CustomCreate" - }, - { - "$ref": "#/definitions/DispenseCreate" - }, - { - "$ref": "#/definitions/DispenseInPlaceCreate" - }, - { - "$ref": "#/definitions/BlowOutCreate" - }, - { - "$ref": "#/definitions/BlowOutInPlaceCreate" - }, - { - "$ref": "#/definitions/DropTipCreate" - }, - { - "$ref": "#/definitions/DropTipInPlaceCreate" - }, - { - "$ref": "#/definitions/HomeCreate" - }, - { - "$ref": "#/definitions/RetractAxisCreate" - }, - { - "$ref": "#/definitions/LoadLabwareCreate" - }, - { - "$ref": "#/definitions/ReloadLabwareCreate" - }, - { - "$ref": "#/definitions/LoadLiquidCreate" - }, - { - "$ref": "#/definitions/LoadLiquidClassCreate" - }, - { - "$ref": "#/definitions/LoadModuleCreate" - }, - { - "$ref": "#/definitions/LoadPipetteCreate" - }, - { - "$ref": "#/definitions/MoveLabwareCreate" - }, - { - "$ref": "#/definitions/MoveRelativeCreate" - }, - { - "$ref": "#/definitions/MoveToCoordinatesCreate" - }, - { - "$ref": "#/definitions/MoveToWellCreate" - }, - { - "$ref": "#/definitions/MoveToAddressableAreaCreate" - }, - { - "$ref": "#/definitions/MoveToAddressableAreaForDropTipCreate" - }, - { - "$ref": "#/definitions/PrepareToAspirateCreate" - }, - { - "$ref": "#/definitions/WaitForResumeCreate" - }, - { - "$ref": "#/definitions/WaitForDurationCreate" - }, - { - "$ref": "#/definitions/PickUpTipCreate" - }, - { - "$ref": "#/definitions/SavePositionCreate" - }, - { - "$ref": "#/definitions/SetRailLightsCreate" - }, - { - "$ref": "#/definitions/TouchTipCreate" - }, - { - "$ref": "#/definitions/SetStatusBarCreate" - }, - { - "$ref": "#/definitions/VerifyTipPresenceCreate" - }, - { - "$ref": "#/definitions/GetTipPresenceCreate" - }, - { - "$ref": "#/definitions/GetNextTipCreate" - }, - { - "$ref": "#/definitions/LiquidProbeCreate" - }, - { - "$ref": "#/definitions/TryLiquidProbeCreate" - }, - { - "$ref": "#/definitions/opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureCreate" - }, - { - "$ref": "#/definitions/opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureCreate" - }, - { - "$ref": "#/definitions/DeactivateHeaterCreate" - }, - { - "$ref": "#/definitions/SetAndWaitForShakeSpeedCreate" - }, - { - "$ref": "#/definitions/DeactivateShakerCreate" - }, - { - "$ref": "#/definitions/OpenLabwareLatchCreate" - }, - { - "$ref": "#/definitions/CloseLabwareLatchCreate" - }, - { - "$ref": "#/definitions/DisengageCreate" - }, - { - "$ref": "#/definitions/EngageCreate" - }, - { - "$ref": "#/definitions/opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureCreate" - }, - { - "$ref": "#/definitions/opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureCreate" - }, - { - "$ref": "#/definitions/DeactivateTemperatureCreate" - }, - { - "$ref": "#/definitions/SetTargetBlockTemperatureCreate" - }, - { - "$ref": "#/definitions/WaitForBlockTemperatureCreate" - }, - { - "$ref": "#/definitions/SetTargetLidTemperatureCreate" - }, - { - "$ref": "#/definitions/WaitForLidTemperatureCreate" - }, - { - "$ref": "#/definitions/DeactivateBlockCreate" - }, - { - "$ref": "#/definitions/DeactivateLidCreate" - }, - { - "$ref": "#/definitions/opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidCreate" - }, - { - "$ref": "#/definitions/opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidCreate" - }, - { - "$ref": "#/definitions/RunProfileCreate" - }, - { - "$ref": "#/definitions/RunExtendedProfileCreate" - }, - { - "$ref": "#/definitions/opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidCreate" - }, - { - "$ref": "#/definitions/opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidCreate" - }, - { - "$ref": "#/definitions/InitializeCreate" - }, - { - "$ref": "#/definitions/ReadAbsorbanceCreate" - }, - { - "$ref": "#/definitions/CalibrateGripperCreate" - }, - { - "$ref": "#/definitions/CalibratePipetteCreate" - }, - { - "$ref": "#/definitions/CalibrateModuleCreate" - }, - { - "$ref": "#/definitions/MoveToMaintenancePositionCreate" - }, - { - "$ref": "#/definitions/UnsafeBlowOutInPlaceCreate" - }, - { - "$ref": "#/definitions/UnsafeDropTipInPlaceCreate" - }, - { - "$ref": "#/definitions/UpdatePositionEstimatorsCreate" - }, - { - "$ref": "#/definitions/UnsafeEngageAxesCreate" - }, - { - "$ref": "#/definitions/UnsafeUngripLabwareCreate" - }, - { - "$ref": "#/definitions/UnsafePlaceLabwareCreate" - }, - { - "$ref": "#/definitions/MoveAxesRelativeCreate" - }, - { - "$ref": "#/definitions/MoveAxesToCreate" - }, - { - "$ref": "#/definitions/MoveToCreate" - }, - { - "$ref": "#/definitions/openGripperJawCreate" + "$defs": { + "AddressableAreaLocation": { + "description": "The location of something place in an addressable area. This is a superset of deck slots.", + "properties": { + "addressableAreaName": { + "description": "The name of the addressable area that you want to use. Valid values are the `id`s of `addressableArea`s in the [deck definition](https://github.com/Opentrons/opentrons/tree/edge/shared-data/deck).", + "title": "Addressableareaname", + "type": "string" + } + }, + "required": ["addressableAreaName"], + "title": "AddressableAreaLocation", + "type": "object" }, - { - "$ref": "#/definitions/closeGripperJawCreate" - } - ], - "definitions": { - "AirGapInPlaceParams": { - "title": "AirGapInPlaceParams", - "description": "Payload required to air gap in place.", - "type": "object", + "AddressableOffsetVector": { + "description": "Offset, in deck coordinates, from nominal to actual position of an addressable area.", "properties": { - "flowRate": { - "title": "Flowrate", - "description": "Speed in \u00b5L/s configured for the pipette", - "exclusiveMinimum": 0, + "x": { + "title": "X", "type": "number" }, - "volume": { - "title": "Volume", - "description": "The amount of liquid to aspirate, in \u00b5L. Must not be greater than the remaining available amount, which depends on the pipette (see `loadPipette`), its configuration (see `configureForVolume`), the tip (see `pickUpTip`), and the amount you've aspirated so far. There is some tolerance for floating point rounding errors.", - "minimum": 0, + "y": { + "title": "Y", "type": "number" }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", - "type": "string" + "z": { + "title": "Z", + "type": "number" } }, - "required": ["flowRate", "volume", "pipetteId"] - }, - "CommandIntent": { - "title": "CommandIntent", - "description": "Run intent for a given command.\n\nProps:\n PROTOCOL: the command is part of the protocol run itself.\n SETUP: the command is part of the setup phase of a run.", - "enum": ["protocol", "setup", "fixit"], - "type": "string" + "required": ["x", "y", "z"], + "title": "AddressableOffsetVector", + "type": "object" }, "AirGapInPlaceCreate": { - "title": "AirGapInPlaceCreate", "description": "AirGapInPlace command request model.", - "type": "object", "properties": { "commandType": { - "title": "Commandtype", + "const": "airGapInPlace", "default": "airGapInPlace", "enum": ["airGapInPlace"], + "title": "Commandtype", "type": "string" }, - "params": { - "$ref": "#/definitions/AirGapInPlaceParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/AirGapInPlaceParams" } }, - "required": ["params"] - }, - "WellOrigin": { - "title": "WellOrigin", - "description": "Origin of WellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well\n MENISCUS: the meniscus-center of the well", - "enum": ["top", "bottom", "center", "meniscus"], - "type": "string" + "required": ["params"], + "title": "AirGapInPlaceCreate", + "type": "object" }, - "WellOffset": { - "title": "WellOffset", - "description": "An offset vector in (x, y, z).", - "type": "object", + "AirGapInPlaceParams": { + "description": "Payload required to air gap in place.", "properties": { - "x": { - "title": "X", - "default": 0, + "flowRate": { + "description": "Speed in \u00b5L/s configured for the pipette", + "exclusiveMinimum": 0.0, + "title": "Flowrate", "type": "number" }, - "y": { - "title": "Y", - "default": 0, - "type": "number" + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", + "type": "string" }, - "z": { - "title": "Z", - "default": 0, + "volume": { + "description": "The amount of liquid to aspirate, in \u00b5L. Must not be greater than the remaining available amount, which depends on the pipette (see `loadPipette`), its configuration (see `configureForVolume`), the tip (see `pickUpTip`), and the amount you've aspirated so far. There is some tolerance for floating point rounding errors.", + "minimum": 0.0, + "title": "Volume", "type": "number" } - } + }, + "required": ["flowRate", "volume", "pipetteId"], + "title": "AirGapInPlaceParams", + "type": "object" }, - "LiquidHandlingWellLocation": { - "title": "LiquidHandlingWellLocation", - "description": "A relative location in reference to a well's location.\n\nTo be used with commands that handle liquids.", - "type": "object", + "AllNozzleLayoutConfiguration": { + "description": "All basemodel to represent a reset to the nozzle configuration. Sending no parameters resets to default.", "properties": { - "origin": { - "default": "top", - "allOf": [ - { - "$ref": "#/definitions/WellOrigin" - } - ] - }, - "offset": { - "$ref": "#/definitions/WellOffset" - }, - "volumeOffset": { - "title": "Volumeoffset", - "description": "A volume of liquid, in \u00b5L, to offset the z-axis offset. When \"operationVolume\" is specified, this volume is pulled from the command volume parameter.", - "default": 0.0, - "anyOf": [ - { - "type": "number" - }, - { - "enum": ["operationVolume"], - "type": "string" - } - ] - } - } - }, - "AspirateParams": { - "title": "AspirateParams", - "description": "Parameters required to aspirate from a specific well.", - "type": "object", - "properties": { - "labwareId": { - "title": "Labwareid", - "description": "Identifier of labware to use.", - "type": "string" - }, - "wellName": { - "title": "Wellname", - "description": "Name of well to use in labware.", - "type": "string" - }, - "wellLocation": { - "title": "Welllocation", - "description": "Relative well location at which to perform the operation", - "allOf": [ - { - "$ref": "#/definitions/LiquidHandlingWellLocation" - } - ] - }, - "flowRate": { - "title": "Flowrate", - "description": "Speed in \u00b5L/s configured for the pipette", - "exclusiveMinimum": 0, - "type": "number" - }, - "volume": { - "title": "Volume", - "description": "The amount of liquid to aspirate, in \u00b5L. Must not be greater than the remaining available amount, which depends on the pipette (see `loadPipette`), its configuration (see `configureForVolume`), the tip (see `pickUpTip`), and the amount you've aspirated so far. There is some tolerance for floating point rounding errors.", - "minimum": 0, - "type": "number" - }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", + "style": { + "const": "ALL", + "default": "ALL", + "enum": ["ALL"], + "title": "Style", "type": "string" } }, - "required": ["labwareId", "wellName", "flowRate", "volume", "pipetteId"] + "title": "AllNozzleLayoutConfiguration", + "type": "object" }, "AspirateCreate": { - "title": "AspirateCreate", "description": "Create aspirate command request model.", - "type": "object", "properties": { "commandType": { - "title": "Commandtype", + "const": "aspirate", "default": "aspirate", "enum": ["aspirate"], + "title": "Commandtype", "type": "string" }, - "params": { - "$ref": "#/definitions/AspirateParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" - } - }, - "required": ["params"] - }, - "AspirateInPlaceParams": { - "title": "AspirateInPlaceParams", - "description": "Payload required to aspirate in place.", - "type": "object", - "properties": { - "flowRate": { - "title": "Flowrate", - "description": "Speed in \u00b5L/s configured for the pipette", - "exclusiveMinimum": 0, - "type": "number" - }, - "volume": { - "title": "Volume", - "description": "The amount of liquid to aspirate, in \u00b5L. Must not be greater than the remaining available amount, which depends on the pipette (see `loadPipette`), its configuration (see `configureForVolume`), the tip (see `pickUpTip`), and the amount you've aspirated so far. There is some tolerance for floating point rounding errors.", - "minimum": 0, - "type": "number" }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", - "type": "string" + "params": { + "$ref": "#/$defs/AspirateParams" } }, - "required": ["flowRate", "volume", "pipetteId"] + "required": ["params"], + "title": "AspirateCreate", + "type": "object" }, "AspirateInPlaceCreate": { - "title": "AspirateInPlaceCreate", "description": "AspirateInPlace command request model.", - "type": "object", "properties": { "commandType": { - "title": "Commandtype", + "const": "aspirateInPlace", "default": "aspirateInPlace", "enum": ["aspirateInPlace"], + "title": "Commandtype", "type": "string" }, - "params": { - "$ref": "#/definitions/AspirateInPlaceParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" - } - }, - "required": ["params"] - }, - "CommentParams": { - "title": "CommentParams", - "description": "Payload required to annotate execution with a comment.", - "type": "object", - "properties": { - "message": { - "title": "Message", - "description": "A user-facing message", - "type": "string" - } - }, - "required": ["message"] - }, - "CommentCreate": { - "title": "CommentCreate", - "description": "Comment command request model.", - "type": "object", - "properties": { - "commandType": { - "title": "Commandtype", - "default": "comment", - "enum": ["comment"], + "title": "Key", "type": "string" }, "params": { - "$ref": "#/definitions/CommentParams" - }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] - }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" + "$ref": "#/$defs/AspirateInPlaceParams" } }, - "required": ["params"] + "required": ["params"], + "title": "AspirateInPlaceCreate", + "type": "object" }, - "ConfigureForVolumeParams": { - "title": "ConfigureForVolumeParams", - "description": "Parameters required to configure volume for a specific pipette.", - "type": "object", + "AspirateInPlaceParams": { + "description": "Payload required to aspirate in place.", "properties": { + "flowRate": { + "description": "Speed in \u00b5L/s configured for the pipette", + "exclusiveMinimum": 0.0, + "title": "Flowrate", + "type": "number" + }, "pipetteId": { - "title": "Pipetteid", "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" }, "volume": { + "description": "The amount of liquid to aspirate, in \u00b5L. Must not be greater than the remaining available amount, which depends on the pipette (see `loadPipette`), its configuration (see `configureForVolume`), the tip (see `pickUpTip`), and the amount you've aspirated so far. There is some tolerance for floating point rounding errors.", + "minimum": 0.0, "title": "Volume", - "description": "Amount of liquid in uL. Must be at least 0 and no greater than a pipette-specific maximum volume.", - "minimum": 0, "type": "number" - }, - "tipOverlapNotAfterVersion": { - "title": "Tipoverlapnotafterversion", - "description": "A version of tip overlap data to not exceed. The highest-versioned tip overlap data that does not exceed this version will be used. Versions are expressed as vN where N is an integer, counting up from v0. If None, the current highest version will be used.", - "type": "string" } }, - "required": ["pipetteId", "volume"] + "required": ["flowRate", "volume", "pipetteId"], + "title": "AspirateInPlaceParams", + "type": "object" }, - "ConfigureForVolumeCreate": { - "title": "ConfigureForVolumeCreate", - "description": "Configure for volume command creation request model.", - "type": "object", + "AspirateParams": { + "description": "Parameters required to aspirate from a specific well.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "configureForVolume", - "enum": ["configureForVolume"], + "flowRate": { + "description": "Speed in \u00b5L/s configured for the pipette", + "exclusiveMinimum": 0.0, + "title": "Flowrate", + "type": "number" + }, + "labwareId": { + "description": "Identifier of labware to use.", + "title": "Labwareid", "type": "string" }, - "params": { - "$ref": "#/definitions/ConfigureForVolumeParams" + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", + "type": "string" }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "volume": { + "description": "The amount of liquid to aspirate, in \u00b5L. Must not be greater than the remaining available amount, which depends on the pipette (see `loadPipette`), its configuration (see `configureForVolume`), the tip (see `pickUpTip`), and the amount you've aspirated so far. There is some tolerance for floating point rounding errors.", + "minimum": 0.0, + "title": "Volume", + "type": "number" }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" - } - }, - "required": ["params"] - }, - "AllNozzleLayoutConfiguration": { - "title": "AllNozzleLayoutConfiguration", - "description": "All basemodel to represent a reset to the nozzle configuration. Sending no parameters resets to default.", - "type": "object", - "properties": { - "style": { - "title": "Style", - "default": "ALL", - "enum": ["ALL"], - "type": "string" - } - } - }, - "SingleNozzleLayoutConfiguration": { - "title": "SingleNozzleLayoutConfiguration", - "description": "Minimum information required for a new nozzle configuration.", - "type": "object", - "properties": { - "style": { - "title": "Style", - "default": "SINGLE", - "enum": ["SINGLE"], - "type": "string" + "wellLocation": { + "$ref": "#/$defs/LiquidHandlingWellLocation", + "description": "Relative well location at which to perform the operation" }, - "primaryNozzle": { - "title": "Primarynozzle", - "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.", - "enum": ["A1", "H1", "A12", "H12"], + "wellName": { + "description": "Name of well to use in labware.", + "title": "Wellname", "type": "string" } }, - "required": ["primaryNozzle"] + "required": ["labwareId", "wellName", "flowRate", "volume", "pipetteId"], + "title": "AspirateParams", + "type": "object" }, - "RowNozzleLayoutConfiguration": { - "title": "RowNozzleLayoutConfiguration", - "description": "Minimum information required for a new nozzle configuration.", - "type": "object", + "AspirateProperties": { + "description": "Properties specific to the aspirate function.", "properties": { - "style": { - "title": "Style", - "default": "ROW", - "enum": ["ROW"], - "type": "string" + "correctionByVolume": { + "description": "Settings for volume correction keyed by by target aspiration volume, representing additional volume the plunger should move to accurately hit target volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Correctionbyvolume", + "type": "array" }, - "primaryNozzle": { - "title": "Primarynozzle", - "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.", - "enum": ["A1", "H1", "A12", "H12"], - "type": "string" + "delay": { + "$ref": "#/$defs/DelayProperties", + "description": "Delay settings after an aspirate" + }, + "flowRateByVolume": { + "description": "Settings for flow rate keyed by target aspiration volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Flowratebyvolume", + "type": "array" + }, + "mix": { + "$ref": "#/$defs/MixProperties", + "description": "Mixing settings for before an aspirate" + }, + "offset": { + "$ref": "#/$defs/Coordinate", + "description": "Relative offset for aspiration." + }, + "positionReference": { + "$ref": "#/$defs/PositionReference", + "description": "Position reference for aspiration." + }, + "preWet": { + "description": "Whether to perform a pre-wet action.", + "title": "Prewet", + "type": "boolean" + }, + "retract": { + "$ref": "#/$defs/RetractAspirate", + "description": "Pipette retract settings after an aspirate." + }, + "submerge": { + "$ref": "#/$defs/Submerge", + "description": "Submerge settings for aspirate." } }, - "required": ["primaryNozzle"] + "required": [ + "submerge", + "retract", + "positionReference", + "offset", + "flowRateByVolume", + "correctionByVolume", + "preWet", + "mix", + "delay" + ], + "title": "AspirateProperties", + "type": "object" }, - "ColumnNozzleLayoutConfiguration": { - "title": "ColumnNozzleLayoutConfiguration", - "description": "Information required for nozzle configurations of type ROW and COLUMN.", - "type": "object", + "BlowOutCreate": { + "description": "Create blow-out command request model.", "properties": { - "style": { - "title": "Style", - "default": "COLUMN", - "enum": ["COLUMN"], + "commandType": { + "const": "blowout", + "default": "blowout", + "enum": ["blowout"], + "title": "Commandtype", "type": "string" }, - "primaryNozzle": { - "title": "Primarynozzle", - "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.", - "enum": ["A1", "H1", "A12", "H12"], + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" + }, + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/BlowOutParams" } }, - "required": ["primaryNozzle"] + "required": ["params"], + "title": "BlowOutCreate", + "type": "object" }, - "QuadrantNozzleLayoutConfiguration": { - "title": "QuadrantNozzleLayoutConfiguration", - "description": "Information required for nozzle configurations of type QUADRANT.", - "type": "object", + "BlowOutInPlaceCreate": { + "description": "BlowOutInPlace command request model.", "properties": { - "style": { - "title": "Style", - "default": "QUADRANT", - "enum": ["QUADRANT"], + "commandType": { + "const": "blowOutInPlace", + "default": "blowOutInPlace", + "enum": ["blowOutInPlace"], + "title": "Commandtype", "type": "string" }, - "primaryNozzle": { - "title": "Primarynozzle", - "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.", - "enum": ["A1", "H1", "A12", "H12"], - "type": "string" + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" }, - "frontRightNozzle": { - "title": "Frontrightnozzle", - "description": "The front right nozzle in your configuration.", - "pattern": "[A-Z]\\d{1,2}", + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" }, - "backLeftNozzle": { - "title": "Backleftnozzle", - "description": "The back left nozzle in your configuration.", - "pattern": "[A-Z]\\d{1,2}", - "type": "string" + "params": { + "$ref": "#/$defs/BlowOutInPlaceParams" } }, - "required": ["primaryNozzle", "frontRightNozzle", "backLeftNozzle"] + "required": ["params"], + "title": "BlowOutInPlaceCreate", + "type": "object" }, - "ConfigureNozzleLayoutParams": { - "title": "ConfigureNozzleLayoutParams", - "description": "Parameters required to configure the nozzle layout for a specific pipette.", - "type": "object", + "BlowOutInPlaceParams": { + "description": "Payload required to blow-out in place.", "properties": { + "flowRate": { + "description": "Speed in \u00b5L/s configured for the pipette", + "exclusiveMinimum": 0.0, + "title": "Flowrate", + "type": "number" + }, "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", "title": "Pipetteid", + "type": "string" + } + }, + "required": ["flowRate", "pipetteId"], + "title": "BlowOutInPlaceParams", + "type": "object" + }, + "BlowOutParams": { + "description": "Payload required to blow-out a specific well.", + "properties": { + "flowRate": { + "description": "Speed in \u00b5L/s configured for the pipette", + "exclusiveMinimum": 0.0, + "title": "Flowrate", + "type": "number" + }, + "labwareId": { + "description": "Identifier of labware to use.", + "title": "Labwareid", + "type": "string" + }, + "pipetteId": { "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" }, - "configurationParams": { - "title": "Configurationparams", + "wellLocation": { + "$ref": "#/$defs/WellLocation", + "description": "Relative well location at which to perform the operation" + }, + "wellName": { + "description": "Name of well to use in labware.", + "title": "Wellname", + "type": "string" + } + }, + "required": ["labwareId", "wellName", "flowRate", "pipetteId"], + "title": "BlowOutParams", + "type": "object" + }, + "BlowoutLocation": { + "description": "Location for blowout during a transfer function.", + "enum": ["source", "destination", "trash"], + "title": "BlowoutLocation", + "type": "string" + }, + "BlowoutParams": { + "description": "Parameters for blowout.", + "properties": { + "flowRate": { "anyOf": [ { - "$ref": "#/definitions/AllNozzleLayoutConfiguration" - }, - { - "$ref": "#/definitions/SingleNozzleLayoutConfiguration" - }, - { - "$ref": "#/definitions/RowNozzleLayoutConfiguration" - }, - { - "$ref": "#/definitions/ColumnNozzleLayoutConfiguration" + "minimum": 0, + "type": "integer" }, { - "$ref": "#/definitions/QuadrantNozzleLayoutConfiguration" + "minimum": 0.0, + "type": "number" } - ] + ], + "description": "Flow rate for blow out, in microliters per second.", + "title": "Flowrate" + }, + "location": { + "$ref": "#/$defs/BlowoutLocation", + "description": "Location well or trash entity for blow out." } }, - "required": ["pipetteId", "configurationParams"] + "required": ["location", "flowRate"], + "title": "BlowoutParams", + "type": "object" }, - "ConfigureNozzleLayoutCreate": { - "title": "ConfigureNozzleLayoutCreate", - "description": "Configure nozzle layout creation request model.", - "type": "object", + "BlowoutProperties": { + "description": "Blowout properties.", + "properties": { + "enable": { + "description": "Whether blow-out is enabled.", + "title": "Enable", + "type": "boolean" + }, + "params": { + "$ref": "#/$defs/BlowoutParams", + "description": "Parameters for the blowout function.", + "title": "Params" + } + }, + "required": ["enable"], + "title": "BlowoutProperties", + "type": "object" + }, + "CalibrateGripperCreate": { + "description": "A request to create a `calibrateGripper` command.", "properties": { "commandType": { + "const": "calibration/calibrateGripper", + "default": "calibration/calibrateGripper", + "enum": ["calibration/calibrateGripper"], "title": "Commandtype", - "default": "configureNozzleLayout", - "enum": ["configureNozzleLayout"], "type": "string" }, - "params": { - "$ref": "#/definitions/ConfigureNozzleLayoutParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/CalibrateGripperParams" } }, - "required": ["params"] + "required": ["params"], + "title": "CalibrateGripperCreate", + "type": "object" }, - "CustomParams": { - "title": "CustomParams", - "description": "Payload used by a custom command.", - "type": "object", - "properties": {} + "CalibrateGripperParams": { + "description": "Parameters for a `calibrateGripper` command.", + "properties": { + "jaw": { + "$ref": "#/$defs/CalibrateGripperParamsJaw", + "description": "Which of the gripper's jaws to use to measure its offset. The robot will assume that a human operator has already attached the capacitive probe to the jaw and none is attached to the other jaw." + }, + "otherJawOffset": { + "$ref": "#/$defs/Vec3f", + "description": "If an offset for the other probe is already found, then specifying it here will enable the CalibrateGripper command to complete the calibration process by calculating the total offset and saving it to disk. If this param is not specified then the command will only find and return the offset for the specified probe.", + "title": "Otherjawoffset" + } + }, + "required": ["jaw"], + "title": "CalibrateGripperParams", + "type": "object" }, - "CustomCreate": { - "title": "CustomCreate", - "description": "A request to create a custom command.", - "type": "object", + "CalibrateGripperParamsJaw": { + "enum": ["front", "rear"], + "title": "CalibrateGripperParamsJaw", + "type": "string" + }, + "CalibrateModuleCreate": { + "description": "Create calibrate-module command request model.", "properties": { "commandType": { + "const": "calibration/calibrateModule", + "default": "calibration/calibrateModule", + "enum": ["calibration/calibrateModule"], "title": "Commandtype", - "default": "custom", - "enum": ["custom"], "type": "string" }, - "params": { - "$ref": "#/definitions/CustomParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/CalibrateModuleParams" } }, - "required": ["params"] + "required": ["params"], + "title": "CalibrateModuleCreate", + "type": "object" }, - "DispenseParams": { - "title": "DispenseParams", - "description": "Payload required to dispense to a specific well.", - "type": "object", + "CalibrateModuleParams": { + "description": "Payload required to calibrate-module.", "properties": { "labwareId": { + "description": "The unique id of module calibration adapter labware.", "title": "Labwareid", - "description": "Identifier of labware to use.", - "type": "string" - }, - "wellName": { - "title": "Wellname", - "description": "Name of well to use in labware.", "type": "string" }, - "wellLocation": { - "title": "Welllocation", - "description": "Relative well location at which to perform the operation", - "allOf": [ - { - "$ref": "#/definitions/LiquidHandlingWellLocation" - } - ] - }, - "flowRate": { - "title": "Flowrate", - "description": "Speed in \u00b5L/s configured for the pipette", - "exclusiveMinimum": 0, - "type": "number" - }, - "volume": { - "title": "Volume", - "description": "The amount of liquid to dispense, in \u00b5L. Must not be greater than the currently aspirated volume. There is some tolerance for floating point rounding errors.", - "minimum": 0, - "type": "number" - }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", + "moduleId": { + "description": "The unique id of module to calibrate.", + "title": "Moduleid", "type": "string" }, - "pushOut": { - "title": "Pushout", - "description": "push the plunger a small amount farther than necessary for accurate low-volume dispensing", - "type": "number" + "mount": { + "$ref": "#/$defs/MountType", + "description": "The instrument mount used to calibrate the module." } }, - "required": ["labwareId", "wellName", "flowRate", "volume", "pipetteId"] + "required": ["moduleId", "labwareId", "mount"], + "title": "CalibrateModuleParams", + "type": "object" }, - "DispenseCreate": { - "title": "DispenseCreate", - "description": "Create dispense command request model.", - "type": "object", + "CalibratePipetteCreate": { + "description": "Create calibrate-pipette command request model.", "properties": { "commandType": { + "const": "calibration/calibratePipette", + "default": "calibration/calibratePipette", + "enum": ["calibration/calibratePipette"], "title": "Commandtype", - "default": "dispense", - "enum": ["dispense"], "type": "string" }, - "params": { - "$ref": "#/definitions/DispenseParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/CalibratePipetteParams" } }, - "required": ["params"] + "required": ["params"], + "title": "CalibratePipetteCreate", + "type": "object" }, - "DispenseInPlaceParams": { - "title": "DispenseInPlaceParams", - "description": "Payload required to dispense in place.", - "type": "object", + "CalibratePipetteParams": { + "description": "Payload required to calibrate-pipette.", "properties": { - "flowRate": { - "title": "Flowrate", - "description": "Speed in \u00b5L/s configured for the pipette", - "exclusiveMinimum": 0, - "type": "number" - }, - "volume": { - "title": "Volume", - "description": "The amount of liquid to dispense, in \u00b5L. Must not be greater than the currently aspirated volume. There is some tolerance for floating point rounding errors.", - "minimum": 0, - "type": "number" - }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", - "type": "string" - }, - "pushOut": { - "title": "Pushout", - "description": "push the plunger a small amount farther than necessary for accurate low-volume dispensing", - "type": "number" + "mount": { + "$ref": "#/$defs/MountType", + "description": "Instrument mount to calibrate." } }, - "required": ["flowRate", "volume", "pipetteId"] + "required": ["mount"], + "title": "CalibratePipetteParams", + "type": "object" }, - "DispenseInPlaceCreate": { - "title": "DispenseInPlaceCreate", - "description": "DispenseInPlace command request model.", - "type": "object", + "CloseLabwareLatchCreate": { + "description": "A request to create a Heater-Shaker's close latch command.", "properties": { "commandType": { + "const": "heaterShaker/closeLabwareLatch", + "default": "heaterShaker/closeLabwareLatch", + "enum": ["heaterShaker/closeLabwareLatch"], "title": "Commandtype", - "default": "dispenseInPlace", - "enum": ["dispenseInPlace"], "type": "string" }, - "params": { - "$ref": "#/definitions/DispenseInPlaceParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/CloseLabwareLatchParams" } }, - "required": ["params"] + "required": ["params"], + "title": "CloseLabwareLatchCreate", + "type": "object" }, - "WellLocation": { - "title": "WellLocation", - "description": "A relative location in reference to a well's location.", - "type": "object", + "CloseLabwareLatchParams": { + "description": "Input parameters to close a Heater-Shaker Module's labware latch.", "properties": { - "origin": { - "default": "top", - "allOf": [ - { - "$ref": "#/definitions/WellOrigin" - } - ] - }, - "offset": { - "$ref": "#/definitions/WellOffset" - }, - "volumeOffset": { - "title": "Volumeoffset", - "description": "A volume of liquid, in \u00b5L, to offset the z-axis offset.", - "default": 0.0, - "type": "number" + "moduleId": { + "description": "Unique ID of the Heater-Shaker Module.", + "title": "Moduleid", + "type": "string" } - } + }, + "required": ["moduleId"], + "title": "CloseLabwareLatchParams", + "type": "object" }, - "BlowOutParams": { - "title": "BlowOutParams", - "description": "Payload required to blow-out a specific well.", - "type": "object", + "ColumnNozzleLayoutConfiguration": { + "description": "Information required for nozzle configurations of type ROW and COLUMN.", "properties": { - "labwareId": { - "title": "Labwareid", - "description": "Identifier of labware to use.", - "type": "string" - }, - "wellName": { - "title": "Wellname", - "description": "Name of well to use in labware.", + "primaryNozzle": { + "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.", + "enum": ["A1", "H1", "A12", "H12"], + "title": "Primarynozzle", "type": "string" }, - "wellLocation": { - "title": "Welllocation", - "description": "Relative well location at which to perform the operation", - "allOf": [ - { - "$ref": "#/definitions/WellLocation" - } - ] - }, - "flowRate": { - "title": "Flowrate", - "description": "Speed in \u00b5L/s configured for the pipette", - "exclusiveMinimum": 0, - "type": "number" - }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", + "style": { + "const": "COLUMN", + "default": "COLUMN", + "enum": ["COLUMN"], + "title": "Style", "type": "string" } }, - "required": ["labwareId", "wellName", "flowRate", "pipetteId"] + "required": ["primaryNozzle"], + "title": "ColumnNozzleLayoutConfiguration", + "type": "object" }, - "BlowOutCreate": { - "title": "BlowOutCreate", - "description": "Create blow-out command request model.", - "type": "object", + "CommandIntent": { + "description": "Run intent for a given command.\n\nProps:\n PROTOCOL: the command is part of the protocol run itself.\n SETUP: the command is part of the setup phase of a run.", + "enum": ["protocol", "setup", "fixit"], + "title": "CommandIntent", + "type": "string" + }, + "CommentCreate": { + "description": "Comment command request model.", "properties": { "commandType": { + "const": "comment", + "default": "comment", + "enum": ["comment"], "title": "Commandtype", - "default": "blowout", - "enum": ["blowout"], "type": "string" }, - "params": { - "$ref": "#/definitions/BlowOutParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/CommentParams" } }, - "required": ["params"] + "required": ["params"], + "title": "CommentCreate", + "type": "object" }, - "BlowOutInPlaceParams": { - "title": "BlowOutInPlaceParams", - "description": "Payload required to blow-out in place.", - "type": "object", + "CommentParams": { + "description": "Payload required to annotate execution with a comment.", "properties": { - "flowRate": { - "title": "Flowrate", - "description": "Speed in \u00b5L/s configured for the pipette", - "exclusiveMinimum": 0, - "type": "number" - }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", + "message": { + "description": "A user-facing message", + "title": "Message", "type": "string" } }, - "required": ["flowRate", "pipetteId"] + "required": ["message"], + "title": "CommentParams", + "type": "object" }, - "BlowOutInPlaceCreate": { - "title": "BlowOutInPlaceCreate", - "description": "BlowOutInPlace command request model.", - "type": "object", + "ConfigureForVolumeCreate": { + "description": "Configure for volume command creation request model.", "properties": { "commandType": { + "const": "configureForVolume", + "default": "configureForVolume", + "enum": ["configureForVolume"], "title": "Commandtype", - "default": "blowOutInPlace", - "enum": ["blowOutInPlace"], "type": "string" }, - "params": { - "$ref": "#/definitions/BlowOutInPlaceParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" - } - }, - "required": ["params"] - }, - "DropTipWellOrigin": { - "title": "DropTipWellOrigin", - "description": "The origin of a DropTipWellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well\n DEFAULT: the default drop-tip location of the well,\n based on pipette configuration and length of the tip.", - "enum": ["top", "bottom", "center", "default"], - "type": "string" - }, - "DropTipWellLocation": { - "title": "DropTipWellLocation", - "description": "Like WellLocation, but for dropping tips.\n\nUnlike a typical WellLocation, the location for a drop tip\ndefaults to location based on the tip length rather than the well's top.", - "type": "object", - "properties": { - "origin": { - "default": "default", - "allOf": [ - { - "$ref": "#/definitions/DropTipWellOrigin" - } - ] }, - "offset": { - "$ref": "#/definitions/WellOffset" + "params": { + "$ref": "#/$defs/ConfigureForVolumeParams" } - } + }, + "required": ["params"], + "title": "ConfigureForVolumeCreate", + "type": "object" }, - "DropTipParams": { - "title": "DropTipParams", - "description": "Payload required to drop a tip in a specific well.", - "type": "object", + "ConfigureForVolumeParams": { + "description": "Parameters required to configure volume for a specific pipette.", "properties": { "pipetteId": { - "title": "Pipetteid", "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" }, - "labwareId": { - "title": "Labwareid", - "description": "Identifier of labware to use.", - "type": "string" - }, - "wellName": { - "title": "Wellname", - "description": "Name of well to use in labware.", + "tipOverlapNotAfterVersion": { + "description": "A version of tip overlap data to not exceed. The highest-versioned tip overlap data that does not exceed this version will be used. Versions are expressed as vN where N is an integer, counting up from v0. If None, the current highest version will be used.", + "title": "Tipoverlapnotafterversion", "type": "string" }, - "wellLocation": { - "title": "Welllocation", - "description": "Relative well location at which to drop the tip.", - "allOf": [ - { - "$ref": "#/definitions/DropTipWellLocation" - } - ] - }, - "homeAfter": { - "title": "Homeafter", - "description": "Whether to home this pipette's plunger after dropping the tip. You should normally leave this unspecified to let the robot choose a safe default depending on its hardware.", - "type": "boolean" - }, - "alternateDropLocation": { - "title": "Alternatedroplocation", - "description": "Whether to alternate location where tip is dropped within the labware. If True, this command will ignore the wellLocation provided and alternate between dropping tips at two predetermined locations inside the specified labware well. If False, the tip will be dropped at the top center of the well.", - "default": false, - "type": "boolean" + "volume": { + "description": "Amount of liquid in uL. Must be at least 0 and no greater than a pipette-specific maximum volume.", + "minimum": 0.0, + "title": "Volume", + "type": "number" } }, - "required": ["pipetteId", "labwareId", "wellName"] + "required": ["pipetteId", "volume"], + "title": "ConfigureForVolumeParams", + "type": "object" }, - "DropTipCreate": { - "title": "DropTipCreate", - "description": "Drop tip command creation request model.", - "type": "object", + "ConfigureNozzleLayoutCreate": { + "description": "Configure nozzle layout creation request model.", "properties": { "commandType": { + "const": "configureNozzleLayout", + "default": "configureNozzleLayout", + "enum": ["configureNozzleLayout"], "title": "Commandtype", - "default": "dropTip", - "enum": ["dropTip"], "type": "string" }, - "params": { - "$ref": "#/definitions/DropTipParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/ConfigureNozzleLayoutParams" } }, - "required": ["params"] + "required": ["params"], + "title": "ConfigureNozzleLayoutCreate", + "type": "object" }, - "DropTipInPlaceParams": { - "title": "DropTipInPlaceParams", - "description": "Payload required to drop a tip in place.", - "type": "object", + "ConfigureNozzleLayoutParams": { + "description": "Parameters required to configure the nozzle layout for a specific pipette.", "properties": { + "configurationParams": { + "anyOf": [ + { + "$ref": "#/$defs/AllNozzleLayoutConfiguration" + }, + { + "$ref": "#/$defs/SingleNozzleLayoutConfiguration" + }, + { + "$ref": "#/$defs/RowNozzleLayoutConfiguration" + }, + { + "$ref": "#/$defs/ColumnNozzleLayoutConfiguration" + }, + { + "$ref": "#/$defs/QuadrantNozzleLayoutConfiguration" + } + ], + "title": "Configurationparams" + }, "pipetteId": { - "title": "Pipetteid", "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" + } + }, + "required": ["pipetteId", "configurationParams"], + "title": "ConfigureNozzleLayoutParams", + "type": "object" + }, + "Coordinate": { + "description": "Three-dimensional coordinates.", + "properties": { + "x": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + } + ], + "title": "X" }, - "homeAfter": { - "title": "Homeafter", - "description": "Whether to home this pipette's plunger after dropping the tip. You should normally leave this unspecified to let the robot choose a safe default depending on its hardware.", - "type": "boolean" + "y": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + } + ], + "title": "Y" + }, + "z": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + } + ], + "title": "Z" } }, - "required": ["pipetteId"] + "required": ["x", "y", "z"], + "title": "Coordinate", + "type": "object" }, - "DropTipInPlaceCreate": { - "title": "DropTipInPlaceCreate", - "description": "Drop tip in place command creation request model.", - "type": "object", + "CustomCreate": { + "description": "A request to create a custom command.", "properties": { "commandType": { + "const": "custom", + "default": "custom", + "enum": ["custom"], "title": "Commandtype", - "default": "dropTipInPlace", - "enum": ["dropTipInPlace"], "type": "string" }, - "params": { - "$ref": "#/definitions/DropTipInPlaceParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/CustomParams" } }, - "required": ["params"] - }, - "MotorAxis": { - "title": "MotorAxis", - "description": "Motor axis on which to issue a home command.", - "enum": [ - "x", - "y", - "leftZ", - "rightZ", - "leftPlunger", - "rightPlunger", - "extensionZ", - "extensionJaw", - "axis96ChannelCam" - ], - "type": "string" - }, - "MountType": { - "title": "MountType", - "description": "An enumeration.", - "enum": ["left", "right", "extension"], - "type": "string" + "required": ["params"], + "title": "CustomCreate", + "type": "object" }, - "HomeParams": { - "title": "HomeParams", - "description": "Payload required for a Home command.", - "type": "object", - "properties": { - "axes": { - "description": "Axes to return to their home positions. If omitted, will home all motors. Extra axes may be implicitly homed to ensure accurate homing of the explicitly specified axes.", - "type": "array", - "items": { - "$ref": "#/definitions/MotorAxis" - } - }, - "skipIfMountPositionOk": { - "description": "If this parameter is provided, the gantry will only be homed if the specified mount has an invalid position. If omitted, the homing action will be executed unconditionally.", - "allOf": [ - { - "$ref": "#/definitions/MountType" - } - ] - } - } + "CustomParams": { + "additionalProperties": true, + "description": "Payload used by a custom command.", + "properties": {}, + "title": "CustomParams", + "type": "object" }, - "HomeCreate": { - "title": "HomeCreate", - "description": "Data to create a Home command.", - "type": "object", + "DeactivateBlockCreate": { + "description": "A request to create a Thermocycler's deactivate block command.", "properties": { "commandType": { + "const": "thermocycler/deactivateBlock", + "default": "thermocycler/deactivateBlock", + "enum": ["thermocycler/deactivateBlock"], "title": "Commandtype", - "default": "home", - "enum": ["home"], "type": "string" }, - "params": { - "$ref": "#/definitions/HomeParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/DeactivateBlockParams" } }, - "required": ["params"] + "required": ["params"], + "title": "DeactivateBlockCreate", + "type": "object" }, - "RetractAxisParams": { - "title": "RetractAxisParams", - "description": "Payload required for a Retract Axis command.", - "type": "object", + "DeactivateBlockParams": { + "description": "Input parameters to unset a Thermocycler's target block temperature.", "properties": { - "axis": { - "description": "Axis to retract to its home position as quickly as safely possible. The difference between retracting an axis and homing an axis using the home command is that a home will always probe the limit switch and will work as the first motion command a robot will need to execute; On the other hand, retraction will rely on this previously determined home position to move to it as fast as safely possible. So on the Flex, it will move (fast) the axis to the previously recorded home position and on the OT2, it will move (fast) the axis a safe distance from the previously recorded home position, and then slowly approach the limit switch.", - "allOf": [ - { - "$ref": "#/definitions/MotorAxis" - } - ] + "moduleId": { + "description": "Unique ID of the Thermocycler.", + "title": "Moduleid", + "type": "string" } }, - "required": ["axis"] + "required": ["moduleId"], + "title": "DeactivateBlockParams", + "type": "object" }, - "RetractAxisCreate": { - "title": "RetractAxisCreate", - "description": "Data to create a Retract Axis command.", - "type": "object", + "DeactivateHeaterCreate": { + "description": "A request to create a Heater-Shaker's deactivate heater command.", "properties": { "commandType": { + "const": "heaterShaker/deactivateHeater", + "default": "heaterShaker/deactivateHeater", + "enum": ["heaterShaker/deactivateHeater"], "title": "Commandtype", - "default": "retractAxis", - "enum": ["retractAxis"], "type": "string" }, - "params": { - "$ref": "#/definitions/RetractAxisParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/DeactivateHeaterParams" } }, - "required": ["params"] - }, - "DeckSlotName": { - "title": "DeckSlotName", - "description": "Deck slot identifiers.", - "enum": [ - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "A1", - "A2", - "A3", - "B1", - "B2", - "B3", - "C1", - "C2", - "C3", - "D1", - "D2", - "D3" - ] - }, - "DeckSlotLocation": { - "title": "DeckSlotLocation", - "description": "The location of something placed in a single deck slot.", - "type": "object", - "properties": { - "slotName": { - "description": "A slot on the robot's deck.\n\nThe plain numbers like `\"5\"` are for the OT-2, and the coordinates like `\"C2\"` are for the Flex.\n\nWhen you provide one of these values, you can use either style. It will automatically be converted to match the robot.\n\nWhen one of these values is returned, it will always match the robot.", - "allOf": [ - { - "$ref": "#/definitions/DeckSlotName" - } - ] - } - }, - "required": ["slotName"] + "required": ["params"], + "title": "DeactivateHeaterCreate", + "type": "object" }, - "ModuleLocation": { - "title": "ModuleLocation", - "description": "The location of something placed atop a hardware module.", - "type": "object", + "DeactivateHeaterParams": { + "description": "Input parameters to unset a Heater-Shaker's target temperature.", "properties": { "moduleId": { + "description": "Unique ID of the Heater-Shaker Module.", "title": "Moduleid", - "description": "The ID of a loaded module from a prior `loadModule` command.", "type": "string" } }, - "required": ["moduleId"] + "required": ["moduleId"], + "title": "DeactivateHeaterParams", + "type": "object" }, - "OnLabwareLocation": { - "title": "OnLabwareLocation", - "description": "The location of something placed atop another labware.", - "type": "object", + "DeactivateLidCreate": { + "description": "A request to create a Thermocycler's deactivate lid command.", "properties": { - "labwareId": { - "title": "Labwareid", - "description": "The ID of a loaded Labware from a prior `loadLabware` command.", + "commandType": { + "const": "thermocycler/deactivateLid", + "default": "thermocycler/deactivateLid", + "enum": ["thermocycler/deactivateLid"], + "title": "Commandtype", "type": "string" - } - }, - "required": ["labwareId"] - }, - "AddressableAreaLocation": { - "title": "AddressableAreaLocation", - "description": "The location of something place in an addressable area. This is a superset of deck slots.", - "type": "object", - "properties": { - "addressableAreaName": { - "title": "Addressableareaname", - "description": "The name of the addressable area that you want to use. Valid values are the `id`s of `addressableArea`s in the [deck definition](https://github.com/Opentrons/opentrons/tree/edge/shared-data/deck).", - "type": "string" - } - }, - "required": ["addressableAreaName"] - }, - "LoadLabwareParams": { - "title": "LoadLabwareParams", - "description": "Payload required to load a labware into a slot.", - "type": "object", - "properties": { - "location": { - "title": "Location", - "description": "Location the labware should be loaded into.", - "anyOf": [ - { - "$ref": "#/definitions/DeckSlotLocation" - }, - { - "$ref": "#/definitions/ModuleLocation" - }, - { - "$ref": "#/definitions/OnLabwareLocation" - }, - { - "enum": ["offDeck"], - "type": "string" - }, - { - "$ref": "#/definitions/AddressableAreaLocation" - } - ] - }, - "loadName": { - "title": "Loadname", - "description": "Name used to reference a labware definition.", - "type": "string" - }, - "namespace": { - "title": "Namespace", - "description": "The namespace the labware definition belongs to.", - "type": "string" - }, - "version": { - "title": "Version", - "description": "The labware definition version.", - "type": "integer" - }, - "labwareId": { - "title": "Labwareid", - "description": "An optional ID to assign to this labware. If None, an ID will be generated.", - "type": "string" - }, - "displayName": { - "title": "Displayname", - "description": "An optional user-specified display name or label for this labware.", - "type": "string" - } - }, - "required": ["location", "loadName", "namespace", "version"] - }, - "LoadLabwareCreate": { - "title": "LoadLabwareCreate", - "description": "Load labware command creation request.", - "type": "object", - "properties": { - "commandType": { - "title": "Commandtype", - "default": "loadLabware", - "enum": ["loadLabware"], - "type": "string" - }, - "params": { - "$ref": "#/definitions/LoadLabwareParams" }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/DeactivateLidParams" } }, - "required": ["params"] + "required": ["params"], + "title": "DeactivateLidCreate", + "type": "object" }, - "ReloadLabwareParams": { - "title": "ReloadLabwareParams", - "description": "Payload required to load a labware into a slot.", - "type": "object", + "DeactivateLidParams": { + "description": "Input parameters to unset a Thermocycler's target lid temperature.", "properties": { - "labwareId": { - "title": "Labwareid", - "description": "The already-loaded labware instance to update.", + "moduleId": { + "description": "Unique ID of the Thermocycler.", + "title": "Moduleid", "type": "string" } }, - "required": ["labwareId"] + "required": ["moduleId"], + "title": "DeactivateLidParams", + "type": "object" }, - "ReloadLabwareCreate": { - "title": "ReloadLabwareCreate", - "description": "Reload labware command creation request.", - "type": "object", + "DeactivateShakerCreate": { + "description": "A request to create a Heater-Shaker's deactivate shaker command.", "properties": { "commandType": { + "const": "heaterShaker/deactivateShaker", + "default": "heaterShaker/deactivateShaker", + "enum": ["heaterShaker/deactivateShaker"], "title": "Commandtype", - "default": "reloadLabware", - "enum": ["reloadLabware"], "type": "string" }, - "params": { - "$ref": "#/definitions/ReloadLabwareParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/DeactivateShakerParams" } }, - "required": ["params"] + "required": ["params"], + "title": "DeactivateShakerCreate", + "type": "object" }, - "LoadLiquidParams": { - "title": "LoadLiquidParams", - "description": "Payload required to load a liquid into a well.", - "type": "object", + "DeactivateShakerParams": { + "description": "Input parameters to deactivate shaker for a Heater-Shaker Module.", "properties": { - "liquidId": { - "title": "Liquidid", - "description": "Unique identifier of the liquid to load. If this is the sentinel value EMPTY, all values of volumeByWell must be 0.", - "anyOf": [ - { - "type": "string" - }, - { - "enum": ["EMPTY"], - "type": "string" - } - ] - }, - "labwareId": { - "title": "Labwareid", - "description": "Unique identifier of labware to load liquid into.", + "moduleId": { + "description": "Unique ID of the Heater-Shaker Module.", + "title": "Moduleid", "type": "string" - }, - "volumeByWell": { - "title": "Volumebywell", - "description": "Volume of liquid, in \u00b5L, loaded into each well by name, in this labware. If the liquid id is the sentinel value EMPTY, all volumes must be 0.", - "type": "object", - "additionalProperties": { - "type": "number" - } } }, - "required": ["liquidId", "labwareId", "volumeByWell"] + "required": ["moduleId"], + "title": "DeactivateShakerParams", + "type": "object" }, - "LoadLiquidCreate": { - "title": "LoadLiquidCreate", - "description": "Load liquid command creation request.", - "type": "object", + "DeactivateTemperatureCreate": { + "description": "A request to deactivate a Temperature Module.", "properties": { "commandType": { + "const": "temperatureModule/deactivate", + "default": "temperatureModule/deactivate", + "enum": ["temperatureModule/deactivate"], "title": "Commandtype", - "default": "loadLiquid", - "enum": ["loadLiquid"], "type": "string" }, - "params": { - "$ref": "#/definitions/LoadLiquidParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/DeactivateTemperatureParams" } }, - "required": ["params"] + "required": ["params"], + "title": "DeactivateTemperatureCreate", + "type": "object" }, - "PositionReference": { - "title": "PositionReference", - "description": "Positional reference for liquid handling operations.", - "enum": ["well-bottom", "well-top", "well-center", "liquid-meniscus"] + "DeactivateTemperatureParams": { + "description": "Input parameters to deactivate a Temperature Module.", + "properties": { + "moduleId": { + "description": "Unique ID of the Temperature Module.", + "title": "Moduleid", + "type": "string" + } + }, + "required": ["moduleId"], + "title": "DeactivateTemperatureParams", + "type": "object" }, - "Coordinate": { - "title": "Coordinate", - "description": "Three-dimensional coordinates.", - "type": "object", + "DeckPoint": { + "description": "Coordinates of a point in deck space.", "properties": { "x": { "title": "X", - "anyOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ] + "type": "number" }, "y": { "title": "Y", - "anyOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ] + "type": "number" }, "z": { "title": "Z", - "anyOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ] + "type": "number" + } + }, + "required": ["x", "y", "z"], + "title": "DeckPoint", + "type": "object" + }, + "DeckSlotLocation": { + "description": "The location of something placed in a single deck slot.", + "properties": { + "slotName": { + "$ref": "#/$defs/DeckSlotName", + "description": "A slot on the robot's deck.\n\nThe plain numbers like `\"5\"` are for the OT-2, and the coordinates like `\"C2\"` are for the Flex.\n\nWhen you provide one of these values, you can use either style. It will automatically be converted to match the robot.\n\nWhen one of these values is returned, it will always match the robot." } }, - "required": ["x", "y", "z"] + "required": ["slotName"], + "title": "DeckSlotLocation", + "type": "object" + }, + "DeckSlotName": { + "description": "Deck slot identifiers.", + "enum": [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "A1", + "A2", + "A3", + "B1", + "B2", + "B3", + "C1", + "C2", + "C3", + "D1", + "D2", + "D3" + ], + "title": "DeckSlotName", + "type": "string" }, "DelayParams": { - "title": "DelayParams", "description": "Parameters for delay.", - "type": "object", "properties": { "duration": { - "title": "Duration", - "description": "Duration of delay, in seconds.", "anyOf": [ { - "type": "integer", - "minimum": 0 + "minimum": 0, + "type": "integer" }, { - "type": "number", - "minimum": 0.0 + "minimum": 0.0, + "type": "number" } - ] + ], + "description": "Duration of delay, in seconds.", + "title": "Duration" } }, - "required": ["duration"] + "required": ["duration"], + "title": "DelayParams", + "type": "object" }, "DelayProperties": { - "title": "DelayProperties", "description": "Shared properties for delay..", - "type": "object", "properties": { "enable": { - "title": "Enable", "description": "Whether delay is enabled.", + "title": "Enable", "type": "boolean" }, "params": { - "title": "Params", + "$ref": "#/$defs/DelayParams", "description": "Parameters for the delay function.", - "allOf": [ - { - "$ref": "#/definitions/DelayParams" - } - ] + "title": "Params" } }, - "required": ["enable"] + "required": ["enable"], + "title": "DelayProperties", + "type": "object" }, - "Submerge": { - "title": "Submerge", - "description": "Shared properties for the submerge function before aspiration or dispense.", - "type": "object", + "DisengageCreate": { + "description": "A request to create a Magnetic Module disengage command.", "properties": { - "positionReference": { - "description": "Position reference for submerge.", - "allOf": [ - { - "$ref": "#/definitions/PositionReference" - } - ] + "commandType": { + "const": "magneticModule/disengage", + "default": "magneticModule/disengage", + "enum": ["magneticModule/disengage"], + "title": "Commandtype", + "type": "string" }, - "offset": { - "title": "Offset", - "description": "Relative offset for submerge.", - "allOf": [ - { - "$ref": "#/definitions/Coordinate" - } - ] + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" }, - "speed": { - "title": "Speed", - "description": "Speed of submerging, in millimeters per second.", - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", + "type": "string" }, - "delay": { - "title": "Delay", - "description": "Delay settings for submerge.", - "allOf": [ - { - "$ref": "#/definitions/DelayProperties" - } - ] + "params": { + "$ref": "#/$defs/DisengageParams" } }, - "required": ["positionReference", "offset", "speed", "delay"] + "required": ["params"], + "title": "DisengageCreate", + "type": "object" }, - "LiquidClassTouchTipParams": { - "title": "LiquidClassTouchTipParams", - "description": "Parameters for touch-tip.", - "type": "object", + "DisengageParams": { + "description": "Input data to disengage a Magnetic Module's magnets.", "properties": { - "zOffset": { - "title": "Zoffset", - "description": "Offset from the top of the well for touch-tip, in millimeters.", - "anyOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ] - }, - "mmToEdge": { - "title": "Mmtoedge", - "description": "Offset away from the the well edge, in millimeters.", - "anyOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ] - }, - "speed": { - "title": "Speed", - "description": "Touch-tip speed, in millimeters per second.", - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] + "moduleId": { + "description": "The ID of the Magnetic Module whose magnets you want to disengage, from a prior `loadModule` command.", + "title": "Moduleid", + "type": "string" } }, - "required": ["zOffset", "mmToEdge", "speed"] + "required": ["moduleId"], + "title": "DisengageParams", + "type": "object" }, - "TouchTipProperties": { - "title": "TouchTipProperties", - "description": "Shared properties for the touch-tip function.", - "type": "object", + "DispenseCreate": { + "description": "Create dispense command request model.", "properties": { - "enable": { - "title": "Enable", - "description": "Whether touch-tip is enabled.", - "type": "boolean" + "commandType": { + "const": "dispense", + "default": "dispense", + "enum": ["dispense"], + "title": "Commandtype", + "type": "string" + }, + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" + }, + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", + "type": "string" }, "params": { - "title": "Params", - "description": "Parameters for the touch-tip function.", - "allOf": [ - { - "$ref": "#/definitions/LiquidClassTouchTipParams" - } - ] + "$ref": "#/$defs/DispenseParams" } }, - "required": ["enable"] + "required": ["params"], + "title": "DispenseCreate", + "type": "object" }, - "RetractAspirate": { - "title": "RetractAspirate", - "description": "Shared properties for the retract function after aspiration.", - "type": "object", + "DispenseInPlaceCreate": { + "description": "DispenseInPlace command request model.", "properties": { - "positionReference": { - "description": "Position reference for retract after aspirate.", - "allOf": [ - { - "$ref": "#/definitions/PositionReference" - } - ] + "commandType": { + "const": "dispenseInPlace", + "default": "dispenseInPlace", + "enum": ["dispenseInPlace"], + "title": "Commandtype", + "type": "string" }, - "offset": { - "title": "Offset", - "description": "Relative offset for retract after aspirate.", - "allOf": [ - { - "$ref": "#/definitions/Coordinate" - } - ] + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" }, - "speed": { - "title": "Speed", - "description": "Speed of retraction, in millimeters per second.", - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", + "type": "string" }, - "airGapByVolume": { - "title": "Airgapbyvolume", - "description": "Settings for air gap keyed by target aspiration volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - } - ] - } + "params": { + "$ref": "#/$defs/DispenseInPlaceParams" + } + }, + "required": ["params"], + "title": "DispenseInPlaceCreate", + "type": "object" + }, + "DispenseInPlaceParams": { + "description": "Payload required to dispense in place.", + "properties": { + "flowRate": { + "description": "Speed in \u00b5L/s configured for the pipette", + "exclusiveMinimum": 0.0, + "title": "Flowrate", + "type": "number" }, - "touchTip": { - "title": "Touchtip", - "description": "Touch tip settings for retract after aspirate.", - "allOf": [ - { - "$ref": "#/definitions/TouchTipProperties" - } - ] + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", + "type": "string" }, - "delay": { - "title": "Delay", - "description": "Delay settings for retract after aspirate.", - "allOf": [ - { - "$ref": "#/definitions/DelayProperties" - } - ] + "pushOut": { + "description": "push the plunger a small amount farther than necessary for accurate low-volume dispensing", + "title": "Pushout", + "type": "number" + }, + "volume": { + "description": "The amount of liquid to dispense, in \u00b5L. Must not be greater than the currently aspirated volume. There is some tolerance for floating point rounding errors.", + "minimum": 0.0, + "title": "Volume", + "type": "number" } }, - "required": [ - "positionReference", - "offset", - "speed", - "airGapByVolume", - "touchTip", - "delay" - ] + "required": ["flowRate", "volume", "pipetteId"], + "title": "DispenseInPlaceParams", + "type": "object" }, - "MixParams": { - "title": "MixParams", - "description": "Parameters for mix.", - "type": "object", + "DispenseParams": { + "description": "Payload required to dispense to a specific well.", "properties": { - "repetitions": { - "title": "Repetitions", - "description": "Number of mixing repetitions.", - "minimum": 0, - "type": "integer" + "flowRate": { + "description": "Speed in \u00b5L/s configured for the pipette", + "exclusiveMinimum": 0.0, + "title": "Flowrate", + "type": "number" + }, + "labwareId": { + "description": "Identifier of labware to use.", + "title": "Labwareid", + "type": "string" + }, + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", + "type": "string" + }, + "pushOut": { + "description": "push the plunger a small amount farther than necessary for accurate low-volume dispensing", + "title": "Pushout", + "type": "number" }, "volume": { + "description": "The amount of liquid to dispense, in \u00b5L. Must not be greater than the currently aspirated volume. There is some tolerance for floating point rounding errors.", + "minimum": 0.0, "title": "Volume", - "description": "Volume used for mixing, in microliters.", - "anyOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ] + "type": "number" + }, + "wellLocation": { + "$ref": "#/$defs/LiquidHandlingWellLocation", + "description": "Relative well location at which to perform the operation" + }, + "wellName": { + "description": "Name of well to use in labware.", + "title": "Wellname", + "type": "string" } }, - "required": ["repetitions", "volume"] + "required": ["labwareId", "wellName", "flowRate", "volume", "pipetteId"], + "title": "DispenseParams", + "type": "object" }, - "MixProperties": { - "title": "MixProperties", - "description": "Mixing properties.", - "type": "object", + "DropTipCreate": { + "description": "Drop tip command creation request model.", "properties": { - "enable": { - "title": "Enable", - "description": "Whether mix is enabled.", - "type": "boolean" + "commandType": { + "const": "dropTip", + "default": "dropTip", + "enum": ["dropTip"], + "title": "Commandtype", + "type": "string" + }, + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" + }, + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", + "type": "string" }, "params": { - "title": "Params", - "description": "Parameters for the mix function.", - "allOf": [ - { - "$ref": "#/definitions/MixParams" - } - ] + "$ref": "#/$defs/DropTipParams" } }, - "required": ["enable"] + "required": ["params"], + "title": "DropTipCreate", + "type": "object" }, - "AspirateProperties": { - "title": "AspirateProperties", - "description": "Properties specific to the aspirate function.", - "type": "object", + "DropTipInPlaceCreate": { + "description": "Drop tip in place command creation request model.", "properties": { - "submerge": { - "title": "Submerge", - "description": "Submerge settings for aspirate.", - "allOf": [ - { - "$ref": "#/definitions/Submerge" - } - ] - }, - "retract": { - "title": "Retract", - "description": "Pipette retract settings after an aspirate.", - "allOf": [ - { - "$ref": "#/definitions/RetractAspirate" - } - ] - }, - "positionReference": { - "description": "Position reference for aspiration.", - "allOf": [ - { - "$ref": "#/definitions/PositionReference" - } - ] - }, - "offset": { - "title": "Offset", - "description": "Relative offset for aspiration.", - "allOf": [ - { - "$ref": "#/definitions/Coordinate" - } - ] - }, - "flowRateByVolume": { - "title": "Flowratebyvolume", - "description": "Settings for flow rate keyed by target aspiration volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - } - ] - } - }, - "correctionByVolume": { - "title": "Correctionbyvolume", - "description": "Settings for volume correction keyed by by target aspiration volume, representing additional volume the plunger should move to accurately hit target volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ] - } - ] - } + "commandType": { + "const": "dropTipInPlace", + "default": "dropTipInPlace", + "enum": ["dropTipInPlace"], + "title": "Commandtype", + "type": "string" }, - "preWet": { - "title": "Prewet", - "description": "Whether to perform a pre-wet action.", - "type": "boolean" + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" }, - "mix": { - "title": "Mix", - "description": "Mixing settings for before an aspirate", - "allOf": [ - { - "$ref": "#/definitions/MixProperties" - } - ] + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", + "type": "string" }, - "delay": { - "title": "Delay", - "description": "Delay settings after an aspirate", - "allOf": [ - { - "$ref": "#/definitions/DelayProperties" - } - ] + "params": { + "$ref": "#/$defs/DropTipInPlaceParams" } }, - "required": [ - "submerge", - "retract", - "positionReference", - "offset", - "flowRateByVolume", - "correctionByVolume", - "preWet", - "mix", - "delay" - ] - }, - "BlowoutLocation": { - "title": "BlowoutLocation", - "description": "Location for blowout during a transfer function.", - "enum": ["source", "destination", "trash"] + "required": ["params"], + "title": "DropTipInPlaceCreate", + "type": "object" }, - "BlowoutParams": { - "title": "BlowoutParams", - "description": "Parameters for blowout.", - "type": "object", + "DropTipInPlaceParams": { + "description": "Payload required to drop a tip in place.", "properties": { - "location": { - "description": "Location well or trash entity for blow out.", - "allOf": [ - { - "$ref": "#/definitions/BlowoutLocation" - } - ] + "homeAfter": { + "description": "Whether to home this pipette's plunger after dropping the tip. You should normally leave this unspecified to let the robot choose a safe default depending on its hardware.", + "title": "Homeafter", + "type": "boolean" }, - "flowRate": { - "title": "Flowrate", - "description": "Flow rate for blow out, in microliters per second.", - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", + "type": "string" } }, - "required": ["location", "flowRate"] + "required": ["pipetteId"], + "title": "DropTipInPlaceParams", + "type": "object" }, - "BlowoutProperties": { - "title": "BlowoutProperties", - "description": "Blowout properties.", - "type": "object", + "DropTipParams": { + "description": "Payload required to drop a tip in a specific well.", "properties": { - "enable": { - "title": "Enable", - "description": "Whether blow-out is enabled.", + "alternateDropLocation": { + "description": "Whether to alternate location where tip is dropped within the labware. If True, this command will ignore the wellLocation provided and alternate between dropping tips at two predetermined locations inside the specified labware well. If False, the tip will be dropped at the top center of the well.", + "title": "Alternatedroplocation", "type": "boolean" }, - "params": { - "title": "Params", - "description": "Parameters for the blowout function.", - "allOf": [ - { - "$ref": "#/definitions/BlowoutParams" - } - ] + "homeAfter": { + "description": "Whether to home this pipette's plunger after dropping the tip. You should normally leave this unspecified to let the robot choose a safe default depending on its hardware.", + "title": "Homeafter", + "type": "boolean" + }, + "labwareId": { + "description": "Identifier of labware to use.", + "title": "Labwareid", + "type": "string" + }, + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", + "type": "string" + }, + "wellLocation": { + "$ref": "#/$defs/DropTipWellLocation", + "description": "Relative well location at which to drop the tip." + }, + "wellName": { + "description": "Name of well to use in labware.", + "title": "Wellname", + "type": "string" } }, - "required": ["enable"] + "required": ["pipetteId", "labwareId", "wellName"], + "title": "DropTipParams", + "type": "object" }, - "RetractDispense": { - "title": "RetractDispense", - "description": "Shared properties for the retract function after dispense.", - "type": "object", + "DropTipWellLocation": { + "description": "Like WellLocation, but for dropping tips.\n\nUnlike a typical WellLocation, the location for a drop tip\ndefaults to location based on the tip length rather than the well's top.", "properties": { - "positionReference": { - "description": "Position reference for retract after dispense.", - "allOf": [ - { - "$ref": "#/definitions/PositionReference" - } - ] - }, "offset": { - "title": "Offset", - "description": "Relative offset for retract after dispense.", - "allOf": [ - { - "$ref": "#/definitions/Coordinate" - } - ] - }, - "speed": { - "title": "Speed", - "description": "Speed of retraction, in millimeters per second.", - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] + "$ref": "#/$defs/WellOffset" }, - "airGapByVolume": { - "title": "Airgapbyvolume", - "description": "Settings for air gap keyed by target aspiration volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - } - ] - } + "origin": { + "$ref": "#/$defs/DropTipWellOrigin", + "default": "default" + } + }, + "title": "DropTipWellLocation", + "type": "object" + }, + "DropTipWellOrigin": { + "description": "The origin of a DropTipWellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well\n DEFAULT: the default drop-tip location of the well,\n based on pipette configuration and length of the tip.", + "enum": ["top", "bottom", "center", "default"], + "title": "DropTipWellOrigin", + "type": "string" + }, + "EngageCreate": { + "description": "A request to create a Magnetic Module engage command.", + "properties": { + "commandType": { + "const": "magneticModule/engage", + "default": "magneticModule/engage", + "enum": ["magneticModule/engage"], + "title": "Commandtype", + "type": "string" }, - "blowout": { - "title": "Blowout", - "description": "Blowout properties for retract after dispense.", - "allOf": [ - { - "$ref": "#/definitions/BlowoutProperties" - } - ] + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" }, - "touchTip": { - "title": "Touchtip", - "description": "Touch tip settings for retract after dispense.", - "allOf": [ - { - "$ref": "#/definitions/TouchTipProperties" - } - ] + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", + "type": "string" }, - "delay": { - "title": "Delay", - "description": "Delay settings for retract after dispense.", - "allOf": [ - { - "$ref": "#/definitions/DelayProperties" - } - ] + "params": { + "$ref": "#/$defs/EngageParams" } }, - "required": [ - "positionReference", - "offset", - "speed", - "airGapByVolume", - "blowout", - "touchTip", - "delay" - ] + "required": ["params"], + "title": "EngageCreate", + "type": "object" }, - "SingleDispenseProperties": { - "title": "SingleDispenseProperties", - "description": "Properties specific to the single-dispense function.", - "type": "object", + "EngageParams": { + "description": "Input data to engage a Magnetic Module.", "properties": { - "submerge": { - "title": "Submerge", - "description": "Submerge settings for single dispense.", - "allOf": [ - { - "$ref": "#/definitions/Submerge" - } - ] - }, - "retract": { - "title": "Retract", - "description": "Pipette retract settings after a single dispense.", - "allOf": [ - { - "$ref": "#/definitions/RetractDispense" - } - ] - }, - "positionReference": { - "description": "Position reference for single dispense.", - "allOf": [ - { - "$ref": "#/definitions/PositionReference" - } - ] - }, - "offset": { - "title": "Offset", - "description": "Relative offset for single dispense.", - "allOf": [ - { - "$ref": "#/definitions/Coordinate" - } - ] - }, - "flowRateByVolume": { - "title": "Flowratebyvolume", - "description": "Settings for flow rate keyed by target dispense volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - } - ] - } - }, - "correctionByVolume": { - "title": "Correctionbyvolume", - "description": "Settings for volume correction keyed by by target dispense volume, representing additional volume the plunger should move to accurately hit target volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ] - } - ] - } - }, - "mix": { - "title": "Mix", - "description": "Mixing settings for after a dispense", - "allOf": [ - { - "$ref": "#/definitions/MixProperties" - } - ] - }, - "pushOutByVolume": { - "title": "Pushoutbyvolume", - "description": "Settings for pushout keyed by target dispense volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - } - ] - } - }, - "delay": { - "title": "Delay", - "description": "Delay after dispense, in seconds.", - "allOf": [ - { - "$ref": "#/definitions/DelayProperties" - } - ] - } - }, - "required": [ - "submerge", - "retract", - "positionReference", - "offset", - "flowRateByVolume", - "correctionByVolume", - "mix", - "pushOutByVolume", - "delay" - ] - }, - "MultiDispenseProperties": { - "title": "MultiDispenseProperties", - "description": "Properties specific to the multi-dispense function.", - "type": "object", - "properties": { - "submerge": { - "title": "Submerge", - "description": "Submerge settings for multi-dispense.", - "allOf": [ - { - "$ref": "#/definitions/Submerge" - } - ] - }, - "retract": { - "title": "Retract", - "description": "Pipette retract settings after a multi-dispense.", - "allOf": [ - { - "$ref": "#/definitions/RetractDispense" - } - ] - }, - "positionReference": { - "description": "Position reference for multi-dispense.", - "allOf": [ - { - "$ref": "#/definitions/PositionReference" - } - ] - }, - "offset": { - "title": "Offset", - "description": "Relative offset for single multi-dispense.", - "allOf": [ - { - "$ref": "#/definitions/Coordinate" - } - ] - }, - "flowRateByVolume": { - "title": "Flowratebyvolume", - "description": "Settings for flow rate keyed by target dispense volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - } - ] - } - }, - "correctionByVolume": { - "title": "Correctionbyvolume", - "description": "Settings for volume correction keyed by by target dispense volume, representing additional volume the plunger should move to accurately hit target volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ] - } - ] - } - }, - "conditioningByVolume": { - "title": "Conditioningbyvolume", - "description": "Settings for conditioning volume keyed by target dispense volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - } - ] - } - }, - "disposalByVolume": { - "title": "Disposalbyvolume", - "description": "Settings for disposal volume keyed by target dispense volume.", - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - }, - { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "number", - "minimum": 0.0 - } - ] - } - ] - } + "height": { + "description": "How high, in millimeters, to raise the magnets.\n\nZero means the tops of the magnets are level with the ledge that the labware rests on. This will be slightly above the magnets' minimum height, the hardware home position. Negative values are allowed, to put the magnets below the ledge.\n\nUnits are always true millimeters. This is unlike certain labware definitions, engage commands in the Python Protocol API, and engage commands in older versions of the JSON protocol schema. Take care to convert properly.", + "title": "Height", + "type": "number" }, - "delay": { - "title": "Delay", - "description": "Delay settings after each dispense", - "allOf": [ - { - "$ref": "#/definitions/DelayProperties" - } - ] + "moduleId": { + "description": "The ID of the Magnetic Module whose magnets you want to raise, from a prior `loadModule` command.", + "title": "Moduleid", + "type": "string" } }, - "required": [ - "submerge", - "retract", - "positionReference", - "offset", - "flowRateByVolume", - "correctionByVolume", - "conditioningByVolume", - "disposalByVolume", - "delay" - ] + "required": ["moduleId", "height"], + "title": "EngageParams", + "type": "object" }, - "LiquidClassRecord": { - "title": "LiquidClassRecord", - "description": "LiquidClassRecord is our internal representation of an (immutable) liquid class.\n\nConceptually, a liquid class record is the tuple (name, pipette, tip, transfer properties).\nWe consider two liquid classes to be the same if every entry in that tuple is the same; and liquid\nclasses are different if any entry in the tuple is different.\n\nThis class defines the tuple via inheritance so that we can reuse the definitions from shared_data.", - "type": "object", + "GetNextTipCreate": { + "description": "Get next tip command creation request model.", "properties": { - "tiprack": { - "title": "Tiprack", - "description": "The name of tiprack whose tip will be used when handling this specific liquid class with this pipette", - "type": "string" - }, - "aspirate": { - "title": "Aspirate", - "description": "Aspirate parameters for this tip type.", - "allOf": [ - { - "$ref": "#/definitions/AspirateProperties" - } - ] - }, - "singleDispense": { - "title": "Singledispense", - "description": "Single dispense parameters for this tip type.", - "allOf": [ - { - "$ref": "#/definitions/SingleDispenseProperties" - } - ] - }, - "multiDispense": { - "title": "Multidispense", - "description": "Optional multi-dispense parameters for this tip type.", - "allOf": [ - { - "$ref": "#/definitions/MultiDispenseProperties" - } - ] - }, - "liquidClassName": { - "title": "Liquidclassname", - "description": "Identifier for the liquid of this liquid class, e.g. glycerol50.", + "commandType": { + "const": "getNextTip", + "default": "getNextTip", + "enum": ["getNextTip"], + "title": "Commandtype", "type": "string" }, - "pipetteModel": { - "title": "Pipettemodel", - "description": "Identifier for the pipette of this liquid class.", + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" + }, + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/GetNextTipParams" } }, - "required": [ - "tiprack", - "aspirate", - "singleDispense", - "liquidClassName", - "pipetteModel" - ] + "required": ["params"], + "title": "GetNextTipCreate", + "type": "object" }, - "LoadLiquidClassParams": { - "title": "LoadLiquidClassParams", - "description": "The liquid class transfer properties to store.", - "type": "object", + "GetNextTipParams": { + "description": "Payload needed to resolve the next available tip.", "properties": { - "liquidClassId": { - "title": "Liquidclassid", - "description": "Unique identifier for the liquid class to store. If you do not supply a liquidClassId, we will generate one.", + "labwareIds": { + "description": "Labware ID(s) of tip racks to resolve next available tip(s) from Labware IDs will be resolved sequentially", + "items": { + "type": "string" + }, + "title": "Labwareids", + "type": "array" + }, + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" }, - "liquidClassRecord": { - "title": "Liquidclassrecord", - "description": "The liquid class to store.", - "allOf": [ - { - "$ref": "#/definitions/LiquidClassRecord" - } - ] + "startingTipWell": { + "description": "Name of starting tip rack 'well'. This only applies to the first tip rack in the list provided in labwareIDs", + "title": "Startingtipwell", + "type": "string" } }, - "required": ["liquidClassRecord"] + "required": ["pipetteId", "labwareIds"], + "title": "GetNextTipParams", + "type": "object" }, - "LoadLiquidClassCreate": { - "title": "LoadLiquidClassCreate", - "description": "Load Liquid Class command creation request.", - "type": "object", + "GetTipPresenceCreate": { + "description": "GetTipPresence command creation request model.", "properties": { "commandType": { + "const": "getTipPresence", + "default": "getTipPresence", + "enum": ["getTipPresence"], "title": "Commandtype", - "default": "loadLiquidClass", - "enum": ["loadLiquidClass"], "type": "string" }, - "params": { - "$ref": "#/definitions/LoadLiquidClassParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/GetTipPresenceParams" } }, - "required": ["params"] - }, - "ModuleModel": { - "title": "ModuleModel", - "description": "All available modules' models.", - "enum": [ - "temperatureModuleV1", - "temperatureModuleV2", - "magneticModuleV1", - "magneticModuleV2", - "thermocyclerModuleV1", - "thermocyclerModuleV2", - "heaterShakerModuleV1", - "magneticBlockV1", - "absorbanceReaderV1" - ], - "type": "string" + "required": ["params"], + "title": "GetTipPresenceCreate", + "type": "object" }, - "LoadModuleParams": { - "title": "LoadModuleParams", - "description": "Payload required to load a module.", - "type": "object", + "GetTipPresenceParams": { + "description": "Payload required for a GetTipPresence command.", "properties": { - "model": { - "description": "The model name of the module to load.\n\nProtocol Engine will look for a connected module that either exactly matches this one, or is compatible.\n\n For example, if you request a `temperatureModuleV1` here, Protocol Engine might load a `temperatureModuleV1` or a `temperatureModuleV2`.\n\n The model that it finds connected will be available through `result.model`.", - "allOf": [ - { - "$ref": "#/definitions/ModuleModel" - } - ] - }, - "location": { - "title": "Location", - "description": "The location into which this module should be loaded.\n\nFor the Thermocycler Module, which occupies multiple deck slots, this should be the front-most occupied slot (normally slot 7).", - "allOf": [ - { - "$ref": "#/definitions/DeckSlotLocation" - } - ] - }, - "moduleId": { - "title": "Moduleid", - "description": "An optional ID to assign to this module. If None, an ID will be generated.", + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" } }, - "required": ["model", "location"] + "required": ["pipetteId"], + "title": "GetTipPresenceParams", + "type": "object" }, - "LoadModuleCreate": { - "title": "LoadModuleCreate", - "description": "The model for a creation request for a load module command.", - "type": "object", + "HomeCreate": { + "description": "Data to create a Home command.", "properties": { "commandType": { + "const": "home", + "default": "home", + "enum": ["home"], "title": "Commandtype", - "default": "loadModule", - "enum": ["loadModule"], "type": "string" }, - "params": { - "$ref": "#/definitions/LoadModuleParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/HomeParams" } }, - "required": ["params"] - }, - "PipetteNameType": { - "title": "PipetteNameType", - "description": "Pipette load name values.", - "enum": [ - "p10_single", - "p10_multi", - "p20_single_gen2", - "p20_multi_gen2", - "p50_single", - "p50_multi", - "p50_single_flex", - "p50_multi_flex", - "p300_single", - "p300_multi", - "p300_single_gen2", - "p300_multi_gen2", - "p1000_single", - "p1000_single_gen2", - "p1000_single_flex", - "p1000_multi_flex", - "p1000_multi_em", - "p1000_96", - "p200_96" - ], - "type": "string" + "required": ["params"], + "title": "HomeCreate", + "type": "object" }, - "LoadPipetteParams": { - "title": "LoadPipetteParams", - "description": "Payload needed to load a pipette on to a mount.", - "type": "object", + "HomeParams": { + "description": "Payload required for a Home command.", "properties": { - "pipetteName": { - "description": "The load name of the pipette to be required.", - "allOf": [ - { - "$ref": "#/definitions/PipetteNameType" - } - ] - }, - "mount": { - "description": "The mount the pipette should be present on.", - "allOf": [ - { - "$ref": "#/definitions/MountType" - } - ] - }, - "pipetteId": { - "title": "Pipetteid", - "description": "An optional ID to assign to this pipette. If None, an ID will be generated.", - "type": "string" - }, - "tipOverlapNotAfterVersion": { - "title": "Tipoverlapnotafterversion", - "description": "A version of tip overlap data to not exceed. The highest-versioned tip overlap data that does not exceed this version will be used. Versions are expressed as vN where N is an integer, counting up from v0. If None, the current highest version will be used.", - "type": "string" + "axes": { + "description": "Axes to return to their home positions. If omitted, will home all motors. Extra axes may be implicitly homed to ensure accurate homing of the explicitly specified axes.", + "items": { + "$ref": "#/$defs/MotorAxis" + }, + "title": "Axes", + "type": "array" }, - "liquidPresenceDetection": { - "title": "Liquidpresencedetection", - "description": "Enable liquid presence detection for this pipette. Defaults to False.", - "type": "boolean" + "skipIfMountPositionOk": { + "$ref": "#/$defs/MountType", + "description": "If this parameter is provided, the gantry will only be homed if the specified mount has an invalid position. If omitted, the homing action will be executed unconditionally.", + "title": "Skipifmountpositionok" } }, - "required": ["pipetteName", "mount"] + "title": "HomeParams", + "type": "object" }, - "LoadPipetteCreate": { - "title": "LoadPipetteCreate", - "description": "Load pipette command creation request model.", - "type": "object", + "InitializeCreate": { + "description": "A request to execute an Absorbance Reader measurement.", "properties": { "commandType": { + "const": "absorbanceReader/initialize", + "default": "absorbanceReader/initialize", + "enum": ["absorbanceReader/initialize"], "title": "Commandtype", - "default": "loadPipette", - "enum": ["loadPipette"], "type": "string" }, - "params": { - "$ref": "#/definitions/LoadPipetteParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", + "type": "string" + }, + "params": { + "$ref": "#/$defs/InitializeParams" + } + }, + "required": ["params"], + "title": "InitializeCreate", + "type": "object" + }, + "InitializeParams": { + "description": "Input parameters to initialize an absorbance reading.", + "properties": { + "measureMode": { + "description": "Initialize single or multi measurement mode.", + "enum": ["single", "multi"], + "title": "Measuremode", + "type": "string" + }, + "moduleId": { + "description": "Unique ID of the absorbance reader.", + "title": "Moduleid", "type": "string" + }, + "referenceWavelength": { + "description": "Optional reference wavelength in nm.", + "title": "Referencewavelength", + "type": "integer" + }, + "sampleWavelengths": { + "description": "Sample wavelengths in nm.", + "items": { + "type": "integer" + }, + "title": "Samplewavelengths", + "type": "array" } }, - "required": ["params"] + "required": ["moduleId", "measureMode", "sampleWavelengths"], + "title": "InitializeParams", + "type": "object" + }, + "InstrumentSensorId": { + "description": "Primary and secondary sensor ids.", + "enum": ["primary", "secondary", "both"], + "title": "InstrumentSensorId", + "type": "string" }, "LabwareMovementStrategy": { - "title": "LabwareMovementStrategy", "description": "Strategy to use for labware movement.", "enum": ["usingGripper", "manualMoveWithPause", "manualMoveWithoutPause"], + "title": "LabwareMovementStrategy", "type": "string" }, "LabwareOffsetVector": { - "title": "LabwareOffsetVector", "description": "Offset, in deck coordinates from nominal to actual position.", - "type": "object", "properties": { "x": { "title": "X", "type": "number" }, - "y": { - "title": "Y", - "type": "number" + "y": { + "title": "Y", + "type": "number" + }, + "z": { + "title": "Z", + "type": "number" + } + }, + "required": ["x", "y", "z"], + "title": "LabwareOffsetVector", + "type": "object" + }, + "LiquidClassRecord": { + "description": "LiquidClassRecord is our internal representation of an (immutable) liquid class.\n\nConceptually, a liquid class record is the tuple (name, pipette, tip, transfer properties).\nWe consider two liquid classes to be the same if every entry in that tuple is the same; and liquid\nclasses are different if any entry in the tuple is different.\n\nThis class defines the tuple via inheritance so that we can reuse the definitions from shared_data.", + "properties": { + "aspirate": { + "$ref": "#/$defs/AspirateProperties", + "description": "Aspirate parameters for this tip type." + }, + "liquidClassName": { + "description": "Identifier for the liquid of this liquid class, e.g. glycerol50.", + "title": "Liquidclassname", + "type": "string" + }, + "multiDispense": { + "$ref": "#/$defs/MultiDispenseProperties", + "description": "Optional multi-dispense parameters for this tip type.", + "title": "Multidispense" + }, + "pipetteModel": { + "description": "Identifier for the pipette of this liquid class.", + "title": "Pipettemodel", + "type": "string" }, - "z": { - "title": "Z", - "type": "number" + "singleDispense": { + "$ref": "#/$defs/SingleDispenseProperties", + "description": "Single dispense parameters for this tip type." + }, + "tiprack": { + "description": "The name of tiprack whose tip will be used when handling this specific liquid class with this pipette", + "title": "Tiprack", + "type": "string" } }, - "required": ["x", "y", "z"] + "required": [ + "tiprack", + "aspirate", + "singleDispense", + "liquidClassName", + "pipetteModel" + ], + "title": "LiquidClassRecord", + "type": "object" }, - "MoveLabwareParams": { - "title": "MoveLabwareParams", - "description": "Input parameters for a ``moveLabware`` command.", - "type": "object", + "LiquidClassTouchTipParams": { + "description": "Parameters for touch-tip.", "properties": { - "labwareId": { - "title": "Labwareid", - "description": "The ID of the labware to move.", - "type": "string" - }, - "newLocation": { - "title": "Newlocation", - "description": "Where to move the labware.", + "mmToEdge": { "anyOf": [ { - "$ref": "#/definitions/DeckSlotLocation" - }, - { - "$ref": "#/definitions/ModuleLocation" + "type": "integer" }, { - "$ref": "#/definitions/OnLabwareLocation" - }, + "type": "number" + } + ], + "description": "Offset away from the the well edge, in millimeters.", + "title": "Mmtoedge" + }, + "speed": { + "anyOf": [ { - "enum": ["offDeck"], - "type": "string" + "minimum": 0, + "type": "integer" }, { - "$ref": "#/definitions/AddressableAreaLocation" + "minimum": 0.0, + "type": "number" } - ] + ], + "description": "Touch-tip speed, in millimeters per second.", + "title": "Speed" }, - "strategy": { - "description": "Whether to use the gripper to perform the labware movement or to perform a manual movement with an option to pause.", - "allOf": [ + "zOffset": { + "anyOf": [ { - "$ref": "#/definitions/LabwareMovementStrategy" - } - ] - }, - "pickUpOffset": { - "title": "Pickupoffset", - "description": "Offset to use when picking up labware. Experimental param, subject to change", - "allOf": [ + "type": "integer" + }, { - "$ref": "#/definitions/LabwareOffsetVector" + "type": "number" } - ] + ], + "description": "Offset from the top of the well for touch-tip, in millimeters.", + "title": "Zoffset" + } + }, + "required": ["zOffset", "mmToEdge", "speed"], + "title": "LiquidClassTouchTipParams", + "type": "object" + }, + "LiquidHandlingWellLocation": { + "description": "A relative location in reference to a well's location.\n\nTo be used with commands that handle liquids.", + "properties": { + "offset": { + "$ref": "#/$defs/WellOffset" }, - "dropOffset": { - "title": "Dropoffset", - "description": "Offset to use when dropping off labware. Experimental param, subject to change", - "allOf": [ + "origin": { + "$ref": "#/$defs/WellOrigin", + "default": "top" + }, + "volumeOffset": { + "anyOf": [ + { + "type": "number" + }, { - "$ref": "#/definitions/LabwareOffsetVector" + "const": "operationVolume", + "enum": ["operationVolume"], + "type": "string" } - ] + ], + "default": 0.0, + "description": "A volume of liquid, in \u00b5L, to offset the z-axis offset. When \"operationVolume\" is specified, this volume is pulled from the command volume parameter.", + "title": "Volumeoffset" } }, - "required": ["labwareId", "newLocation", "strategy"] + "title": "LiquidHandlingWellLocation", + "type": "object" }, - "MoveLabwareCreate": { - "title": "MoveLabwareCreate", - "description": "A request to create a ``moveLabware`` command.", - "type": "object", + "LiquidProbeCreate": { + "description": "The request model for a `liquidProbe` command.", "properties": { "commandType": { + "const": "liquidProbe", + "default": "liquidProbe", + "enum": ["liquidProbe"], "title": "Commandtype", - "default": "moveLabware", - "enum": ["moveLabware"], "type": "string" }, - "params": { - "$ref": "#/definitions/MoveLabwareParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/LiquidProbeParams" } }, - "required": ["params"] - }, - "MovementAxis": { - "title": "MovementAxis", - "description": "Axis on which to issue a relative movement.", - "enum": ["x", "y", "z"], - "type": "string" + "required": ["params"], + "title": "LiquidProbeCreate", + "type": "object" }, - "MoveRelativeParams": { - "title": "MoveRelativeParams", - "description": "Payload required for a MoveRelative command.", - "type": "object", + "LiquidProbeParams": { + "description": "Parameters required for a `liquidProbe` command.", "properties": { + "labwareId": { + "description": "Identifier of labware to use.", + "title": "Labwareid", + "type": "string" + }, "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", "title": "Pipetteid", - "description": "Pipette to move.", "type": "string" }, - "axis": { - "description": "Axis along which to move.", - "allOf": [ - { - "$ref": "#/definitions/MovementAxis" - } - ] + "wellLocation": { + "$ref": "#/$defs/WellLocation", + "description": "Relative well location at which to perform the operation" }, - "distance": { - "title": "Distance", - "description": "Distance to move in millimeters. A positive number will move towards the right (x), back (y), top (z) of the deck.", - "type": "number" + "wellName": { + "description": "Name of well to use in labware.", + "title": "Wellname", + "type": "string" } }, - "required": ["pipetteId", "axis", "distance"] + "required": ["labwareId", "wellName", "pipetteId"], + "title": "LiquidProbeParams", + "type": "object" }, - "MoveRelativeCreate": { - "title": "MoveRelativeCreate", - "description": "Data to create a MoveRelative command.", - "type": "object", + "LoadLabwareCreate": { + "description": "Load labware command creation request.", "properties": { "commandType": { + "const": "loadLabware", + "default": "loadLabware", + "enum": ["loadLabware"], "title": "Commandtype", - "default": "moveRelative", - "enum": ["moveRelative"], "type": "string" }, - "params": { - "$ref": "#/definitions/MoveRelativeParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/LoadLabwareParams" } }, - "required": ["params"] + "required": ["params"], + "title": "LoadLabwareCreate", + "type": "object" }, - "DeckPoint": { - "title": "DeckPoint", - "description": "Coordinates of a point in deck space.", - "type": "object", + "LoadLabwareParams": { + "description": "Payload required to load a labware into a slot.", "properties": { - "x": { - "title": "X", - "type": "number" + "displayName": { + "description": "An optional user-specified display name or label for this labware.", + "title": "Displayname", + "type": "string" }, - "y": { - "title": "Y", - "type": "number" + "labwareId": { + "description": "An optional ID to assign to this labware. If None, an ID will be generated.", + "title": "Labwareid", + "type": "string" }, - "z": { - "title": "Z", - "type": "number" + "loadName": { + "description": "Name used to reference a labware definition.", + "title": "Loadname", + "type": "string" + }, + "location": { + "anyOf": [ + { + "$ref": "#/$defs/DeckSlotLocation" + }, + { + "$ref": "#/$defs/ModuleLocation" + }, + { + "$ref": "#/$defs/OnLabwareLocation" + }, + { + "const": "offDeck", + "enum": ["offDeck"], + "type": "string" + }, + { + "$ref": "#/$defs/AddressableAreaLocation" + } + ], + "description": "Location the labware should be loaded into.", + "title": "Location" + }, + "namespace": { + "description": "The namespace the labware definition belongs to.", + "title": "Namespace", + "type": "string" + }, + "version": { + "description": "The labware definition version.", + "title": "Version", + "type": "integer" } }, - "required": ["x", "y", "z"] + "required": ["location", "loadName", "namespace", "version"], + "title": "LoadLabwareParams", + "type": "object" }, - "MoveToCoordinatesParams": { - "title": "MoveToCoordinatesParams", - "description": "Payload required to move a pipette to coordinates.", - "type": "object", + "LoadLiquidClassCreate": { + "description": "Load Liquid Class command creation request.", "properties": { - "minimumZHeight": { - "title": "Minimumzheight", - "description": "Optional minimal Z margin in mm. If this is larger than the API's default safe Z margin, it will make the arc higher. If it's smaller, it will have no effect.", - "type": "number" - }, - "forceDirect": { - "title": "Forcedirect", - "description": "If true, moving from one labware/well to another will not arc to the default safe z, but instead will move directly to the specified location. This will also force the `minimumZHeight` param to be ignored. A 'direct' movement is in X/Y/Z simultaneously.", - "default": false, - "type": "boolean" + "commandType": { + "const": "loadLiquidClass", + "default": "loadLiquidClass", + "enum": ["loadLiquidClass"], + "title": "Commandtype", + "type": "string" }, - "speed": { - "title": "Speed", - "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", - "type": "number" + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" }, - "coordinates": { - "title": "Coordinates", - "description": "X, Y and Z coordinates in mm from deck's origin location (left-front-bottom corner of work space)", - "allOf": [ - { - "$ref": "#/definitions/DeckPoint" - } - ] + "params": { + "$ref": "#/$defs/LoadLiquidClassParams" } }, - "required": ["pipetteId", "coordinates"] + "required": ["params"], + "title": "LoadLiquidClassCreate", + "type": "object" }, - "MoveToCoordinatesCreate": { - "title": "MoveToCoordinatesCreate", - "description": "Move to coordinates command creation request model.", - "type": "object", + "LoadLiquidClassParams": { + "description": "The liquid class transfer properties to store.", + "properties": { + "liquidClassId": { + "description": "Unique identifier for the liquid class to store. If you do not supply a liquidClassId, we will generate one.", + "title": "Liquidclassid", + "type": "string" + }, + "liquidClassRecord": { + "$ref": "#/$defs/LiquidClassRecord", + "description": "The liquid class to store." + } + }, + "required": ["liquidClassRecord"], + "title": "LoadLiquidClassParams", + "type": "object" + }, + "LoadLiquidCreate": { + "description": "Load liquid command creation request.", "properties": { "commandType": { + "const": "loadLiquid", + "default": "loadLiquid", + "enum": ["loadLiquid"], "title": "Commandtype", - "default": "moveToCoordinates", - "enum": ["moveToCoordinates"], "type": "string" }, - "params": { - "$ref": "#/definitions/MoveToCoordinatesParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/LoadLiquidParams" } }, - "required": ["params"] + "required": ["params"], + "title": "LoadLiquidCreate", + "type": "object" }, - "MoveToWellParams": { - "title": "MoveToWellParams", - "description": "Payload required to move a pipette to a specific well.", - "type": "object", + "LoadLiquidParams": { + "description": "Payload required to load a liquid into a well.", "properties": { - "minimumZHeight": { - "title": "Minimumzheight", - "description": "Optional minimal Z margin in mm. If this is larger than the API's default safe Z margin, it will make the arc higher. If it's smaller, it will have no effect.", - "type": "number" - }, - "forceDirect": { - "title": "Forcedirect", - "description": "If true, moving from one labware/well to another will not arc to the default safe z, but instead will move directly to the specified location. This will also force the `minimumZHeight` param to be ignored. A 'direct' movement is in X/Y/Z simultaneously.", - "default": false, - "type": "boolean" - }, - "speed": { - "title": "Speed", - "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", - "type": "number" - }, "labwareId": { + "description": "Unique identifier of labware to load liquid into.", "title": "Labwareid", - "description": "Identifier of labware to use.", "type": "string" }, - "wellName": { - "title": "Wellname", - "description": "Name of well to use in labware.", - "type": "string" - }, - "wellLocation": { - "title": "Welllocation", - "description": "Relative well location at which to perform the operation", - "allOf": [ + "liquidId": { + "anyOf": [ { - "$ref": "#/definitions/WellLocation" + "type": "string" + }, + { + "const": "EMPTY", + "enum": ["EMPTY"], + "type": "string" } - ] + ], + "description": "Unique identifier of the liquid to load. If this is the sentinel value EMPTY, all values of volumeByWell must be 0.", + "title": "Liquidid" }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", - "type": "string" + "volumeByWell": { + "additionalProperties": { + "type": "number" + }, + "description": "Volume of liquid, in \u00b5L, loaded into each well by name, in this labware. If the liquid id is the sentinel value EMPTY, all volumes must be 0.", + "title": "Volumebywell", + "type": "object" } }, - "required": ["labwareId", "wellName", "pipetteId"] + "required": ["liquidId", "labwareId", "volumeByWell"], + "title": "LoadLiquidParams", + "type": "object" }, - "MoveToWellCreate": { - "title": "MoveToWellCreate", - "description": "Move to well command creation request model.", - "type": "object", + "LoadModuleCreate": { + "description": "The model for a creation request for a load module command.", "properties": { "commandType": { + "const": "loadModule", + "default": "loadModule", + "enum": ["loadModule"], "title": "Commandtype", - "default": "moveToWell", - "enum": ["moveToWell"], "type": "string" }, - "params": { - "$ref": "#/definitions/MoveToWellParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/LoadModuleParams" } }, - "required": ["params"] + "required": ["params"], + "title": "LoadModuleCreate", + "type": "object" }, - "AddressableOffsetVector": { - "title": "AddressableOffsetVector", - "description": "Offset, in deck coordinates, from nominal to actual position of an addressable area.", - "type": "object", + "LoadModuleParams": { + "description": "Payload required to load a module.", "properties": { - "x": { - "title": "X", - "type": "number" + "location": { + "$ref": "#/$defs/DeckSlotLocation", + "description": "The location into which this module should be loaded.\n\nFor the Thermocycler Module, which occupies multiple deck slots, this should be the front-most occupied slot (normally slot 7)." }, - "y": { - "title": "Y", - "type": "number" + "model": { + "$ref": "#/$defs/ModuleModel", + "description": "The model name of the module to load.\n\nProtocol Engine will look for a connected module that either exactly matches this one, or is compatible.\n\n For example, if you request a `temperatureModuleV1` here, Protocol Engine might load a `temperatureModuleV1` or a `temperatureModuleV2`.\n\n The model that it finds connected will be available through `result.model`." }, - "z": { - "title": "Z", - "type": "number" + "moduleId": { + "description": "An optional ID to assign to this module. If None, an ID will be generated.", + "title": "Moduleid", + "type": "string" } }, - "required": ["x", "y", "z"] + "required": ["model", "location"], + "title": "LoadModuleParams", + "type": "object" }, - "MoveToAddressableAreaParams": { - "title": "MoveToAddressableAreaParams", - "description": "Payload required to move a pipette to a specific addressable area.\n\nAn *addressable area* is a space in the robot that may or may not be usable depending on how\nthe robot's deck is configured. For example, if a Flex is configured with a waste chute, it will\nhave additional addressable areas representing the opening of the waste chute, where tips and\nlabware can be dropped.\n\nThis moves the pipette so all of its nozzles are centered over the addressable area.\nIf the pipette is currently configured with a partial tip layout, this centering is over all\nthe pipette's physical nozzles, not just the nozzles that are active.\n\nThe z-position will be chosen to put the bottom of the tips---or the bottom of the nozzles,\nif there are no tips---level with the top of the addressable area.\n\nWhen this command is executed, Protocol Engine will make sure the robot's deck is configured\nsuch that the requested addressable area actually exists. For example, if you request\nthe addressable area B4, it will make sure the robot is set up with a B3/B4 staging area slot.\nIf that's not the case, the command will fail.", - "type": "object", + "LoadPipetteCreate": { + "description": "Load pipette command creation request model.", "properties": { - "minimumZHeight": { - "title": "Minimumzheight", - "description": "Optional minimal Z margin in mm. If this is larger than the API's default safe Z margin, it will make the arc higher. If it's smaller, it will have no effect.", - "type": "number" + "commandType": { + "const": "loadPipette", + "default": "loadPipette", + "enum": ["loadPipette"], + "title": "Commandtype", + "type": "string" }, - "forceDirect": { - "title": "Forcedirect", - "description": "If true, moving from one labware/well to another will not arc to the default safe z, but instead will move directly to the specified location. This will also force the `minimumZHeight` param to be ignored. A 'direct' movement is in X/Y/Z simultaneously.", - "default": false, + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" + }, + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", + "type": "string" + }, + "params": { + "$ref": "#/$defs/LoadPipetteParams" + } + }, + "required": ["params"], + "title": "LoadPipetteCreate", + "type": "object" + }, + "LoadPipetteParams": { + "description": "Payload needed to load a pipette on to a mount.", + "properties": { + "liquidPresenceDetection": { + "description": "Enable liquid presence detection for this pipette. Defaults to False.", + "title": "Liquidpresencedetection", "type": "boolean" }, - "speed": { - "title": "Speed", - "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", - "type": "number" + "mount": { + "$ref": "#/$defs/MountType", + "description": "The mount the pipette should be present on." }, "pipetteId": { + "description": "An optional ID to assign to this pipette. If None, an ID will be generated.", "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", "type": "string" }, - "addressableAreaName": { - "title": "Addressableareaname", - "description": "The name of the addressable area that you want to use. Valid values are the `id`s of `addressableArea`s in the [deck definition](https://github.com/Opentrons/opentrons/tree/edge/shared-data/deck).", + "pipetteName": { + "$ref": "#/$defs/PipetteNameType", + "description": "The load name of the pipette to be required." + }, + "tipOverlapNotAfterVersion": { + "description": "A version of tip overlap data to not exceed. The highest-versioned tip overlap data that does not exceed this version will be used. Versions are expressed as vN where N is an integer, counting up from v0. If None, the current highest version will be used.", + "title": "Tipoverlapnotafterversion", "type": "string" + } + }, + "required": ["pipetteName", "mount"], + "title": "LoadPipetteParams", + "type": "object" + }, + "MaintenancePosition": { + "description": "Maintenance position options.", + "enum": ["attachPlate", "attachInstrument"], + "title": "MaintenancePosition", + "type": "string" + }, + "MixParams": { + "description": "Parameters for mix.", + "properties": { + "repetitions": { + "description": "Number of mixing repetitions.", + "minimum": 0, + "title": "Repetitions", + "type": "integer" }, - "offset": { - "title": "Offset", - "description": "Relative offset of addressable area to move pipette's critical point.", - "default": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "allOf": [ + "volume": { + "anyOf": [ + { + "type": "integer" + }, { - "$ref": "#/definitions/AddressableOffsetVector" + "type": "number" } - ] - }, - "stayAtHighestPossibleZ": { - "title": "Stayathighestpossiblez", - "description": "If `true`, the pipette will retract to its highest possible height and stay there instead of descending to the destination. `minimumZHeight` will be ignored.", - "default": false, + ], + "description": "Volume used for mixing, in microliters.", + "title": "Volume" + } + }, + "required": ["repetitions", "volume"], + "title": "MixParams", + "type": "object" + }, + "MixProperties": { + "description": "Mixing properties.", + "properties": { + "enable": { + "description": "Whether mix is enabled.", + "title": "Enable", "type": "boolean" + }, + "params": { + "$ref": "#/$defs/MixParams", + "description": "Parameters for the mix function.", + "title": "Params" } }, - "required": ["pipetteId", "addressableAreaName"] + "required": ["enable"], + "title": "MixProperties", + "type": "object" }, - "MoveToAddressableAreaCreate": { - "title": "MoveToAddressableAreaCreate", - "description": "Move to addressable area command creation request model.", - "type": "object", + "ModuleLocation": { + "description": "The location of something placed atop a hardware module.", + "properties": { + "moduleId": { + "description": "The ID of a loaded module from a prior `loadModule` command.", + "title": "Moduleid", + "type": "string" + } + }, + "required": ["moduleId"], + "title": "ModuleLocation", + "type": "object" + }, + "ModuleModel": { + "description": "All available modules' models.", + "enum": [ + "temperatureModuleV1", + "temperatureModuleV2", + "magneticModuleV1", + "magneticModuleV2", + "thermocyclerModuleV1", + "thermocyclerModuleV2", + "heaterShakerModuleV1", + "magneticBlockV1", + "absorbanceReaderV1" + ], + "title": "ModuleModel", + "type": "string" + }, + "MotorAxis": { + "description": "Motor axis on which to issue a home command.", + "enum": [ + "x", + "y", + "leftZ", + "rightZ", + "leftPlunger", + "rightPlunger", + "extensionZ", + "extensionJaw", + "axis96ChannelCam" + ], + "title": "MotorAxis", + "type": "string" + }, + "MountType": { + "enum": ["left", "right", "extension"], + "title": "MountType", + "type": "string" + }, + "MoveAxesRelativeCreate": { + "description": "MoveAxesRelative command request model.", "properties": { "commandType": { + "const": "robot/moveAxesRelative", + "default": "robot/moveAxesRelative", + "enum": ["robot/moveAxesRelative"], "title": "Commandtype", - "default": "moveToAddressableArea", - "enum": ["moveToAddressableArea"], "type": "string" }, - "params": { - "$ref": "#/definitions/MoveToAddressableAreaParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/MoveAxesRelativeParams" } }, - "required": ["params"] + "required": ["params"], + "title": "MoveAxesRelativeCreate", + "type": "object" }, - "MoveToAddressableAreaForDropTipParams": { - "title": "MoveToAddressableAreaForDropTipParams", - "description": "Payload required to move a pipette to a specific addressable area.\n\nAn *addressable area* is a space in the robot that may or may not be usable depending on how\nthe robot's deck is configured. For example, if a Flex is configured with a waste chute, it will\nhave additional addressable areas representing the opening of the waste chute, where tips and\nlabware can be dropped.\n\nThis moves the pipette so all of its nozzles are centered over the addressable area.\nIf the pipette is currently configured with a partial tip layout, this centering is over all\nthe pipette's physical nozzles, not just the nozzles that are active.\n\nThe z-position will be chosen to put the bottom of the tips---or the bottom of the nozzles,\nif there are no tips---level with the top of the addressable area.\n\nWhen this command is executed, Protocol Engine will make sure the robot's deck is configured\nsuch that the requested addressable area actually exists. For example, if you request\nthe addressable area B4, it will make sure the robot is set up with a B3/B4 staging area slot.\nIf that's not the case, the command will fail.", - "type": "object", + "MoveAxesRelativeParams": { + "description": "Payload required to move axes relative to position.", "properties": { - "minimumZHeight": { - "title": "Minimumzheight", - "description": "Optional minimal Z margin in mm. If this is larger than the API's default safe Z margin, it will make the arc higher. If it's smaller, it will have no effect.", - "type": "number" - }, - "forceDirect": { - "title": "Forcedirect", - "description": "If true, moving from one labware/well to another will not arc to the default safe z, but instead will move directly to the specified location. This will also force the `minimumZHeight` param to be ignored. A 'direct' movement is in X/Y/Z simultaneously.", - "default": false, - "type": "boolean" + "axis_map": { + "additionalProperties": { + "type": "number" + }, + "description": "A dictionary mapping axes to relative movements in mm.", + "title": "Axis Map", + "type": "object" }, "speed": { + "description": "The max velocity to move the axes at. Will fall to hardware defaults if none provided.", "title": "Speed", - "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", "type": "number" - }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", - "type": "string" - }, - "addressableAreaName": { - "title": "Addressableareaname", - "description": "The name of the addressable area that you want to use. Valid values are the `id`s of `addressableArea`s in the [deck definition](https://github.com/Opentrons/opentrons/tree/edge/shared-data/deck).", - "type": "string" - }, - "offset": { - "title": "Offset", - "description": "Relative offset of addressable area to move pipette's critical point.", - "default": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "allOf": [ - { - "$ref": "#/definitions/AddressableOffsetVector" - } - ] - }, - "alternateDropLocation": { - "title": "Alternatedroplocation", - "description": "Whether to alternate location where tip is dropped within the addressable area. If True, this command will ignore the offset provided and alternate between dropping tips at two predetermined locations inside the specified labware well. If False, the tip will be dropped at the top center of the area.", - "default": false, - "type": "boolean" - }, - "ignoreTipConfiguration": { - "title": "Ignoretipconfiguration", - "description": "Whether to utilize the critical point of the tip configuraiton when moving to an addressable area. If True, this command will ignore the tip configuration and use the center of the entire instrument as the critical point for movement. If False, this command will use the critical point provided by the current tip configuration.", - "default": true, - "type": "boolean" } }, - "required": ["pipetteId", "addressableAreaName"] + "required": ["axis_map"], + "title": "MoveAxesRelativeParams", + "type": "object" }, - "MoveToAddressableAreaForDropTipCreate": { - "title": "MoveToAddressableAreaForDropTipCreate", - "description": "Move to addressable area for drop tip command creation request model.", - "type": "object", + "MoveAxesToCreate": { + "description": "MoveAxesTo command request model.", "properties": { "commandType": { + "const": "robot/moveAxesTo", + "default": "robot/moveAxesTo", + "enum": ["robot/moveAxesTo"], "title": "Commandtype", - "default": "moveToAddressableAreaForDropTip", - "enum": ["moveToAddressableAreaForDropTip"], "type": "string" }, - "params": { - "$ref": "#/definitions/MoveToAddressableAreaForDropTipParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/MoveAxesToParams" } }, - "required": ["params"] + "required": ["params"], + "title": "MoveAxesToCreate", + "type": "object" }, - "PrepareToAspirateParams": { - "title": "PrepareToAspirateParams", - "description": "Parameters required to prepare a specific pipette for aspiration.", - "type": "object", + "MoveAxesToParams": { + "description": "Payload required to move axes to absolute position.", "properties": { - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", - "type": "string" + "axis_map": { + "additionalProperties": { + "type": "number" + }, + "description": "The specified axes to move to an absolute deck position with.", + "title": "Axis Map", + "type": "object" + }, + "critical_point": { + "additionalProperties": { + "type": "number" + }, + "description": "The critical point to move the mount with.", + "title": "Critical Point", + "type": "object" + }, + "speed": { + "description": "The max velocity to move the axes at. Will fall to hardware defaults if none provided.", + "title": "Speed", + "type": "number" } }, - "required": ["pipetteId"] + "required": ["axis_map"], + "title": "MoveAxesToParams", + "type": "object" }, - "PrepareToAspirateCreate": { - "title": "PrepareToAspirateCreate", - "description": "Prepare for aspirate command creation request model.", - "type": "object", + "MoveLabwareCreate": { + "description": "A request to create a ``moveLabware`` command.", "properties": { "commandType": { + "const": "moveLabware", + "default": "moveLabware", + "enum": ["moveLabware"], "title": "Commandtype", - "default": "prepareToAspirate", - "enum": ["prepareToAspirate"], "type": "string" }, - "params": { - "$ref": "#/definitions/PrepareToAspirateParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/MoveLabwareParams" } }, - "required": ["params"] - }, - "WaitForResumeParams": { - "title": "WaitForResumeParams", - "description": "Payload required to pause the protocol.", - "type": "object", - "properties": { - "message": { - "title": "Message", - "description": "A user-facing message associated with the pause", - "type": "string" - } - } + "required": ["params"], + "title": "MoveLabwareCreate", + "type": "object" }, - "WaitForResumeCreate": { - "title": "WaitForResumeCreate", - "description": "Wait for resume command request model.", - "type": "object", + "MoveLabwareParams": { + "description": "Input parameters for a ``moveLabware`` command.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "waitForResume", - "enum": ["waitForResume", "pause"], - "type": "string" + "dropOffset": { + "$ref": "#/$defs/LabwareOffsetVector", + "description": "Offset to use when dropping off labware. Experimental param, subject to change", + "title": "Dropoffset" }, - "params": { - "$ref": "#/definitions/WaitForResumeParams" + "labwareId": { + "description": "The ID of the labware to move.", + "title": "Labwareid", + "type": "string" }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ + "newLocation": { + "anyOf": [ + { + "$ref": "#/$defs/DeckSlotLocation" + }, + { + "$ref": "#/$defs/ModuleLocation" + }, { - "$ref": "#/definitions/CommandIntent" + "$ref": "#/$defs/OnLabwareLocation" + }, + { + "const": "offDeck", + "enum": ["offDeck"], + "type": "string" + }, + { + "$ref": "#/$defs/AddressableAreaLocation" } - ] + ], + "description": "Where to move the labware.", + "title": "Newlocation" }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" - } - }, - "required": ["params"] - }, - "WaitForDurationParams": { - "title": "WaitForDurationParams", - "description": "Payload required to pause the protocol.", - "type": "object", - "properties": { - "seconds": { - "title": "Seconds", - "description": "Duration, in seconds, to wait for.", - "type": "number" + "pickUpOffset": { + "$ref": "#/$defs/LabwareOffsetVector", + "description": "Offset to use when picking up labware. Experimental param, subject to change", + "title": "Pickupoffset" }, - "message": { - "title": "Message", - "description": "A user-facing message associated with the pause", - "type": "string" + "strategy": { + "$ref": "#/$defs/LabwareMovementStrategy", + "description": "Whether to use the gripper to perform the labware movement or to perform a manual movement with an option to pause." } }, - "required": ["seconds"] + "required": ["labwareId", "newLocation", "strategy"], + "title": "MoveLabwareParams", + "type": "object" }, - "WaitForDurationCreate": { - "title": "WaitForDurationCreate", - "description": "Wait for duration command request model.", - "type": "object", + "MoveRelativeCreate": { + "description": "Data to create a MoveRelative command.", "properties": { "commandType": { + "const": "moveRelative", + "default": "moveRelative", + "enum": ["moveRelative"], "title": "Commandtype", - "default": "waitForDuration", - "enum": ["waitForDuration"], "type": "string" }, - "params": { - "$ref": "#/definitions/WaitForDurationParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" - } - }, - "required": ["params"] - }, - "PickUpTipWellOrigin": { - "title": "PickUpTipWellOrigin", - "description": "The origin of a PickUpTipWellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well", - "enum": ["top", "bottom", "center"], - "type": "string" - }, - "PickUpTipWellLocation": { - "title": "PickUpTipWellLocation", - "description": "A relative location in reference to a well's location.\n\nTo be used for picking up tips.", - "type": "object", - "properties": { - "origin": { - "default": "top", - "allOf": [ - { - "$ref": "#/definitions/PickUpTipWellOrigin" - } - ] }, - "offset": { - "$ref": "#/definitions/WellOffset" + "params": { + "$ref": "#/$defs/MoveRelativeParams" } - } + }, + "required": ["params"], + "title": "MoveRelativeCreate", + "type": "object" }, - "PickUpTipParams": { - "title": "PickUpTipParams", - "description": "Payload needed to move a pipette to a specific well.", - "type": "object", + "MoveRelativeParams": { + "description": "Payload required for a MoveRelative command.", "properties": { - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", - "type": "string" - }, - "labwareId": { - "title": "Labwareid", - "description": "Identifier of labware to use.", - "type": "string" + "axis": { + "$ref": "#/$defs/MovementAxis", + "description": "Axis along which to move." }, - "wellName": { - "title": "Wellname", - "description": "Name of well to use in labware.", - "type": "string" + "distance": { + "description": "Distance to move in millimeters. A positive number will move towards the right (x), back (y), top (z) of the deck.", + "title": "Distance", + "type": "number" }, - "wellLocation": { - "title": "Welllocation", - "description": "Relative well location at which to pick up the tip.", - "allOf": [ - { - "$ref": "#/definitions/PickUpTipWellLocation" - } - ] + "pipetteId": { + "description": "Pipette to move.", + "title": "Pipetteid", + "type": "string" } }, - "required": ["pipetteId", "labwareId", "wellName"] + "required": ["pipetteId", "axis", "distance"], + "title": "MoveRelativeParams", + "type": "object" }, - "PickUpTipCreate": { - "title": "PickUpTipCreate", - "description": "Pick up tip command creation request model.", - "type": "object", + "MoveToAddressableAreaCreate": { + "description": "Move to addressable area command creation request model.", "properties": { "commandType": { + "const": "moveToAddressableArea", + "default": "moveToAddressableArea", + "enum": ["moveToAddressableArea"], "title": "Commandtype", - "default": "pickUpTip", - "enum": ["pickUpTip"], "type": "string" }, - "params": { - "$ref": "#/definitions/PickUpTipParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/MoveToAddressableAreaParams" } }, - "required": ["params"] + "required": ["params"], + "title": "MoveToAddressableAreaCreate", + "type": "object" }, - "SavePositionParams": { - "title": "SavePositionParams", - "description": "Payload needed to save a pipette's current position.", - "type": "object", + "MoveToAddressableAreaForDropTipCreate": { + "description": "Move to addressable area for drop tip command creation request model.", "properties": { - "pipetteId": { - "title": "Pipetteid", - "description": "Unique identifier of the pipette in question.", + "commandType": { + "const": "moveToAddressableAreaForDropTip", + "default": "moveToAddressableAreaForDropTip", + "enum": ["moveToAddressableAreaForDropTip"], + "title": "Commandtype", "type": "string" }, - "positionId": { - "title": "Positionid", - "description": "An optional ID to assign to this command instance. Auto-assigned if not defined.", + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" + }, + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" }, - "failOnNotHomed": { - "title": "Failonnothomed", - "default": true, - "descrption": "Require all axes to be homed before saving position.", - "type": "boolean" + "params": { + "$ref": "#/$defs/MoveToAddressableAreaForDropTipParams" } }, - "required": ["pipetteId"] + "required": ["params"], + "title": "MoveToAddressableAreaForDropTipCreate", + "type": "object" }, - "SavePositionCreate": { - "title": "SavePositionCreate", - "description": "Save position command creation request model.", - "type": "object", + "MoveToAddressableAreaForDropTipParams": { + "description": "Payload required to move a pipette to a specific addressable area.\n\nAn *addressable area* is a space in the robot that may or may not be usable depending on how\nthe robot's deck is configured. For example, if a Flex is configured with a waste chute, it will\nhave additional addressable areas representing the opening of the waste chute, where tips and\nlabware can be dropped.\n\nThis moves the pipette so all of its nozzles are centered over the addressable area.\nIf the pipette is currently configured with a partial tip layout, this centering is over all\nthe pipette's physical nozzles, not just the nozzles that are active.\n\nThe z-position will be chosen to put the bottom of the tips---or the bottom of the nozzles,\nif there are no tips---level with the top of the addressable area.\n\nWhen this command is executed, Protocol Engine will make sure the robot's deck is configured\nsuch that the requested addressable area actually exists. For example, if you request\nthe addressable area B4, it will make sure the robot is set up with a B3/B4 staging area slot.\nIf that's not the case, the command will fail.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "savePosition", - "enum": ["savePosition"], + "addressableAreaName": { + "description": "The name of the addressable area that you want to use. Valid values are the `id`s of `addressableArea`s in the [deck definition](https://github.com/Opentrons/opentrons/tree/edge/shared-data/deck).", + "title": "Addressableareaname", "type": "string" }, - "params": { - "$ref": "#/definitions/SavePositionParams" + "alternateDropLocation": { + "description": "Whether to alternate location where tip is dropped within the addressable area. If True, this command will ignore the offset provided and alternate between dropping tips at two predetermined locations inside the specified labware well. If False, the tip will be dropped at the top center of the area.", + "title": "Alternatedroplocation", + "type": "boolean" }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "forceDirect": { + "default": false, + "description": "If true, moving from one labware/well to another will not arc to the default safe z, but instead will move directly to the specified location. This will also force the `minimumZHeight` param to be ignored. A 'direct' movement is in X/Y/Z simultaneously.", + "title": "Forcedirect", + "type": "boolean" }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "ignoreTipConfiguration": { + "description": "Whether to utilize the critical point of the tip configuraiton when moving to an addressable area. If True, this command will ignore the tip configuration and use the center of the entire instrument as the critical point for movement. If False, this command will use the critical point provided by the current tip configuration.", + "title": "Ignoretipconfiguration", + "type": "boolean" + }, + "minimumZHeight": { + "description": "Optional minimal Z margin in mm. If this is larger than the API's default safe Z margin, it will make the arc higher. If it's smaller, it will have no effect.", + "title": "Minimumzheight", + "type": "number" + }, + "offset": { + "$ref": "#/$defs/AddressableOffsetVector", + "default": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "description": "Relative offset of addressable area to move pipette's critical point." + }, + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" + }, + "speed": { + "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", + "title": "Speed", + "type": "number" } }, - "required": ["params"] + "required": ["pipetteId", "addressableAreaName"], + "title": "MoveToAddressableAreaForDropTipParams", + "type": "object" }, - "SetRailLightsParams": { - "title": "SetRailLightsParams", - "description": "Payload required to set the rail lights on or off.", - "type": "object", + "MoveToAddressableAreaParams": { + "description": "Payload required to move a pipette to a specific addressable area.\n\nAn *addressable area* is a space in the robot that may or may not be usable depending on how\nthe robot's deck is configured. For example, if a Flex is configured with a waste chute, it will\nhave additional addressable areas representing the opening of the waste chute, where tips and\nlabware can be dropped.\n\nThis moves the pipette so all of its nozzles are centered over the addressable area.\nIf the pipette is currently configured with a partial tip layout, this centering is over all\nthe pipette's physical nozzles, not just the nozzles that are active.\n\nThe z-position will be chosen to put the bottom of the tips---or the bottom of the nozzles,\nif there are no tips---level with the top of the addressable area.\n\nWhen this command is executed, Protocol Engine will make sure the robot's deck is configured\nsuch that the requested addressable area actually exists. For example, if you request\nthe addressable area B4, it will make sure the robot is set up with a B3/B4 staging area slot.\nIf that's not the case, the command will fail.", "properties": { - "on": { - "title": "On", - "description": "The field that determines if the light is turned off or on.", + "addressableAreaName": { + "description": "The name of the addressable area that you want to use. Valid values are the `id`s of `addressableArea`s in the [deck definition](https://github.com/Opentrons/opentrons/tree/edge/shared-data/deck).", + "title": "Addressableareaname", + "type": "string" + }, + "forceDirect": { + "default": false, + "description": "If true, moving from one labware/well to another will not arc to the default safe z, but instead will move directly to the specified location. This will also force the `minimumZHeight` param to be ignored. A 'direct' movement is in X/Y/Z simultaneously.", + "title": "Forcedirect", + "type": "boolean" + }, + "minimumZHeight": { + "description": "Optional minimal Z margin in mm. If this is larger than the API's default safe Z margin, it will make the arc higher. If it's smaller, it will have no effect.", + "title": "Minimumzheight", + "type": "number" + }, + "offset": { + "$ref": "#/$defs/AddressableOffsetVector", + "default": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "description": "Relative offset of addressable area to move pipette's critical point." + }, + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", + "type": "string" + }, + "speed": { + "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", + "title": "Speed", + "type": "number" + }, + "stayAtHighestPossibleZ": { + "default": false, + "description": "If `true`, the pipette will retract to its highest possible height and stay there instead of descending to the destination. `minimumZHeight` will be ignored.", + "title": "Stayathighestpossiblez", "type": "boolean" } }, - "required": ["on"] + "required": ["pipetteId", "addressableAreaName"], + "title": "MoveToAddressableAreaParams", + "type": "object" }, - "SetRailLightsCreate": { - "title": "SetRailLightsCreate", - "description": "setRailLights command request model.", - "type": "object", + "MoveToCoordinatesCreate": { + "description": "Move to coordinates command creation request model.", "properties": { "commandType": { + "const": "moveToCoordinates", + "default": "moveToCoordinates", + "enum": ["moveToCoordinates"], "title": "Commandtype", - "default": "setRailLights", - "enum": ["setRailLights"], "type": "string" }, - "params": { - "$ref": "#/definitions/SetRailLightsParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/MoveToCoordinatesParams" } }, - "required": ["params"] + "required": ["params"], + "title": "MoveToCoordinatesCreate", + "type": "object" }, - "TouchTipParams": { - "title": "TouchTipParams", - "description": "Payload needed to touch a pipette tip the sides of a specific well.", - "type": "object", + "MoveToCoordinatesParams": { + "description": "Payload required to move a pipette to coordinates.", "properties": { - "labwareId": { - "title": "Labwareid", - "description": "Identifier of labware to use.", - "type": "string" + "coordinates": { + "$ref": "#/$defs/DeckPoint", + "description": "X, Y and Z coordinates in mm from deck's origin location (left-front-bottom corner of work space)" }, - "wellName": { - "title": "Wellname", - "description": "Name of well to use in labware.", - "type": "string" + "forceDirect": { + "default": false, + "description": "If true, moving from one labware/well to another will not arc to the default safe z, but instead will move directly to the specified location. This will also force the `minimumZHeight` param to be ignored. A 'direct' movement is in X/Y/Z simultaneously.", + "title": "Forcedirect", + "type": "boolean" }, - "wellLocation": { - "title": "Welllocation", - "description": "Relative well location at which to perform the operation", - "allOf": [ - { - "$ref": "#/definitions/WellLocation" - } - ] + "minimumZHeight": { + "description": "Optional minimal Z margin in mm. If this is larger than the API's default safe Z margin, it will make the arc higher. If it's smaller, it will have no effect.", + "title": "Minimumzheight", + "type": "number" }, "pipetteId": { - "title": "Pipetteid", "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" }, - "radius": { - "title": "Radius", - "description": "The proportion of the target well's radius the pipette tip will move towards.", - "default": 1.0, - "type": "number" - }, - "mmFromEdge": { - "title": "Mmfromedge", - "description": "Offset away from the the well edge, in millimeters.Incompatible when a radius is included as a non 1.0 value.", - "type": "number" - }, "speed": { - "title": "Speed", "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", + "title": "Speed", "type": "number" } }, - "required": ["labwareId", "wellName", "pipetteId"] + "required": ["pipetteId", "coordinates"], + "title": "MoveToCoordinatesParams", + "type": "object" }, - "TouchTipCreate": { - "title": "TouchTipCreate", - "description": "Touch tip command creation request model.", - "type": "object", + "MoveToCreate": { + "description": "MoveTo command request model.", "properties": { "commandType": { + "const": "robot/moveTo", + "default": "robot/moveTo", + "enum": ["robot/moveTo"], "title": "Commandtype", - "default": "touchTip", - "enum": ["touchTip"], + "type": "string" + }, + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" + }, + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" }, "params": { - "$ref": "#/definitions/TouchTipParams" + "$ref": "#/$defs/MoveToParams" + } + }, + "required": ["params"], + "title": "MoveToCreate", + "type": "object" + }, + "MoveToMaintenancePositionCreate": { + "description": "Calibration set up position command creation request model.", + "properties": { + "commandType": { + "const": "calibration/moveToMaintenancePosition", + "default": "calibration/moveToMaintenancePosition", + "enum": ["calibration/moveToMaintenancePosition"], + "title": "Commandtype", + "type": "string" }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/MoveToMaintenancePositionParams" + } + }, + "required": ["params"], + "title": "MoveToMaintenancePositionCreate", + "type": "object" + }, + "MoveToMaintenancePositionParams": { + "description": "Calibration set up position command parameters.", + "properties": { + "maintenancePosition": { + "$ref": "#/$defs/MaintenancePosition", + "default": "attachInstrument", + "description": "The position the gantry mount needs to move to." + }, + "mount": { + "$ref": "#/$defs/MountType", + "description": "Gantry mount to move maintenance position." } }, - "required": ["params"] - }, - "StatusBarAnimation": { - "title": "StatusBarAnimation", - "description": "Status Bar animation options.", - "enum": ["idle", "confirm", "updating", "disco", "off"] + "required": ["mount"], + "title": "MoveToMaintenancePositionParams", + "type": "object" }, - "SetStatusBarParams": { - "title": "SetStatusBarParams", - "description": "Payload required to set the status bar to run an animation.", - "type": "object", + "MoveToParams": { + "description": "Payload required to move to a destination position.", "properties": { - "animation": { - "description": "The animation that should be executed on the status bar.", - "allOf": [ - { - "$ref": "#/definitions/StatusBarAnimation" - } - ] + "destination": { + "$ref": "#/$defs/DeckPoint", + "description": "X, Y and Z coordinates in mm from deck's origin location (left-front-bottom corner of work space)" + }, + "mount": { + "$ref": "#/$defs/MountType", + "description": "The mount to move to the destination point." + }, + "speed": { + "description": "The max velocity to move the axes at. Will fall to hardware defaults if none provided.", + "title": "Speed", + "type": "number" } }, - "required": ["animation"] + "required": ["mount", "destination"], + "title": "MoveToParams", + "type": "object" }, - "SetStatusBarCreate": { - "title": "SetStatusBarCreate", - "description": "setStatusBar command request model.", - "type": "object", + "MoveToWellCreate": { + "description": "Move to well command creation request model.", "properties": { "commandType": { + "const": "moveToWell", + "default": "moveToWell", + "enum": ["moveToWell"], "title": "Commandtype", - "default": "setStatusBar", - "enum": ["setStatusBar"], "type": "string" }, - "params": { - "$ref": "#/definitions/SetStatusBarParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/MoveToWellParams" } }, - "required": ["params"] - }, - "TipPresenceStatus": { - "title": "TipPresenceStatus", - "description": "Tip presence status reported by a pipette.", - "enum": ["present", "absent", "unknown"], - "type": "string" - }, - "InstrumentSensorId": { - "title": "InstrumentSensorId", - "description": "Primary and secondary sensor ids.", - "enum": ["primary", "secondary", "both"], - "type": "string" + "required": ["params"], + "title": "MoveToWellCreate", + "type": "object" }, - "VerifyTipPresenceParams": { - "title": "VerifyTipPresenceParams", - "description": "Payload required for a VerifyTipPresence command.", - "type": "object", + "MoveToWellParams": { + "description": "Payload required to move a pipette to a specific well.", "properties": { + "forceDirect": { + "default": false, + "description": "If true, moving from one labware/well to another will not arc to the default safe z, but instead will move directly to the specified location. This will also force the `minimumZHeight` param to be ignored. A 'direct' movement is in X/Y/Z simultaneously.", + "title": "Forcedirect", + "type": "boolean" + }, + "labwareId": { + "description": "Identifier of labware to use.", + "title": "Labwareid", + "type": "string" + }, + "minimumZHeight": { + "description": "Optional minimal Z margin in mm. If this is larger than the API's default safe Z margin, it will make the arc higher. If it's smaller, it will have no effect.", + "title": "Minimumzheight", + "type": "number" + }, "pipetteId": { - "title": "Pipetteid", "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" }, - "expectedState": { - "description": "The expected tip presence status on the pipette.", - "allOf": [ - { - "$ref": "#/definitions/TipPresenceStatus" - } - ] + "speed": { + "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", + "title": "Speed", + "type": "number" }, - "followSingularSensor": { - "description": "The sensor id to follow if the other can be ignored.", - "allOf": [ - { - "$ref": "#/definitions/InstrumentSensorId" - } - ] + "wellLocation": { + "$ref": "#/$defs/WellLocation", + "description": "Relative well location at which to perform the operation" + }, + "wellName": { + "description": "Name of well to use in labware.", + "title": "Wellname", + "type": "string" } }, - "required": ["pipetteId", "expectedState"] + "required": ["labwareId", "wellName", "pipetteId"], + "title": "MoveToWellParams", + "type": "object" }, - "VerifyTipPresenceCreate": { - "title": "VerifyTipPresenceCreate", - "description": "VerifyTipPresence command creation request model.", - "type": "object", + "MovementAxis": { + "description": "Axis on which to issue a relative movement.", + "enum": ["x", "y", "z"], + "title": "MovementAxis", + "type": "string" + }, + "MultiDispenseProperties": { + "description": "Properties specific to the multi-dispense function.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "verifyTipPresence", - "enum": ["verifyTipPresence"], - "type": "string" + "conditioningByVolume": { + "description": "Settings for conditioning volume keyed by target dispense volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Conditioningbyvolume", + "type": "array" }, - "params": { - "$ref": "#/definitions/VerifyTipPresenceParams" + "correctionByVolume": { + "description": "Settings for volume correction keyed by by target dispense volume, representing additional volume the plunger should move to accurately hit target volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Correctionbyvolume", + "type": "array" }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "delay": { + "$ref": "#/$defs/DelayProperties", + "description": "Delay settings after each dispense" }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" + "disposalByVolume": { + "description": "Settings for disposal volume keyed by target dispense volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Disposalbyvolume", + "type": "array" + }, + "flowRateByVolume": { + "description": "Settings for flow rate keyed by target dispense volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Flowratebyvolume", + "type": "array" + }, + "offset": { + "$ref": "#/$defs/Coordinate", + "description": "Relative offset for single multi-dispense." + }, + "positionReference": { + "$ref": "#/$defs/PositionReference", + "description": "Position reference for multi-dispense." + }, + "retract": { + "$ref": "#/$defs/RetractDispense", + "description": "Pipette retract settings after a multi-dispense." + }, + "submerge": { + "$ref": "#/$defs/Submerge", + "description": "Submerge settings for multi-dispense." } }, - "required": ["params"] + "required": [ + "submerge", + "retract", + "positionReference", + "offset", + "flowRateByVolume", + "correctionByVolume", + "conditioningByVolume", + "disposalByVolume", + "delay" + ], + "title": "MultiDispenseProperties", + "type": "object" }, - "GetTipPresenceParams": { - "title": "GetTipPresenceParams", - "description": "Payload required for a GetTipPresence command.", - "type": "object", + "OnLabwareLocation": { + "description": "The location of something placed atop another labware.", "properties": { - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", + "labwareId": { + "description": "The ID of a loaded Labware from a prior `loadLabware` command.", + "title": "Labwareid", "type": "string" } }, - "required": ["pipetteId"] + "required": ["labwareId"], + "title": "OnLabwareLocation", + "type": "object" }, - "GetTipPresenceCreate": { - "title": "GetTipPresenceCreate", - "description": "GetTipPresence command creation request model.", - "type": "object", + "OpenLabwareLatchCreate": { + "description": "A request to create a Heater-Shaker's open labware latch command.", "properties": { "commandType": { + "const": "heaterShaker/openLabwareLatch", + "default": "heaterShaker/openLabwareLatch", + "enum": ["heaterShaker/openLabwareLatch"], "title": "Commandtype", - "default": "getTipPresence", - "enum": ["getTipPresence"], "type": "string" }, - "params": { - "$ref": "#/definitions/GetTipPresenceParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/OpenLabwareLatchParams" } }, - "required": ["params"] + "required": ["params"], + "title": "OpenLabwareLatchCreate", + "type": "object" }, - "GetNextTipParams": { - "title": "GetNextTipParams", - "description": "Payload needed to resolve the next available tip.", - "type": "object", + "OpenLabwareLatchParams": { + "description": "Input parameters to open a Heater-Shaker Module's labware latch.", "properties": { - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", - "type": "string" - }, - "labwareIds": { - "title": "Labwareids", - "description": "Labware ID(s) of tip racks to resolve next available tip(s) from Labware IDs will be resolved sequentially", - "type": "array", - "items": { - "type": "string" - } - }, - "startingTipWell": { - "title": "Startingtipwell", - "description": "Name of starting tip rack 'well'. This only applies to the first tip rack in the list provided in labwareIDs", + "moduleId": { + "description": "Unique ID of the Heater-Shaker Module.", + "title": "Moduleid", "type": "string" } }, - "required": ["pipetteId", "labwareIds"] + "required": ["moduleId"], + "title": "OpenLabwareLatchParams", + "type": "object" }, - "GetNextTipCreate": { - "title": "GetNextTipCreate", - "description": "Get next tip command creation request model.", - "type": "object", + "PickUpTipCreate": { + "description": "Pick up tip command creation request model.", "properties": { "commandType": { + "const": "pickUpTip", + "default": "pickUpTip", + "enum": ["pickUpTip"], "title": "Commandtype", - "default": "getNextTip", - "enum": ["getNextTip"], "type": "string" }, - "params": { - "$ref": "#/definitions/GetNextTipParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/PickUpTipParams" } }, - "required": ["params"] + "required": ["params"], + "title": "PickUpTipCreate", + "type": "object" }, - "LiquidProbeParams": { - "title": "LiquidProbeParams", - "description": "Parameters required for a `liquidProbe` command.", - "type": "object", + "PickUpTipParams": { + "description": "Payload needed to move a pipette to a specific well.", "properties": { "labwareId": { - "title": "Labwareid", "description": "Identifier of labware to use.", + "title": "Labwareid", "type": "string" }, - "wellName": { - "title": "Wellname", - "description": "Name of well to use in labware.", - "type": "string" - }, - "wellLocation": { - "title": "Welllocation", - "description": "Relative well location at which to perform the operation", - "allOf": [ - { - "$ref": "#/definitions/WellLocation" - } - ] - }, "pipetteId": { - "title": "Pipetteid", "description": "Identifier of pipette to use for liquid handling.", - "type": "string" - } - }, - "required": ["labwareId", "wellName", "pipetteId"] - }, - "LiquidProbeCreate": { - "title": "LiquidProbeCreate", - "description": "The request model for a `liquidProbe` command.", - "type": "object", - "properties": { - "commandType": { - "title": "Commandtype", - "default": "liquidProbe", - "enum": ["liquidProbe"], + "title": "Pipetteid", "type": "string" }, - "params": { - "$ref": "#/definitions/LiquidProbeParams" - }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "wellLocation": { + "$ref": "#/$defs/PickUpTipWellLocation", + "description": "Relative well location at which to pick up the tip." }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "wellName": { + "description": "Name of well to use in labware.", + "title": "Wellname", "type": "string" } }, - "required": ["params"] + "required": ["pipetteId", "labwareId", "wellName"], + "title": "PickUpTipParams", + "type": "object" }, - "TryLiquidProbeParams": { - "title": "TryLiquidProbeParams", - "description": "Parameters required for a `tryLiquidProbe` command.", - "type": "object", + "PickUpTipWellLocation": { + "description": "A relative location in reference to a well's location.\n\nTo be used for picking up tips.", "properties": { - "labwareId": { - "title": "Labwareid", - "description": "Identifier of labware to use.", - "type": "string" - }, - "wellName": { - "title": "Wellname", - "description": "Name of well to use in labware.", - "type": "string" - }, - "wellLocation": { - "title": "Welllocation", - "description": "Relative well location at which to perform the operation", - "allOf": [ - { - "$ref": "#/definitions/WellLocation" - } - ] + "offset": { + "$ref": "#/$defs/WellOffset" }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", - "type": "string" + "origin": { + "$ref": "#/$defs/PickUpTipWellOrigin", + "default": "top" } }, - "required": ["labwareId", "wellName", "pipetteId"] + "title": "PickUpTipWellLocation", + "type": "object" }, - "TryLiquidProbeCreate": { - "title": "TryLiquidProbeCreate", - "description": "The request model for a `tryLiquidProbe` command.", - "type": "object", + "PickUpTipWellOrigin": { + "description": "The origin of a PickUpTipWellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well", + "enum": ["top", "bottom", "center"], + "title": "PickUpTipWellOrigin", + "type": "string" + }, + "PipetteNameType": { + "description": "Pipette load name values.", + "enum": [ + "p10_single", + "p10_multi", + "p20_single_gen2", + "p20_multi_gen2", + "p50_single", + "p50_multi", + "p50_single_flex", + "p50_multi_flex", + "p300_single", + "p300_multi", + "p300_single_gen2", + "p300_multi_gen2", + "p1000_single", + "p1000_single_gen2", + "p1000_single_flex", + "p1000_multi_flex", + "p1000_multi_em", + "p1000_96", + "p200_96" + ], + "title": "PipetteNameType", + "type": "string" + }, + "PositionReference": { + "description": "Positional reference for liquid handling operations.", + "enum": ["well-bottom", "well-top", "well-center", "liquid-meniscus"], + "title": "PositionReference", + "type": "string" + }, + "PrepareToAspirateCreate": { + "description": "Prepare for aspirate command creation request model.", "properties": { "commandType": { + "const": "prepareToAspirate", + "default": "prepareToAspirate", + "enum": ["prepareToAspirate"], "title": "Commandtype", - "default": "tryLiquidProbe", - "enum": ["tryLiquidProbe"], "type": "string" }, - "params": { - "$ref": "#/definitions/TryLiquidProbeParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/PrepareToAspirateParams" } }, - "required": ["params"] + "required": ["params"], + "title": "PrepareToAspirateCreate", + "type": "object" }, - "opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureParams": { - "title": "WaitForTemperatureParams", - "description": "Input parameters to wait for a Heater-Shaker's target temperature.", - "type": "object", + "PrepareToAspirateParams": { + "description": "Parameters required to prepare a specific pipette for aspiration.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Heater-Shaker Module.", + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" - }, - "celsius": { - "title": "Celsius", - "description": "Target temperature in \u00b0C. If not specified, will default to the module's target temperature. Specifying a celsius parameter other than the target temperature could lead to unpredictable behavior and hence is not recommended for use. This parameter can be removed in a future version without prior notice.", - "type": "number" } }, - "required": ["moduleId"] + "required": ["pipetteId"], + "title": "PrepareToAspirateParams", + "type": "object" }, - "opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureCreate": { - "title": "WaitForTemperatureCreate", - "description": "A request to create a Heater-Shaker's wait for temperature command.", - "type": "object", + "ProfileCycle": { + "description": "An individual cycle in a Thermocycler extended profile.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "heaterShaker/waitForTemperature", - "enum": ["heaterShaker/waitForTemperature"], - "type": "string" - }, - "params": { - "$ref": "#/definitions/opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureParams" - }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "repetitions": { + "description": "Number of times to repeat the steps.", + "title": "Repetitions", + "type": "integer" }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" + "steps": { + "description": "Steps to repeat.", + "items": { + "$ref": "#/$defs/ProfileStep" + }, + "title": "Steps", + "type": "array" } }, - "required": ["params"] + "required": ["steps", "repetitions"], + "title": "ProfileCycle", + "type": "object" }, - "opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureParams": { - "title": "SetTargetTemperatureParams", - "description": "Input parameters to set a Heater-Shaker's target temperature.", - "type": "object", + "ProfileStep": { + "description": "An individual step in a Thermocycler extended profile.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Heater-Shaker Module.", - "type": "string" - }, "celsius": { - "title": "Celsius", "description": "Target temperature in \u00b0C.", + "title": "Celsius", + "type": "number" + }, + "holdSeconds": { + "description": "Time to hold target temperature in seconds.", + "title": "Holdseconds", "type": "number" } }, - "required": ["moduleId", "celsius"] + "required": ["celsius", "holdSeconds"], + "title": "ProfileStep", + "type": "object" }, - "opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureCreate": { - "title": "SetTargetTemperatureCreate", - "description": "A request to create a Heater-Shaker's set temperature command.", - "type": "object", + "QuadrantNozzleLayoutConfiguration": { + "description": "Information required for nozzle configurations of type QUADRANT.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "heaterShaker/setTargetTemperature", - "enum": ["heaterShaker/setTargetTemperature"], + "backLeftNozzle": { + "description": "The back left nozzle in your configuration.", + "pattern": "[A-Z]\\d{1,2}", + "title": "Backleftnozzle", "type": "string" }, - "params": { - "$ref": "#/definitions/opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureParams" - }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "frontRightNozzle": { + "description": "The front right nozzle in your configuration.", + "pattern": "[A-Z]\\d{1,2}", + "title": "Frontrightnozzle", + "type": "string" }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "primaryNozzle": { + "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.", + "enum": ["A1", "H1", "A12", "H12"], + "title": "Primarynozzle", "type": "string" - } - }, - "required": ["params"] - }, - "DeactivateHeaterParams": { - "title": "DeactivateHeaterParams", - "description": "Input parameters to unset a Heater-Shaker's target temperature.", - "type": "object", - "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Heater-Shaker Module.", + }, + "style": { + "const": "QUADRANT", + "default": "QUADRANT", + "enum": ["QUADRANT"], + "title": "Style", "type": "string" } }, - "required": ["moduleId"] + "required": ["primaryNozzle", "frontRightNozzle", "backLeftNozzle"], + "title": "QuadrantNozzleLayoutConfiguration", + "type": "object" }, - "DeactivateHeaterCreate": { - "title": "DeactivateHeaterCreate", - "description": "A request to create a Heater-Shaker's deactivate heater command.", - "type": "object", + "ReadAbsorbanceCreate": { + "description": "A request to execute an Absorbance Reader measurement.", "properties": { "commandType": { + "const": "absorbanceReader/read", + "default": "absorbanceReader/read", + "enum": ["absorbanceReader/read"], "title": "Commandtype", - "default": "heaterShaker/deactivateHeater", - "enum": ["heaterShaker/deactivateHeater"], "type": "string" }, - "params": { - "$ref": "#/definitions/DeactivateHeaterParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/ReadAbsorbanceParams" } }, - "required": ["params"] + "required": ["params"], + "title": "ReadAbsorbanceCreate", + "type": "object" }, - "SetAndWaitForShakeSpeedParams": { - "title": "SetAndWaitForShakeSpeedParams", - "description": "Input parameters to set and wait for a shake speed for a Heater-Shaker Module.", - "type": "object", + "ReadAbsorbanceParams": { + "description": "Input parameters for an absorbance reading.", "properties": { + "fileName": { + "description": "Optional file name to use when storing the results of a measurement.", + "title": "Filename", + "type": "string" + }, "moduleId": { + "description": "Unique ID of the Absorbance Reader.", "title": "Moduleid", - "description": "Unique ID of the Heater-Shaker Module.", "type": "string" - }, - "rpm": { - "title": "Rpm", - "description": "Target speed in rotations per minute.", - "type": "number" } }, - "required": ["moduleId", "rpm"] + "required": ["moduleId"], + "title": "ReadAbsorbanceParams", + "type": "object" }, - "SetAndWaitForShakeSpeedCreate": { - "title": "SetAndWaitForShakeSpeedCreate", - "description": "A request to create a Heater-Shaker's set and wait for shake speed command.", - "type": "object", + "ReloadLabwareCreate": { + "description": "Reload labware command creation request.", "properties": { "commandType": { + "const": "reloadLabware", + "default": "reloadLabware", + "enum": ["reloadLabware"], "title": "Commandtype", - "default": "heaterShaker/setAndWaitForShakeSpeed", - "enum": ["heaterShaker/setAndWaitForShakeSpeed"], "type": "string" }, - "params": { - "$ref": "#/definitions/SetAndWaitForShakeSpeedParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/ReloadLabwareParams" } }, - "required": ["params"] + "required": ["params"], + "title": "ReloadLabwareCreate", + "type": "object" }, - "DeactivateShakerParams": { - "title": "DeactivateShakerParams", - "description": "Input parameters to deactivate shaker for a Heater-Shaker Module.", - "type": "object", + "ReloadLabwareParams": { + "description": "Payload required to load a labware into a slot.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Heater-Shaker Module.", + "labwareId": { + "description": "The already-loaded labware instance to update.", + "title": "Labwareid", "type": "string" } }, - "required": ["moduleId"] + "required": ["labwareId"], + "title": "ReloadLabwareParams", + "type": "object" }, - "DeactivateShakerCreate": { - "title": "DeactivateShakerCreate", - "description": "A request to create a Heater-Shaker's deactivate shaker command.", - "type": "object", + "RetractAspirate": { + "description": "Shared properties for the retract function after aspiration.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "heaterShaker/deactivateShaker", - "enum": ["heaterShaker/deactivateShaker"], - "type": "string" + "airGapByVolume": { + "description": "Settings for air gap keyed by target aspiration volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Airgapbyvolume", + "type": "array" }, - "params": { - "$ref": "#/definitions/DeactivateShakerParams" + "delay": { + "$ref": "#/$defs/DelayProperties", + "description": "Delay settings for retract after aspirate." }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ + "offset": { + "$ref": "#/$defs/Coordinate", + "description": "Relative offset for retract after aspirate." + }, + "positionReference": { + "$ref": "#/$defs/PositionReference", + "description": "Position reference for retract after aspirate." + }, + "speed": { + "anyOf": [ { - "$ref": "#/definitions/CommandIntent" + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" } - ] + ], + "description": "Speed of retraction, in millimeters per second.", + "title": "Speed" }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" - } - }, - "required": ["params"] - }, - "OpenLabwareLatchParams": { - "title": "OpenLabwareLatchParams", - "description": "Input parameters to open a Heater-Shaker Module's labware latch.", - "type": "object", - "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Heater-Shaker Module.", - "type": "string" + "touchTip": { + "$ref": "#/$defs/TouchTipProperties", + "description": "Touch tip settings for retract after aspirate." } }, - "required": ["moduleId"] + "required": [ + "positionReference", + "offset", + "speed", + "airGapByVolume", + "touchTip", + "delay" + ], + "title": "RetractAspirate", + "type": "object" }, - "OpenLabwareLatchCreate": { - "title": "OpenLabwareLatchCreate", - "description": "A request to create a Heater-Shaker's open labware latch command.", - "type": "object", + "RetractAxisCreate": { + "description": "Data to create a Retract Axis command.", "properties": { "commandType": { + "const": "retractAxis", + "default": "retractAxis", + "enum": ["retractAxis"], "title": "Commandtype", - "default": "heaterShaker/openLabwareLatch", - "enum": ["heaterShaker/openLabwareLatch"], "type": "string" }, - "params": { - "$ref": "#/definitions/OpenLabwareLatchParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/RetractAxisParams" } }, - "required": ["params"] + "required": ["params"], + "title": "RetractAxisCreate", + "type": "object" }, - "CloseLabwareLatchParams": { - "title": "CloseLabwareLatchParams", - "description": "Input parameters to close a Heater-Shaker Module's labware latch.", - "type": "object", + "RetractAxisParams": { + "description": "Payload required for a Retract Axis command.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Heater-Shaker Module.", - "type": "string" + "axis": { + "$ref": "#/$defs/MotorAxis", + "description": "Axis to retract to its home position as quickly as safely possible. The difference between retracting an axis and homing an axis using the home command is that a home will always probe the limit switch and will work as the first motion command a robot will need to execute; On the other hand, retraction will rely on this previously determined home position to move to it as fast as safely possible. So on the Flex, it will move (fast) the axis to the previously recorded home position and on the OT2, it will move (fast) the axis a safe distance from the previously recorded home position, and then slowly approach the limit switch." } }, - "required": ["moduleId"] + "required": ["axis"], + "title": "RetractAxisParams", + "type": "object" }, - "CloseLabwareLatchCreate": { - "title": "CloseLabwareLatchCreate", - "description": "A request to create a Heater-Shaker's close latch command.", - "type": "object", + "RetractDispense": { + "description": "Shared properties for the retract function after dispense.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "heaterShaker/closeLabwareLatch", - "enum": ["heaterShaker/closeLabwareLatch"], - "type": "string" + "airGapByVolume": { + "description": "Settings for air gap keyed by target aspiration volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Airgapbyvolume", + "type": "array" }, - "params": { - "$ref": "#/definitions/CloseLabwareLatchParams" + "blowout": { + "$ref": "#/$defs/BlowoutProperties", + "description": "Blowout properties for retract after dispense." }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "delay": { + "$ref": "#/$defs/DelayProperties", + "description": "Delay settings for retract after dispense." }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" - } - }, - "required": ["params"] - }, - "DisengageParams": { - "title": "DisengageParams", - "description": "Input data to disengage a Magnetic Module's magnets.", - "type": "object", - "properties": { - "moduleId": { - "title": "Moduleid", - "description": "The ID of the Magnetic Module whose magnets you want to disengage, from a prior `loadModule` command.", - "type": "string" - } - }, - "required": ["moduleId"] - }, - "DisengageCreate": { - "title": "DisengageCreate", - "description": "A request to create a Magnetic Module disengage command.", - "type": "object", - "properties": { - "commandType": { - "title": "Commandtype", - "default": "magneticModule/disengage", - "enum": ["magneticModule/disengage"], - "type": "string" + "offset": { + "$ref": "#/$defs/Coordinate", + "description": "Relative offset for retract after dispense." }, - "params": { - "$ref": "#/definitions/DisengageParams" + "positionReference": { + "$ref": "#/$defs/PositionReference", + "description": "Position reference for retract after dispense." }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ + "speed": { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, { - "$ref": "#/definitions/CommandIntent" + "minimum": 0.0, + "type": "number" } - ] + ], + "description": "Speed of retraction, in millimeters per second.", + "title": "Speed" }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" + "touchTip": { + "$ref": "#/$defs/TouchTipProperties", + "description": "Touch tip settings for retract after dispense." } }, - "required": ["params"] + "required": [ + "positionReference", + "offset", + "speed", + "airGapByVolume", + "blowout", + "touchTip", + "delay" + ], + "title": "RetractDispense", + "type": "object" }, - "EngageParams": { - "title": "EngageParams", - "description": "Input data to engage a Magnetic Module.", - "type": "object", + "RowNozzleLayoutConfiguration": { + "description": "Minimum information required for a new nozzle configuration.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "The ID of the Magnetic Module whose magnets you want to raise, from a prior `loadModule` command.", + "primaryNozzle": { + "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.", + "enum": ["A1", "H1", "A12", "H12"], + "title": "Primarynozzle", "type": "string" }, - "height": { - "title": "Height", - "description": "How high, in millimeters, to raise the magnets.\n\nZero means the tops of the magnets are level with the ledge that the labware rests on. This will be slightly above the magnets' minimum height, the hardware home position. Negative values are allowed, to put the magnets below the ledge.\n\nUnits are always true millimeters. This is unlike certain labware definitions, engage commands in the Python Protocol API, and engage commands in older versions of the JSON protocol schema. Take care to convert properly.", - "type": "number" + "style": { + "const": "ROW", + "default": "ROW", + "enum": ["ROW"], + "title": "Style", + "type": "string" } }, - "required": ["moduleId", "height"] + "required": ["primaryNozzle"], + "title": "RowNozzleLayoutConfiguration", + "type": "object" }, - "EngageCreate": { - "title": "EngageCreate", - "description": "A request to create a Magnetic Module engage command.", - "type": "object", + "RunExtendedProfileCreate": { + "description": "A request to execute a Thermocycler profile run.", "properties": { "commandType": { + "const": "thermocycler/runExtendedProfile", + "default": "thermocycler/runExtendedProfile", + "enum": ["thermocycler/runExtendedProfile"], "title": "Commandtype", - "default": "magneticModule/engage", - "enum": ["magneticModule/engage"], "type": "string" }, - "params": { - "$ref": "#/definitions/EngageParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/RunExtendedProfileParams" } }, - "required": ["params"] + "required": ["params"], + "title": "RunExtendedProfileCreate", + "type": "object" }, - "opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureParams": { - "title": "SetTargetTemperatureParams", - "description": "Input parameters to set a Temperature Module's target temperature.", - "type": "object", + "RunExtendedProfileParams": { + "description": "Input parameters for an individual Thermocycler profile step.", "properties": { + "blockMaxVolumeUl": { + "description": "Amount of liquid in uL of the most-full well in labware loaded onto the thermocycler.", + "title": "Blockmaxvolumeul", + "type": "number" + }, "moduleId": { + "description": "Unique ID of the Thermocycler.", "title": "Moduleid", - "description": "Unique ID of the Temperature Module.", "type": "string" }, - "celsius": { - "title": "Celsius", - "description": "Target temperature in \u00b0C.", - "type": "number" + "profileElements": { + "description": "Elements of the profile. Each can be either a step or a cycle.", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/ProfileStep" + }, + { + "$ref": "#/$defs/ProfileCycle" + } + ] + }, + "title": "Profileelements", + "type": "array" } }, - "required": ["moduleId", "celsius"] + "required": ["moduleId", "profileElements"], + "title": "RunExtendedProfileParams", + "type": "object" }, - "opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureCreate": { - "title": "SetTargetTemperatureCreate", - "description": "A request to create a Temperature Module's set temperature command.", - "type": "object", + "RunProfileCreate": { + "description": "A request to execute a Thermocycler profile run.", "properties": { "commandType": { + "const": "thermocycler/runProfile", + "default": "thermocycler/runProfile", + "enum": ["thermocycler/runProfile"], "title": "Commandtype", - "default": "temperatureModule/setTargetTemperature", - "enum": ["temperatureModule/setTargetTemperature"], "type": "string" }, - "params": { - "$ref": "#/definitions/opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/RunProfileParams" } }, - "required": ["params"] + "required": ["params"], + "title": "RunProfileCreate", + "type": "object" }, - "opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureParams": { - "title": "WaitForTemperatureParams", - "description": "Input parameters to wait for a Temperature Module's target temperature.", - "type": "object", + "RunProfileParams": { + "description": "Input parameters to run a Thermocycler profile.", "properties": { + "blockMaxVolumeUl": { + "description": "Amount of liquid in uL of the most-full well in labware loaded onto the thermocycler.", + "title": "Blockmaxvolumeul", + "type": "number" + }, "moduleId": { + "description": "Unique ID of the Thermocycler.", "title": "Moduleid", - "description": "Unique ID of the Temperature Module.", "type": "string" }, + "profile": { + "description": "Array of profile steps with target temperature and temperature hold time.", + "items": { + "$ref": "#/$defs/RunProfileStepParams" + }, + "title": "Profile", + "type": "array" + } + }, + "required": ["moduleId", "profile"], + "title": "RunProfileParams", + "type": "object" + }, + "RunProfileStepParams": { + "description": "Input parameters for an individual Thermocycler profile step.", + "properties": { "celsius": { + "description": "Target temperature in \u00b0C.", "title": "Celsius", - "description": "Target temperature in \u00b0C. If not specified, will default to the module's target temperature. Specifying a celsius parameter other than the target temperature could lead to unpredictable behavior and hence is not recommended for use. This parameter can be removed in a future version without prior notice.", + "type": "number" + }, + "holdSeconds": { + "description": "Time to hold target temperature at in seconds.", + "title": "Holdseconds", "type": "number" } }, - "required": ["moduleId"] + "required": ["celsius", "holdSeconds"], + "title": "RunProfileStepParams", + "type": "object" }, - "opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureCreate": { - "title": "WaitForTemperatureCreate", - "description": "A request to create a Temperature Module's wait for temperature command.", - "type": "object", + "SavePositionCreate": { + "description": "Save position command creation request model.", "properties": { "commandType": { + "const": "savePosition", + "default": "savePosition", + "enum": ["savePosition"], "title": "Commandtype", - "default": "temperatureModule/waitForTemperature", - "enum": ["temperatureModule/waitForTemperature"], "type": "string" }, - "params": { - "$ref": "#/definitions/opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/SavePositionParams" } }, - "required": ["params"] + "required": ["params"], + "title": "SavePositionCreate", + "type": "object" }, - "DeactivateTemperatureParams": { - "title": "DeactivateTemperatureParams", - "description": "Input parameters to deactivate a Temperature Module.", - "type": "object", + "SavePositionParams": { + "description": "Payload needed to save a pipette's current position.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Temperature Module.", + "failOnNotHomed": { + "description": "Require all axes to be homed before saving position.", + "title": "Failonnothomed", + "type": "boolean" + }, + "pipetteId": { + "description": "Unique identifier of the pipette in question.", + "title": "Pipetteid", + "type": "string" + }, + "positionId": { + "description": "An optional ID to assign to this command instance. Auto-assigned if not defined.", + "title": "Positionid", "type": "string" } }, - "required": ["moduleId"] + "required": ["pipetteId"], + "title": "SavePositionParams", + "type": "object" }, - "DeactivateTemperatureCreate": { - "title": "DeactivateTemperatureCreate", - "description": "A request to deactivate a Temperature Module.", - "type": "object", + "SetAndWaitForShakeSpeedCreate": { + "description": "A request to create a Heater-Shaker's set and wait for shake speed command.", "properties": { "commandType": { + "const": "heaterShaker/setAndWaitForShakeSpeed", + "default": "heaterShaker/setAndWaitForShakeSpeed", + "enum": ["heaterShaker/setAndWaitForShakeSpeed"], "title": "Commandtype", - "default": "temperatureModule/deactivate", - "enum": ["temperatureModule/deactivate"], "type": "string" }, - "params": { - "$ref": "#/definitions/DeactivateTemperatureParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/SetAndWaitForShakeSpeedParams" } }, - "required": ["params"] + "required": ["params"], + "title": "SetAndWaitForShakeSpeedCreate", + "type": "object" }, - "SetTargetBlockTemperatureParams": { - "title": "SetTargetBlockTemperatureParams", - "description": "Input parameters to set a Thermocycler's target block temperature.", - "type": "object", - "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Thermocycler Module.", - "type": "string" - }, - "celsius": { - "title": "Celsius", - "description": "Target temperature in \u00b0C.", - "type": "number" - }, - "blockMaxVolumeUl": { - "title": "Blockmaxvolumeul", - "description": "Amount of liquid in uL of the most-full well in labware loaded onto the thermocycler.", - "type": "number" + "SetAndWaitForShakeSpeedParams": { + "description": "Input parameters to set and wait for a shake speed for a Heater-Shaker Module.", + "properties": { + "moduleId": { + "description": "Unique ID of the Heater-Shaker Module.", + "title": "Moduleid", + "type": "string" }, - "holdTimeSeconds": { - "title": "Holdtimeseconds", - "description": "Amount of time, in seconds, to hold the temperature for. If specified, a waitForBlockTemperature command will block until the given hold time has elapsed.", + "rpm": { + "description": "Target speed in rotations per minute.", + "title": "Rpm", "type": "number" } }, - "required": ["moduleId", "celsius"] + "required": ["moduleId", "rpm"], + "title": "SetAndWaitForShakeSpeedParams", + "type": "object" }, - "SetTargetBlockTemperatureCreate": { - "title": "SetTargetBlockTemperatureCreate", - "description": "A request to create a Thermocycler's set block temperature command.", - "type": "object", + "SetRailLightsCreate": { + "description": "setRailLights command request model.", "properties": { "commandType": { + "const": "setRailLights", + "default": "setRailLights", + "enum": ["setRailLights"], "title": "Commandtype", - "default": "thermocycler/setTargetBlockTemperature", - "enum": ["thermocycler/setTargetBlockTemperature"], "type": "string" }, - "params": { - "$ref": "#/definitions/SetTargetBlockTemperatureParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/SetRailLightsParams" } }, - "required": ["params"] + "required": ["params"], + "title": "SetRailLightsCreate", + "type": "object" }, - "WaitForBlockTemperatureParams": { - "title": "WaitForBlockTemperatureParams", - "description": "Input parameters to wait for Thermocycler's target block temperature.", - "type": "object", + "SetRailLightsParams": { + "description": "Payload required to set the rail lights on or off.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Thermocycler Module.", - "type": "string" + "on": { + "description": "The field that determines if the light is turned off or on.", + "title": "On", + "type": "boolean" } }, - "required": ["moduleId"] + "required": ["on"], + "title": "SetRailLightsParams", + "type": "object" }, - "WaitForBlockTemperatureCreate": { - "title": "WaitForBlockTemperatureCreate", - "description": "A request to create Thermocycler's wait for block temperature command.", - "type": "object", + "SetStatusBarCreate": { + "description": "setStatusBar command request model.", "properties": { "commandType": { + "const": "setStatusBar", + "default": "setStatusBar", + "enum": ["setStatusBar"], "title": "Commandtype", - "default": "thermocycler/waitForBlockTemperature", - "enum": ["thermocycler/waitForBlockTemperature"], "type": "string" }, - "params": { - "$ref": "#/definitions/WaitForBlockTemperatureParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/SetStatusBarParams" } }, - "required": ["params"] + "required": ["params"], + "title": "SetStatusBarCreate", + "type": "object" }, - "SetTargetLidTemperatureParams": { - "title": "SetTargetLidTemperatureParams", - "description": "Input parameters to set a Thermocycler's target lid temperature.", - "type": "object", + "SetStatusBarParams": { + "description": "Payload required to set the status bar to run an animation.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Thermocycler Module.", - "type": "string" - }, - "celsius": { - "title": "Celsius", - "description": "Target temperature in \u00b0C.", - "type": "number" + "animation": { + "$ref": "#/$defs/StatusBarAnimation", + "description": "The animation that should be executed on the status bar." } }, - "required": ["moduleId", "celsius"] + "required": ["animation"], + "title": "SetStatusBarParams", + "type": "object" }, - "SetTargetLidTemperatureCreate": { - "title": "SetTargetLidTemperatureCreate", - "description": "A request to create a Thermocycler's set lid temperature command.", - "type": "object", + "SetTargetBlockTemperatureCreate": { + "description": "A request to create a Thermocycler's set block temperature command.", "properties": { "commandType": { + "const": "thermocycler/setTargetBlockTemperature", + "default": "thermocycler/setTargetBlockTemperature", + "enum": ["thermocycler/setTargetBlockTemperature"], "title": "Commandtype", - "default": "thermocycler/setTargetLidTemperature", - "enum": ["thermocycler/setTargetLidTemperature"], "type": "string" }, - "params": { - "$ref": "#/definitions/SetTargetLidTemperatureParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/SetTargetBlockTemperatureParams" } }, - "required": ["params"] + "required": ["params"], + "title": "SetTargetBlockTemperatureCreate", + "type": "object" }, - "WaitForLidTemperatureParams": { - "title": "WaitForLidTemperatureParams", - "description": "Input parameters to wait for Thermocycler's lid temperature.", - "type": "object", + "SetTargetBlockTemperatureParams": { + "description": "Input parameters to set a Thermocycler's target block temperature.", "properties": { + "blockMaxVolumeUl": { + "description": "Amount of liquid in uL of the most-full well in labware loaded onto the thermocycler.", + "title": "Blockmaxvolumeul", + "type": "number" + }, + "celsius": { + "description": "Target temperature in \u00b0C.", + "title": "Celsius", + "type": "number" + }, + "holdTimeSeconds": { + "description": "Amount of time, in seconds, to hold the temperature for. If specified, a waitForBlockTemperature command will block until the given hold time has elapsed.", + "title": "Holdtimeseconds", + "type": "number" + }, "moduleId": { - "title": "Moduleid", "description": "Unique ID of the Thermocycler Module.", + "title": "Moduleid", "type": "string" } }, - "required": ["moduleId"] + "required": ["moduleId", "celsius"], + "title": "SetTargetBlockTemperatureParams", + "type": "object" }, - "WaitForLidTemperatureCreate": { - "title": "WaitForLidTemperatureCreate", - "description": "A request to create Thermocycler's wait for lid temperature command.", - "type": "object", + "SetTargetLidTemperatureCreate": { + "description": "A request to create a Thermocycler's set lid temperature command.", "properties": { "commandType": { + "const": "thermocycler/setTargetLidTemperature", + "default": "thermocycler/setTargetLidTemperature", + "enum": ["thermocycler/setTargetLidTemperature"], "title": "Commandtype", - "default": "thermocycler/waitForLidTemperature", - "enum": ["thermocycler/waitForLidTemperature"], "type": "string" }, - "params": { - "$ref": "#/definitions/WaitForLidTemperatureParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/SetTargetLidTemperatureParams" } }, - "required": ["params"] + "required": ["params"], + "title": "SetTargetLidTemperatureCreate", + "type": "object" }, - "DeactivateBlockParams": { - "title": "DeactivateBlockParams", - "description": "Input parameters to unset a Thermocycler's target block temperature.", - "type": "object", + "SetTargetLidTemperatureParams": { + "description": "Input parameters to set a Thermocycler's target lid temperature.", "properties": { + "celsius": { + "description": "Target temperature in \u00b0C.", + "title": "Celsius", + "type": "number" + }, "moduleId": { + "description": "Unique ID of the Thermocycler Module.", "title": "Moduleid", - "description": "Unique ID of the Thermocycler.", "type": "string" } }, - "required": ["moduleId"] + "required": ["moduleId", "celsius"], + "title": "SetTargetLidTemperatureParams", + "type": "object" }, - "DeactivateBlockCreate": { - "title": "DeactivateBlockCreate", - "description": "A request to create a Thermocycler's deactivate block command.", - "type": "object", + "SingleDispenseProperties": { + "description": "Properties specific to the single-dispense function.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "thermocycler/deactivateBlock", - "enum": ["thermocycler/deactivateBlock"], - "type": "string" + "correctionByVolume": { + "description": "Settings for volume correction keyed by by target dispense volume, representing additional volume the plunger should move to accurately hit target volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Correctionbyvolume", + "type": "array" }, - "params": { - "$ref": "#/definitions/DeactivateBlockParams" + "delay": { + "$ref": "#/$defs/DelayProperties", + "description": "Delay after dispense, in seconds." }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "flowRateByVolume": { + "description": "Settings for flow rate keyed by target dispense volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Flowratebyvolume", + "type": "array" + }, + "mix": { + "$ref": "#/$defs/MixProperties", + "description": "Mixing settings for after a dispense" + }, + "offset": { + "$ref": "#/$defs/Coordinate", + "description": "Relative offset for single dispense." + }, + "positionReference": { + "$ref": "#/$defs/PositionReference", + "description": "Position reference for single dispense." + }, + "pushOutByVolume": { + "description": "Settings for pushout keyed by target dispense volume.", + "items": { + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + }, + { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" + } + ] + } + ], + "type": "array" + }, + "title": "Pushoutbyvolume", + "type": "array" + }, + "retract": { + "$ref": "#/$defs/RetractDispense", + "description": "Pipette retract settings after a single dispense." }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" + "submerge": { + "$ref": "#/$defs/Submerge", + "description": "Submerge settings for single dispense." } }, - "required": ["params"] + "required": [ + "submerge", + "retract", + "positionReference", + "offset", + "flowRateByVolume", + "correctionByVolume", + "mix", + "pushOutByVolume", + "delay" + ], + "title": "SingleDispenseProperties", + "type": "object" }, - "DeactivateLidParams": { - "title": "DeactivateLidParams", - "description": "Input parameters to unset a Thermocycler's target lid temperature.", - "type": "object", + "SingleNozzleLayoutConfiguration": { + "description": "Minimum information required for a new nozzle configuration.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Thermocycler.", + "primaryNozzle": { + "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.", + "enum": ["A1", "H1", "A12", "H12"], + "title": "Primarynozzle", + "type": "string" + }, + "style": { + "const": "SINGLE", + "default": "SINGLE", + "enum": ["SINGLE"], + "title": "Style", "type": "string" } }, - "required": ["moduleId"] + "required": ["primaryNozzle"], + "title": "SingleNozzleLayoutConfiguration", + "type": "object" }, - "DeactivateLidCreate": { - "title": "DeactivateLidCreate", - "description": "A request to create a Thermocycler's deactivate lid command.", - "type": "object", + "StatusBarAnimation": { + "description": "Status Bar animation options.", + "enum": ["idle", "confirm", "updating", "disco", "off"], + "title": "StatusBarAnimation", + "type": "string" + }, + "Submerge": { + "description": "Shared properties for the submerge function before aspiration or dispense.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "thermocycler/deactivateLid", - "enum": ["thermocycler/deactivateLid"], - "type": "string" + "delay": { + "$ref": "#/$defs/DelayProperties", + "description": "Delay settings for submerge." }, - "params": { - "$ref": "#/definitions/DeactivateLidParams" + "offset": { + "$ref": "#/$defs/Coordinate", + "description": "Relative offset for submerge." }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ + "positionReference": { + "$ref": "#/$defs/PositionReference", + "description": "Position reference for submerge." + }, + "speed": { + "anyOf": [ { - "$ref": "#/definitions/CommandIntent" + "minimum": 0, + "type": "integer" + }, + { + "minimum": 0.0, + "type": "number" } - ] - }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", - "type": "string" + ], + "description": "Speed of submerging, in millimeters per second.", + "title": "Speed" } }, - "required": ["params"] + "required": ["positionReference", "offset", "speed", "delay"], + "title": "Submerge", + "type": "object" }, - "opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidParams": { - "title": "OpenLidParams", - "description": "Input parameters to open a Thermocycler's lid.", - "type": "object", - "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Thermocycler.", - "type": "string" - } - }, - "required": ["moduleId"] + "TipPresenceStatus": { + "description": "Tip presence status reported by a pipette.", + "enum": ["present", "absent", "unknown"], + "title": "TipPresenceStatus", + "type": "string" }, - "opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidCreate": { - "title": "OpenLidCreate", - "description": "A request to open a Thermocycler's lid.", - "type": "object", + "TouchTipCreate": { + "description": "Touch tip command creation request model.", "properties": { "commandType": { + "const": "touchTip", + "default": "touchTip", + "enum": ["touchTip"], "title": "Commandtype", - "default": "thermocycler/openLid", - "enum": ["thermocycler/openLid"], "type": "string" }, - "params": { - "$ref": "#/definitions/opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/TouchTipParams" } }, - "required": ["params"] - }, - "opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidParams": { - "title": "CloseLidParams", - "description": "Input parameters to close a Thermocycler's lid.", - "type": "object", - "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Thermocycler.", - "type": "string" - } - }, - "required": ["moduleId"] + "required": ["params"], + "title": "TouchTipCreate", + "type": "object" }, - "opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidCreate": { - "title": "CloseLidCreate", - "description": "A request to close a Thermocycler's lid.", - "type": "object", + "TouchTipParams": { + "description": "Payload needed to touch a pipette tip the sides of a specific well.", "properties": { - "commandType": { - "title": "Commandtype", - "default": "thermocycler/closeLid", - "enum": ["thermocycler/closeLid"], + "labwareId": { + "description": "Identifier of labware to use.", + "title": "Labwareid", "type": "string" }, - "params": { - "$ref": "#/definitions/opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidParams" - }, - "intent": { - "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "mmFromEdge": { + "description": "Offset away from the the well edge, in millimeters.Incompatible when a radius is included as a non 1.0 value.", + "title": "Mmfromedge", + "type": "number" }, - "key": { - "title": "Key", - "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" - } - }, - "required": ["params"] - }, - "RunProfileStepParams": { - "title": "RunProfileStepParams", - "description": "Input parameters for an individual Thermocycler profile step.", - "type": "object", - "properties": { - "celsius": { - "title": "Celsius", - "description": "Target temperature in \u00b0C.", + }, + "radius": { + "default": 1.0, + "description": "The proportion of the target well's radius the pipette tip will move towards.", + "title": "Radius", "type": "number" }, - "holdSeconds": { - "title": "Holdseconds", - "description": "Time to hold target temperature at in seconds.", + "speed": { + "description": "Override the travel speed in mm/s. This controls the straight linear speed of motion.", + "title": "Speed", "type": "number" + }, + "wellLocation": { + "$ref": "#/$defs/WellLocation", + "description": "Relative well location at which to perform the operation" + }, + "wellName": { + "description": "Name of well to use in labware.", + "title": "Wellname", + "type": "string" } }, - "required": ["celsius", "holdSeconds"] + "required": ["labwareId", "wellName", "pipetteId"], + "title": "TouchTipParams", + "type": "object" }, - "RunProfileParams": { - "title": "RunProfileParams", - "description": "Input parameters to run a Thermocycler profile.", - "type": "object", + "TouchTipProperties": { + "description": "Shared properties for the touch-tip function.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Thermocycler.", - "type": "string" - }, - "profile": { - "title": "Profile", - "description": "Array of profile steps with target temperature and temperature hold time.", - "type": "array", - "items": { - "$ref": "#/definitions/RunProfileStepParams" - } + "enable": { + "description": "Whether touch-tip is enabled.", + "title": "Enable", + "type": "boolean" }, - "blockMaxVolumeUl": { - "title": "Blockmaxvolumeul", - "description": "Amount of liquid in uL of the most-full well in labware loaded onto the thermocycler.", - "type": "number" + "params": { + "$ref": "#/$defs/LiquidClassTouchTipParams", + "description": "Parameters for the touch-tip function.", + "title": "Params" } }, - "required": ["moduleId", "profile"] + "required": ["enable"], + "title": "TouchTipProperties", + "type": "object" }, - "RunProfileCreate": { - "title": "RunProfileCreate", - "description": "A request to execute a Thermocycler profile run.", - "type": "object", + "TryLiquidProbeCreate": { + "description": "The request model for a `tryLiquidProbe` command.", "properties": { "commandType": { + "const": "tryLiquidProbe", + "default": "tryLiquidProbe", + "enum": ["tryLiquidProbe"], "title": "Commandtype", - "default": "thermocycler/runProfile", - "enum": ["thermocycler/runProfile"], "type": "string" }, - "params": { - "$ref": "#/definitions/RunProfileParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" - } - }, - "required": ["params"] - }, - "ProfileStep": { - "title": "ProfileStep", - "description": "An individual step in a Thermocycler extended profile.", - "type": "object", - "properties": { - "celsius": { - "title": "Celsius", - "description": "Target temperature in \u00b0C.", - "type": "number" - }, - "holdSeconds": { - "title": "Holdseconds", - "description": "Time to hold target temperature in seconds.", - "type": "number" - } - }, - "required": ["celsius", "holdSeconds"] - }, - "ProfileCycle": { - "title": "ProfileCycle", - "description": "An individual cycle in a Thermocycler extended profile.", - "type": "object", - "properties": { - "steps": { - "title": "Steps", - "description": "Steps to repeat.", - "type": "array", - "items": { - "$ref": "#/definitions/ProfileStep" - } }, - "repetitions": { - "title": "Repetitions", - "description": "Number of times to repeat the steps.", - "type": "integer" + "params": { + "$ref": "#/$defs/TryLiquidProbeParams" } }, - "required": ["steps", "repetitions"] + "required": ["params"], + "title": "TryLiquidProbeCreate", + "type": "object" }, - "RunExtendedProfileParams": { - "title": "RunExtendedProfileParams", - "description": "Input parameters for an individual Thermocycler profile step.", - "type": "object", + "TryLiquidProbeParams": { + "description": "Parameters required for a `tryLiquidProbe` command.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Thermocycler.", + "labwareId": { + "description": "Identifier of labware to use.", + "title": "Labwareid", "type": "string" }, - "profileElements": { - "title": "Profileelements", - "description": "Elements of the profile. Each can be either a step or a cycle.", - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/ProfileStep" - }, - { - "$ref": "#/definitions/ProfileCycle" - } - ] - } + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", + "type": "string" }, - "blockMaxVolumeUl": { - "title": "Blockmaxvolumeul", - "description": "Amount of liquid in uL of the most-full well in labware loaded onto the thermocycler.", - "type": "number" + "wellLocation": { + "$ref": "#/$defs/WellLocation", + "description": "Relative well location at which to perform the operation" + }, + "wellName": { + "description": "Name of well to use in labware.", + "title": "Wellname", + "type": "string" } }, - "required": ["moduleId", "profileElements"] + "required": ["labwareId", "wellName", "pipetteId"], + "title": "TryLiquidProbeParams", + "type": "object" }, - "RunExtendedProfileCreate": { - "title": "RunExtendedProfileCreate", - "description": "A request to execute a Thermocycler profile run.", - "type": "object", + "UnsafeBlowOutInPlaceCreate": { + "description": "UnsafeBlowOutInPlace command request model.", "properties": { "commandType": { + "const": "unsafe/blowOutInPlace", + "default": "unsafe/blowOutInPlace", + "enum": ["unsafe/blowOutInPlace"], "title": "Commandtype", - "default": "thermocycler/runExtendedProfile", - "enum": ["thermocycler/runExtendedProfile"], "type": "string" }, - "params": { - "$ref": "#/definitions/RunExtendedProfileParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/UnsafeBlowOutInPlaceParams" } }, - "required": ["params"] + "required": ["params"], + "title": "UnsafeBlowOutInPlaceCreate", + "type": "object" }, - "opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidParams": { - "title": "CloseLidParams", - "description": "Input parameters to close the lid on an absorbance reading.", - "type": "object", + "UnsafeBlowOutInPlaceParams": { + "description": "Payload required to blow-out in place while position is unknown.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the absorbance reader.", + "flowRate": { + "description": "Speed in \u00b5L/s configured for the pipette", + "exclusiveMinimum": 0.0, + "title": "Flowrate", + "type": "number" + }, + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" } }, - "required": ["moduleId"] + "required": ["flowRate", "pipetteId"], + "title": "UnsafeBlowOutInPlaceParams", + "type": "object" }, - "opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidCreate": { - "title": "CloseLidCreate", - "description": "A request to execute an Absorbance Reader close lid command.", - "type": "object", + "UnsafeDropTipInPlaceCreate": { + "description": "Drop tip in place command creation request model.", "properties": { "commandType": { + "const": "unsafe/dropTipInPlace", + "default": "unsafe/dropTipInPlace", + "enum": ["unsafe/dropTipInPlace"], "title": "Commandtype", - "default": "absorbanceReader/closeLid", - "enum": ["absorbanceReader/closeLid"], "type": "string" }, - "params": { - "$ref": "#/definitions/opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/UnsafeDropTipInPlaceParams" } }, - "required": ["params"] + "required": ["params"], + "title": "UnsafeDropTipInPlaceCreate", + "type": "object" }, - "opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidParams": { - "title": "OpenLidParams", - "description": "Input parameters to open the lid on an absorbance reading.", - "type": "object", + "UnsafeDropTipInPlaceParams": { + "description": "Payload required to drop a tip in place even if the plunger position is not known.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the absorbance reader.", + "homeAfter": { + "description": "Whether to home this pipette's plunger after dropping the tip. You should normally leave this unspecified to let the robot choose a safe default depending on its hardware.", + "title": "Homeafter", + "type": "boolean" + }, + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", "type": "string" } }, - "required": ["moduleId"] + "required": ["pipetteId"], + "title": "UnsafeDropTipInPlaceParams", + "type": "object" }, - "opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidCreate": { - "title": "OpenLidCreate", - "description": "A request to execute an Absorbance Reader open lid command.", - "type": "object", + "UnsafeEngageAxesCreate": { + "description": "UnsafeEngageAxes command request model.", "properties": { "commandType": { + "const": "unsafe/engageAxes", + "default": "unsafe/engageAxes", + "enum": ["unsafe/engageAxes"], "title": "Commandtype", - "default": "absorbanceReader/openLid", - "enum": ["absorbanceReader/openLid"], "type": "string" }, - "params": { - "$ref": "#/definitions/opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/UnsafeEngageAxesParams" } }, - "required": ["params"] + "required": ["params"], + "title": "UnsafeEngageAxesCreate", + "type": "object" }, - "InitializeParams": { - "title": "InitializeParams", - "description": "Input parameters to initialize an absorbance reading.", - "type": "object", + "UnsafeEngageAxesParams": { + "description": "Payload required for an UnsafeEngageAxes command.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the absorbance reader.", - "type": "string" - }, - "measureMode": { - "title": "Measuremode", - "description": "Initialize single or multi measurement mode.", - "enum": ["single", "multi"], - "type": "string" - }, - "sampleWavelengths": { - "title": "Samplewavelengths", - "description": "Sample wavelengths in nm.", - "type": "array", + "axes": { + "description": "The axes for which to enable.", "items": { - "type": "integer" - } - }, - "referenceWavelength": { - "title": "Referencewavelength", - "description": "Optional reference wavelength in nm.", - "type": "integer" + "$ref": "#/$defs/MotorAxis" + }, + "title": "Axes", + "type": "array" } }, - "required": ["moduleId", "measureMode", "sampleWavelengths"] + "required": ["axes"], + "title": "UnsafeEngageAxesParams", + "type": "object" }, - "InitializeCreate": { - "title": "InitializeCreate", - "description": "A request to execute an Absorbance Reader measurement.", - "type": "object", + "UnsafePlaceLabwareCreate": { + "description": "UnsafePlaceLabware command request model.", "properties": { "commandType": { + "const": "unsafe/placeLabware", + "default": "unsafe/placeLabware", + "enum": ["unsafe/placeLabware"], "title": "Commandtype", - "default": "absorbanceReader/initialize", - "enum": ["absorbanceReader/initialize"], "type": "string" }, - "params": { - "$ref": "#/definitions/InitializeParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/UnsafePlaceLabwareParams" } }, - "required": ["params"] + "required": ["params"], + "title": "UnsafePlaceLabwareCreate", + "type": "object" }, - "ReadAbsorbanceParams": { - "title": "ReadAbsorbanceParams", - "description": "Input parameters for an absorbance reading.", - "type": "object", + "UnsafePlaceLabwareParams": { + "description": "Payload required for an UnsafePlaceLabware command.", "properties": { - "moduleId": { - "title": "Moduleid", - "description": "Unique ID of the Absorbance Reader.", + "labwareURI": { + "description": "Labware URI for labware.", + "title": "Labwareuri", "type": "string" }, - "fileName": { - "title": "Filename", - "description": "Optional file name to use when storing the results of a measurement.", - "type": "string" + "location": { + "anyOf": [ + { + "$ref": "#/$defs/DeckSlotLocation" + }, + { + "$ref": "#/$defs/ModuleLocation" + }, + { + "$ref": "#/$defs/OnLabwareLocation" + }, + { + "$ref": "#/$defs/AddressableAreaLocation" + } + ], + "description": "Where to place the labware.", + "title": "Location" } }, - "required": ["moduleId"] + "required": ["labwareURI", "location"], + "title": "UnsafePlaceLabwareParams", + "type": "object" }, - "ReadAbsorbanceCreate": { - "title": "ReadAbsorbanceCreate", - "description": "A request to execute an Absorbance Reader measurement.", - "type": "object", + "UnsafeUngripLabwareCreate": { + "description": "UnsafeEngageAxes command request model.", "properties": { "commandType": { + "const": "unsafe/ungripLabware", + "default": "unsafe/ungripLabware", + "enum": ["unsafe/ungripLabware"], "title": "Commandtype", - "default": "absorbanceReader/read", - "enum": ["absorbanceReader/read"], + "type": "string" + }, + "intent": { + "$ref": "#/$defs/CommandIntent", + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "title": "Intent" + }, + "key": { + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" }, "params": { - "$ref": "#/definitions/ReadAbsorbanceParams" + "$ref": "#/$defs/UnsafeUngripLabwareParams" + } + }, + "required": ["params"], + "title": "UnsafeUngripLabwareCreate", + "type": "object" + }, + "UnsafeUngripLabwareParams": { + "description": "Payload required for an UngripLabware command.", + "properties": {}, + "title": "UnsafeUngripLabwareParams", + "type": "object" + }, + "UpdatePositionEstimatorsCreate": { + "description": "UpdatePositionEstimators command request model.", + "properties": { + "commandType": { + "const": "unsafe/updatePositionEstimators", + "default": "unsafe/updatePositionEstimators", + "enum": ["unsafe/updatePositionEstimators"], + "title": "Commandtype", + "type": "string" }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/UpdatePositionEstimatorsParams" } }, - "required": ["params"] + "required": ["params"], + "title": "UpdatePositionEstimatorsCreate", + "type": "object" }, - "CalibrateGripperParamsJaw": { - "title": "CalibrateGripperParamsJaw", - "description": "An enumeration.", - "enum": ["front", "rear"] + "UpdatePositionEstimatorsParams": { + "description": "Payload required for an UpdatePositionEstimators command.", + "properties": { + "axes": { + "description": "The axes for which to update the position estimators. Any axes that are not physically present will be ignored.", + "items": { + "$ref": "#/$defs/MotorAxis" + }, + "title": "Axes", + "type": "array" + } + }, + "required": ["axes"], + "title": "UpdatePositionEstimatorsParams", + "type": "object" }, "Vec3f": { - "title": "Vec3f", "description": "A 3D vector of floats.", - "type": "object", "properties": { "x": { "title": "X", "type": "number" }, "y": { - "title": "Y", - "type": "number" - }, - "z": { - "title": "Z", - "type": "number" - } - }, - "required": ["x", "y", "z"] - }, - "CalibrateGripperParams": { - "title": "CalibrateGripperParams", - "description": "Parameters for a `calibrateGripper` command.", - "type": "object", - "properties": { - "jaw": { - "description": "Which of the gripper's jaws to use to measure its offset. The robot will assume that a human operator has already attached the capacitive probe to the jaw and none is attached to the other jaw.", - "allOf": [ - { - "$ref": "#/definitions/CalibrateGripperParamsJaw" - } - ] + "title": "Y", + "type": "number" }, - "otherJawOffset": { - "title": "Otherjawoffset", - "description": "If an offset for the other probe is already found, then specifying it here will enable the CalibrateGripper command to complete the calibration process by calculating the total offset and saving it to disk. If this param is not specified then the command will only find and return the offset for the specified probe.", - "allOf": [ - { - "$ref": "#/definitions/Vec3f" - } - ] + "z": { + "title": "Z", + "type": "number" } }, - "required": ["jaw"] + "required": ["x", "y", "z"], + "title": "Vec3f", + "type": "object" }, - "CalibrateGripperCreate": { - "title": "CalibrateGripperCreate", - "description": "A request to create a `calibrateGripper` command.", - "type": "object", + "VerifyTipPresenceCreate": { + "description": "VerifyTipPresence command creation request model.", "properties": { "commandType": { + "const": "verifyTipPresence", + "default": "verifyTipPresence", + "enum": ["verifyTipPresence"], "title": "Commandtype", - "default": "calibration/calibrateGripper", - "enum": ["calibration/calibrateGripper"], "type": "string" }, - "params": { - "$ref": "#/definitions/CalibrateGripperParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/VerifyTipPresenceParams" } }, - "required": ["params"] + "required": ["params"], + "title": "VerifyTipPresenceCreate", + "type": "object" }, - "CalibratePipetteParams": { - "title": "CalibratePipetteParams", - "description": "Payload required to calibrate-pipette.", - "type": "object", + "VerifyTipPresenceParams": { + "description": "Payload required for a VerifyTipPresence command.", "properties": { - "mount": { - "description": "Instrument mount to calibrate.", - "allOf": [ - { - "$ref": "#/definitions/MountType" - } - ] + "expectedState": { + "$ref": "#/$defs/TipPresenceStatus", + "description": "The expected tip presence status on the pipette." + }, + "followSingularSensor": { + "$ref": "#/$defs/InstrumentSensorId", + "description": "The sensor id to follow if the other can be ignored.", + "title": "Followsingularsensor" + }, + "pipetteId": { + "description": "Identifier of pipette to use for liquid handling.", + "title": "Pipetteid", + "type": "string" } }, - "required": ["mount"] + "required": ["pipetteId", "expectedState"], + "title": "VerifyTipPresenceParams", + "type": "object" }, - "CalibratePipetteCreate": { - "title": "CalibratePipetteCreate", - "description": "Create calibrate-pipette command request model.", - "type": "object", + "WaitForBlockTemperatureCreate": { + "description": "A request to create Thermocycler's wait for block temperature command.", "properties": { "commandType": { + "const": "thermocycler/waitForBlockTemperature", + "default": "thermocycler/waitForBlockTemperature", + "enum": ["thermocycler/waitForBlockTemperature"], "title": "Commandtype", - "default": "calibration/calibratePipette", - "enum": ["calibration/calibratePipette"], "type": "string" }, - "params": { - "$ref": "#/definitions/CalibratePipetteParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/WaitForBlockTemperatureParams" } }, - "required": ["params"] + "required": ["params"], + "title": "WaitForBlockTemperatureCreate", + "type": "object" }, - "CalibrateModuleParams": { - "title": "CalibrateModuleParams", - "description": "Payload required to calibrate-module.", - "type": "object", + "WaitForBlockTemperatureParams": { + "description": "Input parameters to wait for Thermocycler's target block temperature.", "properties": { "moduleId": { + "description": "Unique ID of the Thermocycler Module.", "title": "Moduleid", - "description": "The unique id of module to calibrate.", - "type": "string" - }, - "labwareId": { - "title": "Labwareid", - "description": "The unique id of module calibration adapter labware.", "type": "string" - }, - "mount": { - "description": "The instrument mount used to calibrate the module.", - "allOf": [ - { - "$ref": "#/definitions/MountType" - } - ] } }, - "required": ["moduleId", "labwareId", "mount"] + "required": ["moduleId"], + "title": "WaitForBlockTemperatureParams", + "type": "object" }, - "CalibrateModuleCreate": { - "title": "CalibrateModuleCreate", - "description": "Create calibrate-module command request model.", - "type": "object", + "WaitForDurationCreate": { + "description": "Wait for duration command request model.", "properties": { "commandType": { + "const": "waitForDuration", + "default": "waitForDuration", + "enum": ["waitForDuration"], "title": "Commandtype", - "default": "calibration/calibrateModule", - "enum": ["calibration/calibrateModule"], "type": "string" }, - "params": { - "$ref": "#/definitions/CalibrateModuleParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/WaitForDurationParams" } }, - "required": ["params"] - }, - "MaintenancePosition": { - "title": "MaintenancePosition", - "description": "Maintenance position options.", - "enum": ["attachPlate", "attachInstrument"] + "required": ["params"], + "title": "WaitForDurationCreate", + "type": "object" }, - "MoveToMaintenancePositionParams": { - "title": "MoveToMaintenancePositionParams", - "description": "Calibration set up position command parameters.", - "type": "object", + "WaitForDurationParams": { + "description": "Payload required to pause the protocol.", "properties": { - "mount": { - "description": "Gantry mount to move maintenance position.", - "allOf": [ - { - "$ref": "#/definitions/MountType" - } - ] + "message": { + "description": "A user-facing message associated with the pause", + "title": "Message", + "type": "string" }, - "maintenancePosition": { - "description": "The position the gantry mount needs to move to.", - "default": "attachInstrument", - "allOf": [ - { - "$ref": "#/definitions/MaintenancePosition" - } - ] + "seconds": { + "description": "Duration, in seconds, to wait for.", + "title": "Seconds", + "type": "number" } }, - "required": ["mount"] + "required": ["seconds"], + "title": "WaitForDurationParams", + "type": "object" }, - "MoveToMaintenancePositionCreate": { - "title": "MoveToMaintenancePositionCreate", - "description": "Calibration set up position command creation request model.", - "type": "object", + "WaitForLidTemperatureCreate": { + "description": "A request to create Thermocycler's wait for lid temperature command.", "properties": { "commandType": { + "const": "thermocycler/waitForLidTemperature", + "default": "thermocycler/waitForLidTemperature", + "enum": ["thermocycler/waitForLidTemperature"], "title": "Commandtype", - "default": "calibration/moveToMaintenancePosition", - "enum": ["calibration/moveToMaintenancePosition"], "type": "string" }, - "params": { - "$ref": "#/definitions/MoveToMaintenancePositionParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/WaitForLidTemperatureParams" } }, - "required": ["params"] + "required": ["params"], + "title": "WaitForLidTemperatureCreate", + "type": "object" }, - "UnsafeBlowOutInPlaceParams": { - "title": "UnsafeBlowOutInPlaceParams", - "description": "Payload required to blow-out in place while position is unknown.", - "type": "object", + "WaitForLidTemperatureParams": { + "description": "Input parameters to wait for Thermocycler's lid temperature.", "properties": { - "flowRate": { - "title": "Flowrate", - "description": "Speed in \u00b5L/s configured for the pipette", - "exclusiveMinimum": 0, - "type": "number" - }, - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", + "moduleId": { + "description": "Unique ID of the Thermocycler Module.", + "title": "Moduleid", "type": "string" } }, - "required": ["flowRate", "pipetteId"] + "required": ["moduleId"], + "title": "WaitForLidTemperatureParams", + "type": "object" }, - "UnsafeBlowOutInPlaceCreate": { - "title": "UnsafeBlowOutInPlaceCreate", - "description": "UnsafeBlowOutInPlace command request model.", - "type": "object", + "WaitForResumeCreate": { + "description": "Wait for resume command request model.", "properties": { "commandType": { + "default": "waitForResume", + "enum": ["waitForResume", "pause"], "title": "Commandtype", - "default": "unsafe/blowOutInPlace", - "enum": ["unsafe/blowOutInPlace"], "type": "string" }, - "params": { - "$ref": "#/definitions/UnsafeBlowOutInPlaceParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/WaitForResumeParams" } }, - "required": ["params"] + "required": ["params"], + "title": "WaitForResumeCreate", + "type": "object" }, - "UnsafeDropTipInPlaceParams": { - "title": "UnsafeDropTipInPlaceParams", - "description": "Payload required to drop a tip in place even if the plunger position is not known.", - "type": "object", + "WaitForResumeParams": { + "description": "Payload required to pause the protocol.", "properties": { - "pipetteId": { - "title": "Pipetteid", - "description": "Identifier of pipette to use for liquid handling.", + "message": { + "description": "A user-facing message associated with the pause", + "title": "Message", "type": "string" + } + }, + "title": "WaitForResumeParams", + "type": "object" + }, + "WellLocation": { + "description": "A relative location in reference to a well's location.", + "properties": { + "offset": { + "$ref": "#/$defs/WellOffset" }, - "homeAfter": { - "title": "Homeafter", - "description": "Whether to home this pipette's plunger after dropping the tip. You should normally leave this unspecified to let the robot choose a safe default depending on its hardware.", - "type": "boolean" + "origin": { + "$ref": "#/$defs/WellOrigin", + "default": "top" + }, + "volumeOffset": { + "default": 0.0, + "description": "A volume of liquid, in \u00b5L, to offset the z-axis offset.", + "title": "Volumeoffset", + "type": "number" } }, - "required": ["pipetteId"] + "title": "WellLocation", + "type": "object" }, - "UnsafeDropTipInPlaceCreate": { - "title": "UnsafeDropTipInPlaceCreate", - "description": "Drop tip in place command creation request model.", - "type": "object", + "WellOffset": { + "description": "An offset vector in (x, y, z).", + "properties": { + "x": { + "default": 0, + "title": "X", + "type": "number" + }, + "y": { + "default": 0, + "title": "Y", + "type": "number" + }, + "z": { + "default": 0, + "title": "Z", + "type": "number" + } + }, + "title": "WellOffset", + "type": "object" + }, + "WellOrigin": { + "description": "Origin of WellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well\n MENISCUS: the meniscus-center of the well", + "enum": ["top", "bottom", "center", "meniscus"], + "title": "WellOrigin", + "type": "string" + }, + "closeGripperJawCreate": { + "description": "closeGripperJaw command request model.", "properties": { "commandType": { + "const": "robot/closeGripperJaw", + "default": "robot/closeGripperJaw", + "enum": ["robot/closeGripperJaw"], "title": "Commandtype", - "default": "unsafe/dropTipInPlace", - "enum": ["unsafe/dropTipInPlace"], "type": "string" }, - "params": { - "$ref": "#/definitions/UnsafeDropTipInPlaceParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/closeGripperJawParams" } }, - "required": ["params"] - }, - "UpdatePositionEstimatorsParams": { - "title": "UpdatePositionEstimatorsParams", - "description": "Payload required for an UpdatePositionEstimators command.", - "type": "object", + "required": ["params"], + "title": "closeGripperJawCreate", + "type": "object" + }, + "closeGripperJawParams": { + "description": "Payload required to close a gripper.", "properties": { - "axes": { - "description": "The axes for which to update the position estimators. Any axes that are not physically present will be ignored.", - "type": "array", - "items": { - "$ref": "#/definitions/MotorAxis" - } + "force": { + "description": "The force the gripper should use to hold the jaws, falls to default if none is provided.", + "title": "Force", + "type": "number" } }, - "required": ["axes"] + "title": "closeGripperJawParams", + "type": "object" }, - "UpdatePositionEstimatorsCreate": { - "title": "UpdatePositionEstimatorsCreate", - "description": "UpdatePositionEstimators command request model.", - "type": "object", + "openGripperJawCreate": { + "description": "openGripperJaw command request model.", "properties": { "commandType": { + "const": "robot/openGripperJaw", + "default": "robot/openGripperJaw", + "enum": ["robot/openGripperJaw"], "title": "Commandtype", - "default": "unsafe/updatePositionEstimators", - "enum": ["unsafe/updatePositionEstimators"], "type": "string" }, - "params": { - "$ref": "#/definitions/UpdatePositionEstimatorsParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/openGripperJawParams" } }, - "required": ["params"] + "required": ["params"], + "title": "openGripperJawCreate", + "type": "object" }, - "UnsafeEngageAxesParams": { - "title": "UnsafeEngageAxesParams", - "description": "Payload required for an UnsafeEngageAxes command.", - "type": "object", - "properties": { - "axes": { - "description": "The axes for which to enable.", - "type": "array", - "items": { - "$ref": "#/definitions/MotorAxis" - } - } - }, - "required": ["axes"] + "openGripperJawParams": { + "description": "Payload required to release a gripper.", + "properties": {}, + "title": "openGripperJawParams", + "type": "object" }, - "UnsafeEngageAxesCreate": { - "title": "UnsafeEngageAxesCreate", - "description": "UnsafeEngageAxes command request model.", - "type": "object", + "opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidCreate": { + "description": "A request to execute an Absorbance Reader close lid command.", "properties": { "commandType": { + "const": "absorbanceReader/closeLid", + "default": "absorbanceReader/closeLid", + "enum": ["absorbanceReader/closeLid"], "title": "Commandtype", - "default": "unsafe/engageAxes", - "enum": ["unsafe/engageAxes"], "type": "string" }, - "params": { - "$ref": "#/definitions/UnsafeEngageAxesParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidParams" } }, - "required": ["params"] + "required": ["params"], + "title": "CloseLidCreate", + "type": "object" }, - "UnsafeUngripLabwareParams": { - "title": "UnsafeUngripLabwareParams", - "description": "Payload required for an UngripLabware command.", - "type": "object", - "properties": {} + "opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidParams": { + "description": "Input parameters to close the lid on an absorbance reading.", + "properties": { + "moduleId": { + "description": "Unique ID of the absorbance reader.", + "title": "Moduleid", + "type": "string" + } + }, + "required": ["moduleId"], + "title": "CloseLidParams", + "type": "object" }, - "UnsafeUngripLabwareCreate": { - "title": "UnsafeUngripLabwareCreate", - "description": "UnsafeEngageAxes command request model.", - "type": "object", + "opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidCreate": { + "description": "A request to execute an Absorbance Reader open lid command.", "properties": { "commandType": { + "const": "absorbanceReader/openLid", + "default": "absorbanceReader/openLid", + "enum": ["absorbanceReader/openLid"], "title": "Commandtype", - "default": "unsafe/ungripLabware", - "enum": ["unsafe/ungripLabware"], "type": "string" }, - "params": { - "$ref": "#/definitions/UnsafeUngripLabwareParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidParams" } }, - "required": ["params"] + "required": ["params"], + "title": "OpenLidCreate", + "type": "object" }, - "UnsafePlaceLabwareParams": { - "title": "UnsafePlaceLabwareParams", - "description": "Payload required for an UnsafePlaceLabware command.", - "type": "object", + "opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidParams": { + "description": "Input parameters to open the lid on an absorbance reading.", "properties": { - "labwareURI": { - "title": "Labwareuri", - "description": "Labware URI for labware.", + "moduleId": { + "description": "Unique ID of the absorbance reader.", + "title": "Moduleid", "type": "string" - }, - "location": { - "title": "Location", - "description": "Where to place the labware.", - "anyOf": [ - { - "$ref": "#/definitions/DeckSlotLocation" - }, - { - "$ref": "#/definitions/ModuleLocation" - }, - { - "$ref": "#/definitions/OnLabwareLocation" - }, - { - "$ref": "#/definitions/AddressableAreaLocation" - } - ] } }, - "required": ["labwareURI", "location"] + "required": ["moduleId"], + "title": "OpenLidParams", + "type": "object" }, - "UnsafePlaceLabwareCreate": { - "title": "UnsafePlaceLabwareCreate", - "description": "UnsafePlaceLabware command request model.", - "type": "object", + "opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureCreate": { + "description": "A request to create a Heater-Shaker's set temperature command.", "properties": { "commandType": { + "const": "heaterShaker/setTargetTemperature", + "default": "heaterShaker/setTargetTemperature", + "enum": ["heaterShaker/setTargetTemperature"], "title": "Commandtype", - "default": "unsafe/placeLabware", - "enum": ["unsafe/placeLabware"], "type": "string" }, - "params": { - "$ref": "#/definitions/UnsafePlaceLabwareParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureParams" } }, - "required": ["params"] + "required": ["params"], + "title": "SetTargetTemperatureCreate", + "type": "object" }, - "MoveAxesRelativeParams": { - "title": "MoveAxesRelativeParams", - "description": "Payload required to move axes relative to position.", - "type": "object", + "opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureParams": { + "description": "Input parameters to set a Heater-Shaker's target temperature.", "properties": { - "axis_map": { - "title": "Axis Map", - "description": "A dictionary mapping axes to relative movements in mm.", - "type": "object", - "additionalProperties": { - "type": "number" - } - }, - "speed": { - "title": "Speed", - "description": "The max velocity to move the axes at. Will fall to hardware defaults if none provided.", + "celsius": { + "description": "Target temperature in \u00b0C.", + "title": "Celsius", "type": "number" + }, + "moduleId": { + "description": "Unique ID of the Heater-Shaker Module.", + "title": "Moduleid", + "type": "string" } }, - "required": ["axis_map"] + "required": ["moduleId", "celsius"], + "title": "SetTargetTemperatureParams", + "type": "object" }, - "MoveAxesRelativeCreate": { - "title": "MoveAxesRelativeCreate", - "description": "MoveAxesRelative command request model.", - "type": "object", + "opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureCreate": { + "description": "A request to create a Heater-Shaker's wait for temperature command.", "properties": { "commandType": { + "const": "heaterShaker/waitForTemperature", + "default": "heaterShaker/waitForTemperature", + "enum": ["heaterShaker/waitForTemperature"], "title": "Commandtype", - "default": "robot/moveAxesRelative", - "enum": ["robot/moveAxesRelative"], "type": "string" }, - "params": { - "$ref": "#/definitions/MoveAxesRelativeParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureParams" } }, - "required": ["params"] + "required": ["params"], + "title": "WaitForTemperatureCreate", + "type": "object" }, - "MoveAxesToParams": { - "title": "MoveAxesToParams", - "description": "Payload required to move axes to absolute position.", - "type": "object", + "opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureParams": { + "description": "Input parameters to wait for a Heater-Shaker's target temperature.", "properties": { - "axis_map": { - "title": "Axis Map", - "description": "The specified axes to move to an absolute deck position with.", - "type": "object", - "additionalProperties": { - "type": "number" - } - }, - "critical_point": { - "title": "Critical Point", - "description": "The critical point to move the mount with.", - "type": "object", - "additionalProperties": { - "type": "number" - } - }, - "speed": { - "title": "Speed", - "description": "The max velocity to move the axes at. Will fall to hardware defaults if none provided.", + "celsius": { + "description": "Target temperature in \u00b0C. If not specified, will default to the module's target temperature. Specifying a celsius parameter other than the target temperature could lead to unpredictable behavior and hence is not recommended for use. This parameter can be removed in a future version without prior notice.", + "title": "Celsius", "type": "number" + }, + "moduleId": { + "description": "Unique ID of the Heater-Shaker Module.", + "title": "Moduleid", + "type": "string" } }, - "required": ["axis_map"] + "required": ["moduleId"], + "title": "WaitForTemperatureParams", + "type": "object" }, - "MoveAxesToCreate": { - "title": "MoveAxesToCreate", - "description": "MoveAxesTo command request model.", - "type": "object", + "opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureCreate": { + "description": "A request to create a Temperature Module's set temperature command.", "properties": { "commandType": { + "const": "temperatureModule/setTargetTemperature", + "default": "temperatureModule/setTargetTemperature", + "enum": ["temperatureModule/setTargetTemperature"], "title": "Commandtype", - "default": "robot/moveAxesTo", - "enum": ["robot/moveAxesTo"], "type": "string" }, - "params": { - "$ref": "#/definitions/MoveAxesToParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureParams" } }, - "required": ["params"] + "required": ["params"], + "title": "SetTargetTemperatureCreate", + "type": "object" }, - "MoveToParams": { - "title": "MoveToParams", - "description": "Payload required to move to a destination position.", - "type": "object", + "opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureParams": { + "description": "Input parameters to set a Temperature Module's target temperature.", "properties": { - "mount": { - "description": "The mount to move to the destination point.", - "allOf": [ - { - "$ref": "#/definitions/MountType" - } - ] - }, - "destination": { - "title": "Destination", - "description": "X, Y and Z coordinates in mm from deck's origin location (left-front-bottom corner of work space)", - "allOf": [ - { - "$ref": "#/definitions/DeckPoint" - } - ] - }, - "speed": { - "title": "Speed", - "description": "The max velocity to move the axes at. Will fall to hardware defaults if none provided.", + "celsius": { + "description": "Target temperature in \u00b0C.", + "title": "Celsius", "type": "number" + }, + "moduleId": { + "description": "Unique ID of the Temperature Module.", + "title": "Moduleid", + "type": "string" } }, - "required": ["mount", "destination"] + "required": ["moduleId", "celsius"], + "title": "SetTargetTemperatureParams", + "type": "object" }, - "MoveToCreate": { - "title": "MoveToCreate", - "description": "MoveTo command request model.", - "type": "object", + "opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureCreate": { + "description": "A request to create a Temperature Module's wait for temperature command.", "properties": { "commandType": { - "title": "Commandtype", - "default": "robot/moveTo", - "enum": ["robot/moveTo"], + "const": "temperatureModule/waitForTemperature", + "default": "temperatureModule/waitForTemperature", + "enum": ["temperatureModule/waitForTemperature"], + "title": "Commandtype", "type": "string" }, - "params": { - "$ref": "#/definitions/MoveToParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureParams" } }, - "required": ["params"] + "required": ["params"], + "title": "WaitForTemperatureCreate", + "type": "object" }, - "openGripperJawParams": { - "title": "openGripperJawParams", - "description": "Payload required to release a gripper.", - "type": "object", - "properties": {} + "opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureParams": { + "description": "Input parameters to wait for a Temperature Module's target temperature.", + "properties": { + "celsius": { + "description": "Target temperature in \u00b0C. If not specified, will default to the module's target temperature. Specifying a celsius parameter other than the target temperature could lead to unpredictable behavior and hence is not recommended for use. This parameter can be removed in a future version without prior notice.", + "title": "Celsius", + "type": "number" + }, + "moduleId": { + "description": "Unique ID of the Temperature Module.", + "title": "Moduleid", + "type": "string" + } + }, + "required": ["moduleId"], + "title": "WaitForTemperatureParams", + "type": "object" }, - "openGripperJawCreate": { - "title": "openGripperJawCreate", - "description": "openGripperJaw command request model.", - "type": "object", + "opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidCreate": { + "description": "A request to close a Thermocycler's lid.", "properties": { "commandType": { + "const": "thermocycler/closeLid", + "default": "thermocycler/closeLid", + "enum": ["thermocycler/closeLid"], "title": "Commandtype", - "default": "robot/openGripperJaw", - "enum": ["robot/openGripperJaw"], "type": "string" }, - "params": { - "$ref": "#/definitions/openGripperJawParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", "type": "string" + }, + "params": { + "$ref": "#/$defs/opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidParams" } }, - "required": ["params"] + "required": ["params"], + "title": "CloseLidCreate", + "type": "object" }, - "closeGripperJawParams": { - "title": "closeGripperJawParams", - "description": "Payload required to close a gripper.", - "type": "object", + "opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidParams": { + "description": "Input parameters to close a Thermocycler's lid.", "properties": { - "force": { - "title": "Force", - "description": "The force the gripper should use to hold the jaws, falls to default if none is provided.", - "type": "number" + "moduleId": { + "description": "Unique ID of the Thermocycler.", + "title": "Moduleid", + "type": "string" } - } + }, + "required": ["moduleId"], + "title": "CloseLidParams", + "type": "object" }, - "closeGripperJawCreate": { - "title": "closeGripperJawCreate", - "description": "closeGripperJaw command request model.", - "type": "object", + "opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidCreate": { + "description": "A request to open a Thermocycler's lid.", "properties": { "commandType": { + "const": "thermocycler/openLid", + "default": "thermocycler/openLid", + "enum": ["thermocycler/openLid"], "title": "Commandtype", - "default": "robot/closeGripperJaw", - "enum": ["robot/closeGripperJaw"], "type": "string" }, - "params": { - "$ref": "#/definitions/closeGripperJawParams" - }, "intent": { + "$ref": "#/$defs/CommandIntent", "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", - "allOf": [ - { - "$ref": "#/definitions/CommandIntent" - } - ] + "title": "Intent" }, "key": { - "title": "Key", "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "title": "Key", + "type": "string" + }, + "params": { + "$ref": "#/$defs/opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidParams" + } + }, + "required": ["params"], + "title": "OpenLidCreate", + "type": "object" + }, + "opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidParams": { + "description": "Input parameters to open a Thermocycler's lid.", + "properties": { + "moduleId": { + "description": "Unique ID of the Thermocycler.", + "title": "Moduleid", "type": "string" } }, - "required": ["params"] + "required": ["moduleId"], + "title": "OpenLidParams", + "type": "object" } }, "$id": "opentronsCommandSchemaV11", - "$schema": "http://json-schema.org/draft-07/schema#" + "$schema": "http://json-schema.org/draft-07/schema#", + "discriminator": { + "mapping": { + "absorbanceReader/closeLid": "#/$defs/opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidCreate", + "absorbanceReader/initialize": "#/$defs/InitializeCreate", + "absorbanceReader/openLid": "#/$defs/opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidCreate", + "absorbanceReader/read": "#/$defs/ReadAbsorbanceCreate", + "airGapInPlace": "#/$defs/AirGapInPlaceCreate", + "aspirate": "#/$defs/AspirateCreate", + "aspirateInPlace": "#/$defs/AspirateInPlaceCreate", + "blowOutInPlace": "#/$defs/BlowOutInPlaceCreate", + "blowout": "#/$defs/BlowOutCreate", + "calibration/calibrateGripper": "#/$defs/CalibrateGripperCreate", + "calibration/calibrateModule": "#/$defs/CalibrateModuleCreate", + "calibration/calibratePipette": "#/$defs/CalibratePipetteCreate", + "calibration/moveToMaintenancePosition": "#/$defs/MoveToMaintenancePositionCreate", + "comment": "#/$defs/CommentCreate", + "configureForVolume": "#/$defs/ConfigureForVolumeCreate", + "configureNozzleLayout": "#/$defs/ConfigureNozzleLayoutCreate", + "custom": "#/$defs/CustomCreate", + "dispense": "#/$defs/DispenseCreate", + "dispenseInPlace": "#/$defs/DispenseInPlaceCreate", + "dropTip": "#/$defs/DropTipCreate", + "dropTipInPlace": "#/$defs/DropTipInPlaceCreate", + "getNextTip": "#/$defs/GetNextTipCreate", + "getTipPresence": "#/$defs/GetTipPresenceCreate", + "heaterShaker/closeLabwareLatch": "#/$defs/CloseLabwareLatchCreate", + "heaterShaker/deactivateHeater": "#/$defs/DeactivateHeaterCreate", + "heaterShaker/deactivateShaker": "#/$defs/DeactivateShakerCreate", + "heaterShaker/openLabwareLatch": "#/$defs/OpenLabwareLatchCreate", + "heaterShaker/setAndWaitForShakeSpeed": "#/$defs/SetAndWaitForShakeSpeedCreate", + "heaterShaker/setTargetTemperature": "#/$defs/opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureCreate", + "heaterShaker/waitForTemperature": "#/$defs/opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureCreate", + "home": "#/$defs/HomeCreate", + "liquidProbe": "#/$defs/LiquidProbeCreate", + "loadLabware": "#/$defs/LoadLabwareCreate", + "loadLiquid": "#/$defs/LoadLiquidCreate", + "loadLiquidClass": "#/$defs/LoadLiquidClassCreate", + "loadModule": "#/$defs/LoadModuleCreate", + "loadPipette": "#/$defs/LoadPipetteCreate", + "magneticModule/disengage": "#/$defs/DisengageCreate", + "magneticModule/engage": "#/$defs/EngageCreate", + "moveLabware": "#/$defs/MoveLabwareCreate", + "moveRelative": "#/$defs/MoveRelativeCreate", + "moveToAddressableArea": "#/$defs/MoveToAddressableAreaCreate", + "moveToAddressableAreaForDropTip": "#/$defs/MoveToAddressableAreaForDropTipCreate", + "moveToCoordinates": "#/$defs/MoveToCoordinatesCreate", + "moveToWell": "#/$defs/MoveToWellCreate", + "pause": "#/$defs/WaitForResumeCreate", + "pickUpTip": "#/$defs/PickUpTipCreate", + "prepareToAspirate": "#/$defs/PrepareToAspirateCreate", + "reloadLabware": "#/$defs/ReloadLabwareCreate", + "retractAxis": "#/$defs/RetractAxisCreate", + "robot/closeGripperJaw": "#/$defs/closeGripperJawCreate", + "robot/moveAxesRelative": "#/$defs/MoveAxesRelativeCreate", + "robot/moveAxesTo": "#/$defs/MoveAxesToCreate", + "robot/moveTo": "#/$defs/MoveToCreate", + "robot/openGripperJaw": "#/$defs/openGripperJawCreate", + "savePosition": "#/$defs/SavePositionCreate", + "setRailLights": "#/$defs/SetRailLightsCreate", + "setStatusBar": "#/$defs/SetStatusBarCreate", + "temperatureModule/deactivate": "#/$defs/DeactivateTemperatureCreate", + "temperatureModule/setTargetTemperature": "#/$defs/opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureCreate", + "temperatureModule/waitForTemperature": "#/$defs/opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureCreate", + "thermocycler/closeLid": "#/$defs/opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidCreate", + "thermocycler/deactivateBlock": "#/$defs/DeactivateBlockCreate", + "thermocycler/deactivateLid": "#/$defs/DeactivateLidCreate", + "thermocycler/openLid": "#/$defs/opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidCreate", + "thermocycler/runExtendedProfile": "#/$defs/RunExtendedProfileCreate", + "thermocycler/runProfile": "#/$defs/RunProfileCreate", + "thermocycler/setTargetBlockTemperature": "#/$defs/SetTargetBlockTemperatureCreate", + "thermocycler/setTargetLidTemperature": "#/$defs/SetTargetLidTemperatureCreate", + "thermocycler/waitForBlockTemperature": "#/$defs/WaitForBlockTemperatureCreate", + "thermocycler/waitForLidTemperature": "#/$defs/WaitForLidTemperatureCreate", + "touchTip": "#/$defs/TouchTipCreate", + "tryLiquidProbe": "#/$defs/TryLiquidProbeCreate", + "unsafe/blowOutInPlace": "#/$defs/UnsafeBlowOutInPlaceCreate", + "unsafe/dropTipInPlace": "#/$defs/UnsafeDropTipInPlaceCreate", + "unsafe/engageAxes": "#/$defs/UnsafeEngageAxesCreate", + "unsafe/placeLabware": "#/$defs/UnsafePlaceLabwareCreate", + "unsafe/ungripLabware": "#/$defs/UnsafeUngripLabwareCreate", + "unsafe/updatePositionEstimators": "#/$defs/UpdatePositionEstimatorsCreate", + "verifyTipPresence": "#/$defs/VerifyTipPresenceCreate", + "waitForDuration": "#/$defs/WaitForDurationCreate", + "waitForResume": "#/$defs/WaitForResumeCreate" + }, + "propertyName": "commandType" + }, + "oneOf": [ + { + "$ref": "#/$defs/AirGapInPlaceCreate" + }, + { + "$ref": "#/$defs/AspirateCreate" + }, + { + "$ref": "#/$defs/AspirateInPlaceCreate" + }, + { + "$ref": "#/$defs/CommentCreate" + }, + { + "$ref": "#/$defs/ConfigureForVolumeCreate" + }, + { + "$ref": "#/$defs/ConfigureNozzleLayoutCreate" + }, + { + "$ref": "#/$defs/CustomCreate" + }, + { + "$ref": "#/$defs/DispenseCreate" + }, + { + "$ref": "#/$defs/DispenseInPlaceCreate" + }, + { + "$ref": "#/$defs/BlowOutCreate" + }, + { + "$ref": "#/$defs/BlowOutInPlaceCreate" + }, + { + "$ref": "#/$defs/DropTipCreate" + }, + { + "$ref": "#/$defs/DropTipInPlaceCreate" + }, + { + "$ref": "#/$defs/HomeCreate" + }, + { + "$ref": "#/$defs/RetractAxisCreate" + }, + { + "$ref": "#/$defs/LoadLabwareCreate" + }, + { + "$ref": "#/$defs/ReloadLabwareCreate" + }, + { + "$ref": "#/$defs/LoadLiquidCreate" + }, + { + "$ref": "#/$defs/LoadLiquidClassCreate" + }, + { + "$ref": "#/$defs/LoadModuleCreate" + }, + { + "$ref": "#/$defs/LoadPipetteCreate" + }, + { + "$ref": "#/$defs/MoveLabwareCreate" + }, + { + "$ref": "#/$defs/MoveRelativeCreate" + }, + { + "$ref": "#/$defs/MoveToCoordinatesCreate" + }, + { + "$ref": "#/$defs/MoveToWellCreate" + }, + { + "$ref": "#/$defs/MoveToAddressableAreaCreate" + }, + { + "$ref": "#/$defs/MoveToAddressableAreaForDropTipCreate" + }, + { + "$ref": "#/$defs/PrepareToAspirateCreate" + }, + { + "$ref": "#/$defs/WaitForResumeCreate" + }, + { + "$ref": "#/$defs/WaitForDurationCreate" + }, + { + "$ref": "#/$defs/PickUpTipCreate" + }, + { + "$ref": "#/$defs/SavePositionCreate" + }, + { + "$ref": "#/$defs/SetRailLightsCreate" + }, + { + "$ref": "#/$defs/TouchTipCreate" + }, + { + "$ref": "#/$defs/SetStatusBarCreate" + }, + { + "$ref": "#/$defs/VerifyTipPresenceCreate" + }, + { + "$ref": "#/$defs/GetTipPresenceCreate" + }, + { + "$ref": "#/$defs/GetNextTipCreate" + }, + { + "$ref": "#/$defs/LiquidProbeCreate" + }, + { + "$ref": "#/$defs/TryLiquidProbeCreate" + }, + { + "$ref": "#/$defs/opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureCreate" + }, + { + "$ref": "#/$defs/opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureCreate" + }, + { + "$ref": "#/$defs/DeactivateHeaterCreate" + }, + { + "$ref": "#/$defs/SetAndWaitForShakeSpeedCreate" + }, + { + "$ref": "#/$defs/DeactivateShakerCreate" + }, + { + "$ref": "#/$defs/OpenLabwareLatchCreate" + }, + { + "$ref": "#/$defs/CloseLabwareLatchCreate" + }, + { + "$ref": "#/$defs/DisengageCreate" + }, + { + "$ref": "#/$defs/EngageCreate" + }, + { + "$ref": "#/$defs/opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureCreate" + }, + { + "$ref": "#/$defs/opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureCreate" + }, + { + "$ref": "#/$defs/DeactivateTemperatureCreate" + }, + { + "$ref": "#/$defs/SetTargetBlockTemperatureCreate" + }, + { + "$ref": "#/$defs/WaitForBlockTemperatureCreate" + }, + { + "$ref": "#/$defs/SetTargetLidTemperatureCreate" + }, + { + "$ref": "#/$defs/WaitForLidTemperatureCreate" + }, + { + "$ref": "#/$defs/DeactivateBlockCreate" + }, + { + "$ref": "#/$defs/DeactivateLidCreate" + }, + { + "$ref": "#/$defs/opentrons__protocol_engine__commands__thermocycler__open_lid__OpenLidCreate" + }, + { + "$ref": "#/$defs/opentrons__protocol_engine__commands__thermocycler__close_lid__CloseLidCreate" + }, + { + "$ref": "#/$defs/RunProfileCreate" + }, + { + "$ref": "#/$defs/RunExtendedProfileCreate" + }, + { + "$ref": "#/$defs/opentrons__protocol_engine__commands__absorbance_reader__close_lid__CloseLidCreate" + }, + { + "$ref": "#/$defs/opentrons__protocol_engine__commands__absorbance_reader__open_lid__OpenLidCreate" + }, + { + "$ref": "#/$defs/InitializeCreate" + }, + { + "$ref": "#/$defs/ReadAbsorbanceCreate" + }, + { + "$ref": "#/$defs/CalibrateGripperCreate" + }, + { + "$ref": "#/$defs/CalibratePipetteCreate" + }, + { + "$ref": "#/$defs/CalibrateModuleCreate" + }, + { + "$ref": "#/$defs/MoveToMaintenancePositionCreate" + }, + { + "$ref": "#/$defs/UnsafeBlowOutInPlaceCreate" + }, + { + "$ref": "#/$defs/UnsafeDropTipInPlaceCreate" + }, + { + "$ref": "#/$defs/UpdatePositionEstimatorsCreate" + }, + { + "$ref": "#/$defs/UnsafeEngageAxesCreate" + }, + { + "$ref": "#/$defs/UnsafeUngripLabwareCreate" + }, + { + "$ref": "#/$defs/UnsafePlaceLabwareCreate" + }, + { + "$ref": "#/$defs/MoveAxesRelativeCreate" + }, + { + "$ref": "#/$defs/MoveAxesToCreate" + }, + { + "$ref": "#/$defs/MoveToCreate" + }, + { + "$ref": "#/$defs/openGripperJawCreate" + }, + { + "$ref": "#/$defs/closeGripperJawCreate" + } + ] } diff --git a/shared-data/python/Pipfile b/shared-data/python/Pipfile index dff2c2318bd..36fe4d3a4c2 100644 --- a/shared-data/python/Pipfile +++ b/shared-data/python/Pipfile @@ -4,7 +4,7 @@ verify_ssl = true name = "pypi" [dev-packages] -mypy = "==1.8.0" +mypy = "==1.11.0" flake8 = "~=7.0.0" flake8-annotations = "~=3.0.1" flake8-docstrings = "~=1.7.0" @@ -27,5 +27,5 @@ pytest-clarity = "~=1.0.0" [packages] opentrons-shared-data = { editable = true, path = "." } jsonschema = "==4.21.1" -pydantic = "==1.10.12" +pydantic = "==2.9.0" numpy = "==1.22.3" diff --git a/shared-data/python/Pipfile.lock b/shared-data/python/Pipfile.lock index 43ce052e327..be15adba052 100644 --- a/shared-data/python/Pipfile.lock +++ b/shared-data/python/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9b5174a247c5fe717a5db26f523afd532a6b0fc27943d86f6588839785ef51f4" + "sha256": "26e2a27ca64e01b1f0274cbbe632e28a6d15977ac1d4eecdc5077dd3acb6e364" }, "pipfile-spec": 6, "requires": {}, @@ -14,13 +14,21 @@ ] }, "default": { + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "jsonschema": { "hashes": [ @@ -33,11 +41,11 @@ }, "jsonschema-specifications": { "hashes": [ - "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc", - "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" + "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", + "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" ], - "markers": "python_version >= '3.8'", - "version": "==2023.12.1" + "markers": "python_version >= '3.9'", + "version": "==2024.10.1" }, "numpy": { "hashes": [ @@ -68,172 +76,245 @@ }, "opentrons-shared-data": { "editable": true, - "markers": "python_version >= '3.7'", + "markers": "python_version >= '3.10'", "path": "." }, "pydantic": { "hashes": [ - "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303", - "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe", - "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47", - "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494", - "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33", - "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86", - "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d", - "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c", - "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a", - "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565", - "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb", - "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62", - "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62", - "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0", - "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523", - "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d", - "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405", - "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f", - "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b", - "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718", - "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed", - "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb", - "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5", - "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc", - "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942", - "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe", - "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246", - "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350", - "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303", - "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09", - "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33", - "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8", - "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a", - "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1", - "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6", - "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d" + "sha256:c7a8a9fdf7d100afa49647eae340e2d23efa382466a8d177efcd1381e9be5598", + "sha256:f66a7073abd93214a20c5f7b32d56843137a7a2e70d02111f3be287035c45370" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.10.12" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" + }, + "pydantic-core": { + "hashes": [ + "sha256:0102e49ac7d2df3379ef8d658d3bc59d3d769b0bdb17da189b75efa861fc07b4", + "sha256:0123655fedacf035ab10c23450163c2f65a4174f2bb034b188240a6cf06bb123", + "sha256:043ef8469f72609c4c3a5e06a07a1f713d53df4d53112c6d49207c0bd3c3bd9b", + "sha256:0448b81c3dfcde439551bb04a9f41d7627f676b12701865c8a2574bcea034437", + "sha256:05b366fb8fe3d8683b11ac35fa08947d7b92be78ec64e3277d03bd7f9b7cda79", + "sha256:07049ec9306ec64e955b2e7c40c8d77dd78ea89adb97a2013d0b6e055c5ee4c5", + "sha256:084414ffe9a85a52940b49631321d636dadf3576c30259607b75516d131fecd0", + "sha256:086c5db95157dc84c63ff9d96ebb8856f47ce113c86b61065a066f8efbe80acf", + "sha256:12625e69b1199e94b0ae1c9a95d000484ce9f0182f9965a26572f054b1537e44", + "sha256:16b25a4a120a2bb7dab51b81e3d9f3cde4f9a4456566c403ed29ac81bf49744f", + "sha256:19f1352fe4b248cae22a89268720fc74e83f008057a652894f08fa931e77dced", + "sha256:1a2ab4f410f4b886de53b6bddf5dd6f337915a29dd9f22f20f3099659536b2f6", + "sha256:1c7b81beaf7c7ebde978377dc53679c6cba0e946426fc7ade54251dfe24a7604", + "sha256:1cf842265a3a820ebc6388b963ead065f5ce8f2068ac4e1c713ef77a67b71f7c", + "sha256:1eb37f7d6a8001c0f86dc8ff2ee8d08291a536d76e49e78cda8587bb54d8b329", + "sha256:23af245b8f2f4ee9e2c99cb3f93d0e22fb5c16df3f2f643f5a8da5caff12a653", + "sha256:257d6a410a0d8aeb50b4283dea39bb79b14303e0fab0f2b9d617701331ed1515", + "sha256:276ae78153a94b664e700ac362587c73b84399bd1145e135287513442e7dfbc7", + "sha256:2b1a195efd347ede8bcf723e932300292eb13a9d2a3c1f84eb8f37cbbc905b7f", + "sha256:329a721253c7e4cbd7aad4a377745fbcc0607f9d72a3cc2102dd40519be75ed2", + "sha256:358331e21a897151e54d58e08d0219acf98ebb14c567267a87e971f3d2a3be59", + "sha256:3649bd3ae6a8ebea7dc381afb7f3c6db237fc7cebd05c8ac36ca8a4187b03b30", + "sha256:3713dc093d5048bfaedbba7a8dbc53e74c44a140d45ede020dc347dda18daf3f", + "sha256:3ef71ec876fcc4d3bbf2ae81961959e8d62f8d74a83d116668409c224012e3af", + "sha256:41ae8537ad371ec018e3c5da0eb3f3e40ee1011eb9be1da7f965357c4623c501", + "sha256:4a801c5e1e13272e0909c520708122496647d1279d252c9e6e07dac216accc41", + "sha256:4c83c64d05ffbbe12d4e8498ab72bdb05bcc1026340a4a597dc647a13c1605ec", + "sha256:4cebb9794f67266d65e7e4cbe5dcf063e29fc7b81c79dc9475bd476d9534150e", + "sha256:5668b3173bb0b2e65020b60d83f5910a7224027232c9f5dc05a71a1deac9f960", + "sha256:56e6a12ec8d7679f41b3750ffa426d22b44ef97be226a9bab00a03365f217b2b", + "sha256:582871902e1902b3c8e9b2c347f32a792a07094110c1bca6c2ea89b90150caac", + "sha256:5c8aa40f6ca803f95b1c1c5aeaee6237b9e879e4dfb46ad713229a63651a95fb", + "sha256:5d813fd871b3d5c3005157622ee102e8908ad6011ec915a18bd8fde673c4360e", + "sha256:5dd0ec5f514ed40e49bf961d49cf1bc2c72e9b50f29a163b2cc9030c6742aa73", + "sha256:5f3cf3721eaf8741cffaf092487f1ca80831202ce91672776b02b875580e174a", + "sha256:6294907eaaccf71c076abdd1c7954e272efa39bb043161b4b8aa1cd76a16ce43", + "sha256:64d094ea1aa97c6ded4748d40886076a931a8bf6f61b6e43e4a1041769c39dd2", + "sha256:6650a7bbe17a2717167e3e23c186849bae5cef35d38949549f1c116031b2b3aa", + "sha256:67b6655311b00581914aba481729971b88bb8bc7996206590700a3ac85e457b8", + "sha256:6b06c5d4e8701ac2ba99a2ef835e4e1b187d41095a9c619c5b185c9068ed2a49", + "sha256:6ce883906810b4c3bd90e0ada1f9e808d9ecf1c5f0b60c6b8831d6100bcc7dd6", + "sha256:6db09153d8438425e98cdc9a289c5fade04a5d2128faff8f227c459da21b9703", + "sha256:6f80fba4af0cb1d2344869d56430e304a51396b70d46b91a55ed4959993c0589", + "sha256:743e5811b0c377eb830150d675b0847a74a44d4ad5ab8845923d5b3a756d8100", + "sha256:753294d42fb072aa1775bfe1a2ba1012427376718fa4c72de52005a3d2a22178", + "sha256:7568f682c06f10f30ef643a1e8eec4afeecdafde5c4af1b574c6df079e96f96c", + "sha256:7706e15cdbf42f8fab1e6425247dfa98f4a6f8c63746c995d6a2017f78e619ae", + "sha256:785e7f517ebb9890813d31cb5d328fa5eda825bb205065cde760b3150e4de1f7", + "sha256:7a05c0240f6c711eb381ac392de987ee974fa9336071fb697768dfdb151345ce", + "sha256:7ce7eaf9a98680b4312b7cebcdd9352531c43db00fca586115845df388f3c465", + "sha256:7ce8e26b86a91e305858e018afc7a6e932f17428b1eaa60154bd1f7ee888b5f8", + "sha256:7d0324a35ab436c9d768753cbc3c47a865a2cbc0757066cb864747baa61f6ece", + "sha256:7e9b24cca4037a561422bf5dc52b38d390fb61f7bfff64053ce1b72f6938e6b2", + "sha256:810ca06cca91de9107718dc83d9ac4d2e86efd6c02cba49a190abcaf33fb0472", + "sha256:820f6ee5c06bc868335e3b6e42d7ef41f50dfb3ea32fbd523ab679d10d8741c0", + "sha256:82764c0bd697159fe9947ad59b6db6d7329e88505c8f98990eb07e84cc0a5d81", + "sha256:8ae65fdfb8a841556b52935dfd4c3f79132dc5253b12c0061b96415208f4d622", + "sha256:8d5b0ff3218858859910295df6953d7bafac3a48d5cd18f4e3ed9999efd2245f", + "sha256:95d6bf449a1ac81de562d65d180af5d8c19672793c81877a2eda8fde5d08f2fd", + "sha256:964c7aa318da542cdcc60d4a648377ffe1a2ef0eb1e996026c7f74507b720a78", + "sha256:96ef39add33ff58cd4c112cbac076726b96b98bb8f1e7f7595288dcfb2f10b57", + "sha256:a6612c2a844043e4d10a8324c54cdff0042c558eef30bd705770793d70b224aa", + "sha256:a8031074a397a5925d06b590121f8339d34a5a74cfe6970f8a1124eb8b83f4ac", + "sha256:aab9e522efff3993a9e98ab14263d4e20211e62da088298089a03056980a3e69", + "sha256:ae579143826c6f05a361d9546446c432a165ecf1c0b720bbfd81152645cb897d", + "sha256:ae90b9e50fe1bd115b24785e962b51130340408156d34d67b5f8f3fa6540938e", + "sha256:b18cf68255a476b927910c6873d9ed00da692bb293c5b10b282bd48a0afe3ae2", + "sha256:b7efb12e5071ad8d5b547487bdad489fbd4a5a35a0fc36a1941517a6ad7f23e0", + "sha256:c4d9f15ffe68bcd3898b0ad7233af01b15c57d91cd1667f8d868e0eacbfe3f87", + "sha256:c53100c8ee5a1e102766abde2158077d8c374bee0639201f11d3032e3555dfbc", + "sha256:c57e493a0faea1e4c38f860d6862ba6832723396c884fbf938ff5e9b224200e2", + "sha256:c8319e0bd6a7b45ad76166cc3d5d6a36c97d0c82a196f478c3ee5346566eebfd", + "sha256:caffda619099cfd4f63d48462f6aadbecee3ad9603b4b88b60cb821c1b258576", + "sha256:cc0c316fba3ce72ac3ab7902a888b9dc4979162d320823679da270c2d9ad0cad", + "sha256:cdd02a08205dc90238669f082747612cb3c82bd2c717adc60f9b9ecadb540f80", + "sha256:d50ac34835c6a4a0d456b5db559b82047403c4317b3bc73b3455fefdbdc54b0a", + "sha256:d6b9dd6aa03c812017411734e496c44fef29b43dba1e3dd1fa7361bbacfc1354", + "sha256:da3131ef2b940b99106f29dfbc30d9505643f766704e14c5d5e504e6a480c35e", + "sha256:da43cbe593e3c87d07108d0ebd73771dc414488f1f91ed2e204b0370b94b37ac", + "sha256:dd59638025160056687d598b054b64a79183f8065eae0d3f5ca523cde9943940", + "sha256:e1895e949f8849bc2757c0dbac28422a04be031204df46a56ab34bcf98507342", + "sha256:e1a79ad49f346aa1a2921f31e8dbbab4d64484823e813a002679eaa46cba39e1", + "sha256:e460475719721d59cd54a350c1f71c797c763212c836bf48585478c5514d2854", + "sha256:e64ffaf8f6e17ca15eb48344d86a7a741454526f3a3fa56bc493ad9d7ec63936", + "sha256:e6e3ccebdbd6e53474b0bb7ab8b88e83c0cfe91484b25e058e581348ee5a01a5", + "sha256:e758d271ed0286d146cf7c04c539a5169a888dd0b57026be621547e756af55bc", + "sha256:f087879f1ffde024dd2788a30d55acd67959dcf6c431e9d3682d1c491a0eb474", + "sha256:f477d26183e94eaafc60b983ab25af2a809a1b48ce4debb57b343f671b7a90b6", + "sha256:fc535cb898ef88333cf317777ecdfe0faac1c2a3187ef7eb061b6f7ecf7e6bae" + ], + "markers": "python_version >= '3.8'", + "version": "==2.23.2" }, "referencing": { "hashes": [ - "sha256:3c57da0513e9563eb7e203ebe9bb3a1b509b042016433bd1e45a2853466c3dd3", - "sha256:7e4dc12271d8e15612bfe35792f5ea1c40970dadf8624602e33db2758f7ee554" + "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", + "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" ], "markers": "python_version >= '3.8'", - "version": "==0.32.1" + "version": "==0.35.1" }, "rpds-py": { "hashes": [ - "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147", - "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7", - "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2", - "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68", - "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1", - "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382", - "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d", - "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921", - "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38", - "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4", - "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a", - "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d", - "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518", - "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e", - "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d", - "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf", - "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5", - "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba", - "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6", - "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59", - "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253", - "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6", - "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f", - "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3", - "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea", - "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1", - "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76", - "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93", - "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad", - "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad", - "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc", - "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049", - "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d", - "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90", - "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d", - "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd", - "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25", - "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2", - "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f", - "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6", - "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4", - "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c", - "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8", - "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d", - "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b", - "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19", - "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453", - "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9", - "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde", - "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296", - "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58", - "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec", - "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99", - "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a", - "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb", - "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383", - "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d", - "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896", - "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc", - "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6", - "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b", - "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7", - "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22", - "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf", - "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394", - "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0", - "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57", - "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74", - "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83", - "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29", - "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9", - "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f", - "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745", - "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb", - "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811", - "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55", - "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342", - "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23", - "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82", - "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041", - "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb", - "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066", - "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55", - "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6", - "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a", - "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140", - "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b", - "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9", - "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256", - "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c", - "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772", - "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4", - "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae", - "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920", - "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a", - "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b", - "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361", - "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8", - "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a" + "sha256:02a0629ec053fc013808a85178524e3cb63a61dbc35b22499870194a63578fb9", + "sha256:07924c1b938798797d60c6308fa8ad3b3f0201802f82e4a2c41bb3fafb44cc28", + "sha256:07f59760ef99f31422c49038964b31c4dfcfeb5d2384ebfc71058a7c9adae2d2", + "sha256:0a3a1e9ee9728b2c1734f65d6a1d376c6f2f6fdcc13bb007a08cc4b1ff576dc5", + "sha256:0a90c373ea2975519b58dece25853dbcb9779b05cc46b4819cb1917e3b3215b6", + "sha256:0ad56edabcdb428c2e33bbf24f255fe2b43253b7d13a2cdbf05de955217313e6", + "sha256:0b581f47257a9fce535c4567782a8976002d6b8afa2c39ff616edf87cbeff712", + "sha256:0f8f741b6292c86059ed175d80eefa80997125b7c478fb8769fd9ac8943a16c0", + "sha256:0fc212779bf8411667234b3cdd34d53de6c2b8b8b958e1e12cb473a5f367c338", + "sha256:13c56de6518e14b9bf6edde23c4c39dac5b48dcf04160ea7bce8fca8397cdf86", + "sha256:142c0a5124d9bd0e2976089484af5c74f47bd3298f2ed651ef54ea728d2ea42c", + "sha256:14511a539afee6f9ab492b543060c7491c99924314977a55c98bfa2ee29ce78c", + "sha256:15a842bb369e00295392e7ce192de9dcbf136954614124a667f9f9f17d6a216f", + "sha256:16d4477bcb9fbbd7b5b0e4a5d9b493e42026c0bf1f06f723a9353f5153e75d30", + "sha256:1791ff70bc975b098fe6ecf04356a10e9e2bd7dc21fa7351c1742fdeb9b4966f", + "sha256:19b73643c802f4eaf13d97f7855d0fb527fbc92ab7013c4ad0e13a6ae0ed23bd", + "sha256:200a23239781f46149e6a415f1e870c5ef1e712939fe8fa63035cd053ac2638e", + "sha256:2249280b870e6a42c0d972339e9cc22ee98730a99cd7f2f727549af80dd5a963", + "sha256:2b431c777c9653e569986ecf69ff4a5dba281cded16043d348bf9ba505486f36", + "sha256:2cc3712a4b0b76a1d45a9302dd2f53ff339614b1c29603a911318f2357b04dd2", + "sha256:2fbb0ffc754490aff6dabbf28064be47f0f9ca0b9755976f945214965b3ace7e", + "sha256:32b922e13d4c0080d03e7b62991ad7f5007d9cd74e239c4b16bc85ae8b70252d", + "sha256:36785be22066966a27348444b40389f8444671630063edfb1a2eb04318721e17", + "sha256:37fe0f12aebb6a0e3e17bb4cd356b1286d2d18d2e93b2d39fe647138458b4bcb", + "sha256:3aea7eed3e55119635a74bbeb80b35e776bafccb70d97e8ff838816c124539f1", + "sha256:3c6afcf2338e7f374e8edc765c79fbcb4061d02b15dd5f8f314a4af2bdc7feb5", + "sha256:3ccb8ac2d3c71cda472b75af42818981bdacf48d2e21c36331b50b4f16930163", + "sha256:3d089d0b88996df627693639d123c8158cff41c0651f646cd8fd292c7da90eaf", + "sha256:3dd645e2b0dcb0fd05bf58e2e54c13875847687d0b71941ad2e757e5d89d4356", + "sha256:3e310838a5801795207c66c73ea903deda321e6146d6f282e85fa7e3e4854804", + "sha256:42cbde7789f5c0bcd6816cb29808e36c01b960fb5d29f11e052215aa85497c93", + "sha256:483b29f6f7ffa6af845107d4efe2e3fa8fb2693de8657bc1849f674296ff6a5a", + "sha256:4888e117dd41b9d34194d9e31631af70d3d526efc363085e3089ab1a62c32ed1", + "sha256:49fe9b04b6fa685bd39237d45fad89ba19e9163a1ccaa16611a812e682913496", + "sha256:4a5a844f68776a7715ecb30843b453f07ac89bad393431efbf7accca3ef599c1", + "sha256:4a916087371afd9648e1962e67403c53f9c49ca47b9680adbeef79da3a7811b0", + "sha256:4f676e21db2f8c72ff0936f895271e7a700aa1f8d31b40e4e43442ba94973899", + "sha256:518d2ca43c358929bf08f9079b617f1c2ca6e8848f83c1225c88caeac46e6cbc", + "sha256:5265505b3d61a0f56618c9b941dc54dc334dc6e660f1592d112cd103d914a6db", + "sha256:55cd1fa4ecfa6d9f14fbd97ac24803e6f73e897c738f771a9fe038f2f11ff07c", + "sha256:58b1d5dd591973d426cbb2da5e27ba0339209832b2f3315928c9790e13f159e8", + "sha256:59240685e7da61fb78f65a9f07f8108e36a83317c53f7b276b4175dc44151684", + "sha256:5b48e790e0355865197ad0aca8cde3d8ede347831e1959e158369eb3493d2191", + "sha256:5d4eea0761e37485c9b81400437adb11c40e13ef513375bbd6973e34100aeb06", + "sha256:648386ddd1e19b4a6abab69139b002bc49ebf065b596119f8f37c38e9ecee8ff", + "sha256:653647b8838cf83b2e7e6a0364f49af96deec64d2a6578324db58380cff82aca", + "sha256:6740a3e8d43a32629bb9b009017ea5b9e713b7210ba48ac8d4cb6d99d86c8ee8", + "sha256:6889469bfdc1eddf489729b471303739bf04555bb151fe8875931f8564309afc", + "sha256:68cb0a499f2c4a088fd2f521453e22ed3527154136a855c62e148b7883b99f9a", + "sha256:6aa97af1558a9bef4025f8f5d8c60d712e0a3b13a2fe875511defc6ee77a1ab7", + "sha256:6b73c67850ca7cae0f6c56f71e356d7e9fa25958d3e18a64927c2d930859b8e4", + "sha256:6c8e9340ce5a52f95fa7d3b552b35c7e8f3874d74a03a8a69279fd5fca5dc751", + "sha256:6ca91093a4a8da4afae7fe6a222c3b53ee4eef433ebfee4d54978a103435159e", + "sha256:754bbed1a4ca48479e9d4182a561d001bbf81543876cdded6f695ec3d465846b", + "sha256:762703bdd2b30983c1d9e62b4c88664df4a8a4d5ec0e9253b0231171f18f6d75", + "sha256:78f0b6877bfce7a3d1ff150391354a410c55d3cdce386f862926a4958ad5ab7e", + "sha256:7a07ced2b22f0cf0b55a6a510078174c31b6d8544f3bc00c2bcee52b3d613f74", + "sha256:7dca7081e9a0c3b6490a145593f6fe3173a94197f2cb9891183ef75e9d64c425", + "sha256:7e21b7031e17c6b0e445f42ccc77f79a97e2687023c5746bfb7a9e45e0921b84", + "sha256:7f5179583d7a6cdb981151dd349786cbc318bab54963a192692d945dd3f6435d", + "sha256:83cba698cfb3c2c5a7c3c6bac12fe6c6a51aae69513726be6411076185a8b24a", + "sha256:842c19a6ce894493563c3bd00d81d5100e8e57d70209e84d5491940fdb8b9e3a", + "sha256:84b8382a90539910b53a6307f7c35697bc7e6ffb25d9c1d4e998a13e842a5e83", + "sha256:8ba6f89cac95c0900d932c9efb7f0fb6ca47f6687feec41abcb1bd5e2bd45535", + "sha256:8bbe951244a838a51289ee53a6bae3a07f26d4e179b96fc7ddd3301caf0518eb", + "sha256:925d176a549f4832c6f69fa6026071294ab5910e82a0fe6c6228fce17b0706bd", + "sha256:92b68b79c0da2a980b1c4197e56ac3dd0c8a149b4603747c4378914a68706979", + "sha256:93da1d3db08a827eda74356f9f58884adb254e59b6664f64cc04cdff2cc19b0d", + "sha256:95f3b65d2392e1c5cec27cff08fdc0080270d5a1a4b2ea1d51d5f4a2620ff08d", + "sha256:9c4cb04a16b0f199a8c9bf807269b2f63b7b5b11425e4a6bd44bd6961d28282c", + "sha256:a624cc00ef2158e04188df5e3016385b9353638139a06fb77057b3498f794782", + "sha256:a649dfd735fff086e8a9d0503a9f0c7d01b7912a333c7ae77e1515c08c146dad", + "sha256:a94e52537a0e0a85429eda9e49f272ada715506d3b2431f64b8a3e34eb5f3e75", + "sha256:aa7ac11e294304e615b43f8c441fee5d40094275ed7311f3420d805fde9b07b4", + "sha256:b41b6321805c472f66990c2849e152aff7bc359eb92f781e3f606609eac877ad", + "sha256:b71b8666eeea69d6363248822078c075bac6ed135faa9216aa85f295ff009b1e", + "sha256:b9c2fe36d1f758b28121bef29ed1dee9b7a2453e997528e7d1ac99b94892527c", + "sha256:bb63804105143c7e24cee7db89e37cb3f3941f8e80c4379a0b355c52a52b6780", + "sha256:be5ef2f1fc586a7372bfc355986226484e06d1dc4f9402539872c8bb99e34b01", + "sha256:c142b88039b92e7e0cb2552e8967077e3179b22359e945574f5e2764c3953dcf", + "sha256:c14937af98c4cc362a1d4374806204dd51b1e12dded1ae30645c298e5a5c4cb1", + "sha256:ca449520e7484534a2a44faf629362cae62b660601432d04c482283c47eaebab", + "sha256:cd945871335a639275eee904caef90041568ce3b42f402c6959b460d25ae8732", + "sha256:d0b937b2a1988f184a3e9e577adaa8aede21ec0b38320d6009e02bd026db04fa", + "sha256:d126b52e4a473d40232ec2052a8b232270ed1f8c9571aaf33f73a14cc298c24f", + "sha256:d8761c3c891cc51e90bc9926d6d2f59b27beaf86c74622c8979380a29cc23ac3", + "sha256:d9ecb51120de61e4604650666d1f2b68444d46ae18fd492245a08f53ad2b7711", + "sha256:da584ff96ec95e97925174eb8237e32f626e7a1a97888cdd27ee2f1f24dd0ad8", + "sha256:dbcf360c9e3399b056a238523146ea77eeb2a596ce263b8814c900263e46031a", + "sha256:dbddc10776ca7ebf2a299c41a4dde8ea0d8e3547bfd731cb87af2e8f5bf8962d", + "sha256:dc73505153798c6f74854aba69cc75953888cf9866465196889c7cdd351e720c", + "sha256:e13de156137b7095442b288e72f33503a469aa1980ed856b43c353ac86390519", + "sha256:e1791c4aabd117653530dccd24108fa03cc6baf21f58b950d0a73c3b3b29a350", + "sha256:e75ba609dba23f2c95b776efb9dd3f0b78a76a151e96f96cc5b6b1b0004de66f", + "sha256:e79059d67bea28b53d255c1437b25391653263f0e69cd7dec170d778fdbca95e", + "sha256:ecd27a66740ffd621d20b9a2f2b5ee4129a56e27bfb9458a3bcc2e45794c96cb", + "sha256:f009c69bc8c53db5dfab72ac760895dc1f2bc1b62ab7408b253c8d1ec52459fc", + "sha256:f16bc1334853e91ddaaa1217045dd7be166170beec337576818461268a3de67f", + "sha256:f19169781dddae7478a32301b499b2858bc52fc45a112955e798ee307e294977", + "sha256:fa3060d885657abc549b2a0f8e1b79699290e5d83845141717c6c90c2df38311", + "sha256:fa41a64ac5b08b292906e248549ab48b69c5428f3987b09689ab2441f267d04d", + "sha256:fbf15aff64a163db29a91ed0868af181d6f68ec1a3a7d5afcfe4501252840bad", + "sha256:fe00a9057d100e69b4ae4a094203a708d65b0f345ed546fdef86498bf5390982" ], "markers": "python_version >= '3.8'", - "version": "==0.17.1" + "version": "==0.20.1" }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "markers": "python_version < '3.13'", + "version": "==4.12.2" + }, + "tzdata": { + "hashes": [ + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.2" } }, "develop": { @@ -247,11 +328,19 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" + }, + "backports.tarfile": { + "hashes": [ + "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", + "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991" + ], + "markers": "python_version < '3.12'", + "version": "==1.2.0" }, "black": { "hashes": [ @@ -285,107 +374,122 @@ }, "certifi": { "hashes": [ - "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", - "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2023.11.17" + "version": "==2024.8.30" }, "charset-normalizer": { "hashes": [ - "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", - "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", - "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", - "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", - "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", - "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", - "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", - "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", - "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", - "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", - "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", - "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", - "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", - "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", - "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", - "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", - "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", - "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", - "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", - "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", - "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", - "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", - "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", - "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", - "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", - "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", - "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", - "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", - "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", - "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", - "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", - "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", - "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", - "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", - "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", - "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", - "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", - "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", - "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", - "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", - "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", - "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", - "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", - "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", - "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", - "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", - "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", - "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", - "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", - "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", - "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", - "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", - "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", - "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", - "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", - "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", - "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", - "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", - "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", - "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", - "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", - "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", - "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", - "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", - "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", - "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", - "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", - "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", - "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", - "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", - "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", - "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", - "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", - "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", - "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", - "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", - "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", - "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", - "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", - "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", - "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", - "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", - "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", - "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", - "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", - "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", - "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", - "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", - "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", - "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" + "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621", + "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", + "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", + "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", + "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", + "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", + "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", + "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", + "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", + "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", + "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", + "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", + "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", + "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", + "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", + "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", + "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", + "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", + "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62", + "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", + "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", + "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", + "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", + "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", + "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455", + "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", + "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", + "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", + "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", + "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", + "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", + "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", + "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", + "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", + "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", + "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", + "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", + "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", + "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", + "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee", + "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", + "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", + "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", + "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", + "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", + "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", + "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", + "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", + "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", + "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", + "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", + "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", + "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", + "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", + "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", + "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", + "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", + "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", + "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", + "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", + "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", + "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", + "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149", + "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", + "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574", + "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", + "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", + "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", + "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", + "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", + "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", + "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", + "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", + "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", + "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", + "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51", + "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", + "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", + "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", + "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", + "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", + "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", + "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", + "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", + "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", + "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", + "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6", + "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2", + "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", + "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf", + "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", + "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7", + "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", + "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", + "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", + "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", + "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", + "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4", + "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", + "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", + "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", + "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748", + "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", + "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", + "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.3.2" + "version": "==3.4.0" }, "click": { "hashes": [ @@ -408,85 +512,95 @@ "toml" ], "hashes": [ - "sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca", - "sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471", - "sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a", - "sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058", - "sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85", - "sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143", - "sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446", - "sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590", - "sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a", - "sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105", - "sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9", - "sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a", - "sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac", - "sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25", - "sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2", - "sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450", - "sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932", - "sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba", - "sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137", - "sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae", - "sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614", - "sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70", - "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e", - "sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505", - "sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870", - "sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc", - "sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451", - "sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7", - "sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e", - "sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566", - "sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5", - "sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26", - "sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2", - "sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42", - "sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555", - "sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43", - "sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed", - "sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa", - "sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516", - "sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952", - "sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd", - "sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09", - "sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c", - "sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f", - "sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6", - "sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1", - "sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0", - "sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e", - "sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9", - "sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9", - "sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e", - "sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06" - ], - "markers": "python_version >= '3.8'", - "version": "==7.4.0" + "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376", + "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9", + "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111", + "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172", + "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491", + "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546", + "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2", + "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11", + "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08", + "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c", + "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2", + "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963", + "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613", + "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0", + "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db", + "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf", + "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73", + "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117", + "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1", + "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e", + "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522", + "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25", + "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc", + "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea", + "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52", + "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a", + "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07", + "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06", + "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa", + "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901", + "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b", + "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17", + "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0", + "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21", + "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19", + "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5", + "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51", + "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3", + "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3", + "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f", + "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076", + "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a", + "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718", + "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba", + "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e", + "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27", + "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e", + "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09", + "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e", + "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70", + "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f", + "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72", + "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a", + "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef", + "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b", + "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b", + "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f", + "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806", + "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b", + "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1", + "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c", + "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858" + ], + "markers": "python_version >= '3.9'", + "version": "==7.6.4" }, "docutils": { "hashes": [ - "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", - "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b" + "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", + "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2" ], - "markers": "python_version >= '3.7'", - "version": "==0.20.1" + "markers": "python_version >= '3.9'", + "version": "==0.21.2" }, "exceptiongroup": { "hashes": [ - "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", - "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.0" + "version": "==1.2.2" }, "execnet": { "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" + "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", + "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==2.1.1" }, "flake8": { "hashes": [ @@ -526,19 +640,19 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3.5'", - "version": "==3.6" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "importlib-metadata": { "hashes": [ - "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e", - "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc" + "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", + "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7" ], "markers": "python_version >= '3.8'", - "version": "==7.0.1" + "version": "==8.5.0" }, "iniconfig": { "hashes": [ @@ -550,19 +664,35 @@ }, "jaraco.classes": { "hashes": [ - "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb", - "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621" + "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", + "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" ], "markers": "python_version >= '3.8'", - "version": "==3.3.0" + "version": "==3.4.0" + }, + "jaraco.context": { + "hashes": [ + "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", + "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.1" + }, + "jaraco.functools": { + "hashes": [ + "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", + "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649" + ], + "markers": "python_version >= '3.8'", + "version": "==4.1.0" }, "keyring": { "hashes": [ - "sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836", - "sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25" + "sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6", + "sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741" ], "markers": "python_version >= '3.8'", - "version": "==24.3.0" + "version": "==25.5.0" }, "markdown-it-py": { "hashes": [ @@ -590,45 +720,45 @@ }, "more-itertools": { "hashes": [ - "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684", - "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1" + "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", + "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6" ], "markers": "python_version >= '3.8'", - "version": "==10.2.0" + "version": "==10.5.0" }, "mypy": { "hashes": [ - "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6", - "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d", - "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02", - "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d", - "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3", - "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3", - "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", - "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66", - "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259", - "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", - "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd", - "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", - "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8", - "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", - "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b", - "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e", - "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6", - "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", - "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9", - "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", - "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a", - "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592", - "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218", - "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", - "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4", - "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410", - "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" + "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", + "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095", + "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac", + "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6", + "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", + "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", + "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00", + "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", + "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7", + "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13", + "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be", + "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", + "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850", + "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287", + "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", + "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229", + "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", + "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c", + "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac", + "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", + "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", + "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", + "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9", + "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", + "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf", + "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe", + "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.8.0" + "version": "==1.11.0" }, "mypy-extensions": { "hashes": [ @@ -640,32 +770,32 @@ }, "nh3": { "hashes": [ - "sha256:0d02d0ff79dfd8208ed25a39c12cbda092388fff7f1662466e27d97ad011b770", - "sha256:3277481293b868b2715907310c7be0f1b9d10491d5adf9fce11756a97e97eddf", - "sha256:3b803a5875e7234907f7d64777dfde2b93db992376f3d6d7af7f3bc347deb305", - "sha256:427fecbb1031db085eaac9931362adf4a796428ef0163070c484b5a768e71601", - "sha256:5f0d77272ce6d34db6c87b4f894f037d55183d9518f948bba236fe81e2bb4e28", - "sha256:60684857cfa8fdbb74daa867e5cad3f0c9789415aba660614fe16cd66cbb9ec7", - "sha256:6f42f99f0cf6312e470b6c09e04da31f9abaadcd3eb591d7d1a88ea931dca7f3", - "sha256:86e447a63ca0b16318deb62498db4f76fc60699ce0a1231262880b38b6cff911", - "sha256:8d595df02413aa38586c24811237e95937ef18304e108b7e92c890a06793e3bf", - "sha256:9c0d415f6b7f2338f93035bba5c0d8c1b464e538bfbb1d598acd47d7969284f0", - "sha256:a5167a6403d19c515217b6bcaaa9be420974a6ac30e0da9e84d4fc67a5d474c5", - "sha256:ac19c0d68cd42ecd7ead91a3a032fdfff23d29302dbb1311e641a130dfefba97", - "sha256:b1e97221cedaf15a54f5243f2c5894bb12ca951ae4ddfd02a9d4ea9df9e1a29d", - "sha256:bc2d086fb540d0fa52ce35afaded4ea526b8fc4d3339f783db55c95de40ef02e", - "sha256:d1e30ff2d8d58fb2a14961f7aac1bbb1c51f9bdd7da727be35c63826060b0bf3", - "sha256:f3b53ba93bb7725acab1e030bc2ecd012a817040fd7851b332f86e2f9bb98dc6" - ], - "version": "==0.2.15" + "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164", + "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86", + "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b", + "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad", + "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204", + "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a", + "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200", + "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189", + "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f", + "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811", + "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844", + "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4", + "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be", + "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50", + "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307", + "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe" + ], + "version": "==0.2.18" }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==23.2" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pathspec": { "hashes": [ @@ -677,27 +807,27 @@ }, "pkginfo": { "hashes": [ - "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546", - "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046" + "sha256:9ec518eefccd159de7ed45386a6bb4c6ca5fa2cb3bd9b71154fae44f6f1b36a3", + "sha256:c6bc916b8298d159e31f2c216e35ee5b86da7da18874f879798d0a1983537c86" ], - "markers": "python_version >= '3.6'", - "version": "==1.9.6" + "markers": "python_version >= '3.8'", + "version": "==1.11.2" }, "platformdirs": { "hashes": [ - "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380", - "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420" + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" ], "markers": "python_version >= '3.8'", - "version": "==4.1.0" + "version": "==4.3.6" }, "pluggy": { "hashes": [ - "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", - "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.3.0" + "version": "==1.5.0" }, "pprintpp": { "hashes": [ @@ -732,11 +862,11 @@ }, "pygments": { "hashes": [ - "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", - "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" + "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", + "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" ], - "markers": "python_version >= '3.7'", - "version": "==2.17.2" + "markers": "python_version >= '3.8'", + "version": "==2.18.0" }, "pytest": { "hashes": [ @@ -775,19 +905,19 @@ }, "readme-renderer": { "hashes": [ - "sha256:13d039515c1f24de668e2c93f2e877b9dbe6c6c32328b90a40a49d8b2b85f36d", - "sha256:2d55489f83be4992fe4454939d1a051c33edbab778e82761d060c9fc6b308cd1" + "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", + "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1" ], - "markers": "python_version >= '3.8'", - "version": "==42.0" + "markers": "python_version >= '3.9'", + "version": "==44.0" }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "requests-toolbelt": { "hashes": [ @@ -807,11 +937,11 @@ }, "rich": { "hashes": [ - "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa", - "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235" + "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", + "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" ], - "markers": "python_full_version >= '3.7.0'", - "version": "==13.7.0" + "markers": "python_full_version >= '3.8.0'", + "version": "==13.9.4" }, "snowballstemmer": { "hashes": [ @@ -822,11 +952,11 @@ }, "tomli": { "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38", + "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed" ], "markers": "python_version < '3.11'", - "version": "==2.0.1" + "version": "==2.0.2" }, "twine": { "hashes": [ @@ -848,19 +978,19 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "markers": "python_version < '3.13'", + "version": "==4.12.2" }, "urllib3": { "hashes": [ - "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", - "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "markers": "python_version >= '3.8'", - "version": "==2.1.0" + "version": "==2.2.3" }, "wheel": { "hashes": [ @@ -873,11 +1003,11 @@ }, "zipp": { "hashes": [ - "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31", - "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0" + "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", + "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29" ], "markers": "python_version >= '3.8'", - "version": "==3.17.0" + "version": "==3.20.2" } } } diff --git a/shared-data/python/mypy.ini b/shared-data/python/mypy.ini index 17d9374de2a..a12fe382e75 100644 --- a/shared-data/python/mypy.ini +++ b/shared-data/python/mypy.ini @@ -16,26 +16,7 @@ warn_untyped_fields = True warn_return_any = False [mypy-opentrons_shared_data.pipette.*] -no_implicit_optional = False warn_return_any = False [mypy-opentrons_shared_data.protocol.*] warn_return_any = False - -[mypy-tests.deck.*] -disallow_untyped_defs = False - -[mypy-tests.labware.*] -disallow_untyped_defs = False -disallow_untyped_calls = False - -[mypy-tests.module.*] -disallow_untyped_defs = False -disallow_untyped_calls = False - -[mypy-tests.pipette.*] -disallow_untyped_defs = False -disallow_untyped_calls = False - -[mypy-tests.protocol.*] -disallow_untyped_defs = False diff --git a/shared-data/python/opentrons_shared_data/gripper/gripper_definition.py b/shared-data/python/opentrons_shared_data/gripper/gripper_definition.py index 707d960a9ba..99e362c25d0 100644 --- a/shared-data/python/opentrons_shared_data/gripper/gripper_definition.py +++ b/shared-data/python/opentrons_shared_data/gripper/gripper_definition.py @@ -1,8 +1,8 @@ """Gripper configurations.""" -from typing_extensions import Literal -from typing import TYPE_CHECKING, List, Dict, Tuple, Any, NewType -from pydantic import BaseModel, Field, conint, confloat +from typing_extensions import Annotated, Literal +from typing import List, Dict, Tuple, Any, NewType +from pydantic import ConfigDict, BaseModel, Field from enum import Enum @@ -42,22 +42,20 @@ def __str__(self) -> str: GripperSchema = Dict[str, Any] -if TYPE_CHECKING: - _StrictNonNegativeInt = int - _StrictNonNegativeFloat = float -else: - _StrictNonNegativeInt = conint(strict=True, ge=0) - _StrictNonNegativeFloat = confloat(strict=True, ge=0.0) +_StrictNonNegativeInt = Annotated[int, Field(strict=True, ge=0)] +_StrictNonNegativeFloat = Annotated[float, Field(strict=True, ge=0.0)] + + +PolynomialTerm = Tuple[_StrictNonNegativeInt, float] +_Polynomial = Annotated[List[PolynomialTerm], Field(min_length=1)] class GripperBaseModel(BaseModel): """Gripper base model.""" - class Config: - """Config.""" - - alias_generator = _snake_to_camel_case - allow_population_by_field_name = True + model_config = ConfigDict( + alias_generator=_snake_to_camel_case, populate_by_name=True + ) Offset = Tuple[float, float, float] @@ -74,16 +72,12 @@ class Geometry(GripperBaseModel): max_allowed_grip_error: _StrictNonNegativeFloat -PolynomialTerm = Tuple[_StrictNonNegativeInt, float] - - class GripForceProfile(GripperBaseModel): """Gripper force profile.""" - polynomial: List[PolynomialTerm] = Field( + polynomial: _Polynomial = Field( ..., description="Polynomial function to convert a grip force in Newton to the jaw motor duty cycle value, which will be read by the gripper firmware.", - min_items=1, ) default_grip_force: _StrictNonNegativeFloat default_idle_force: _StrictNonNegativeFloat diff --git a/shared-data/python/opentrons_shared_data/labware/labware_definition.py b/shared-data/python/opentrons_shared_data/labware/labware_definition.py index 3363c874c55..994d4e743eb 100644 --- a/shared-data/python/opentrons_shared_data/labware/labware_definition.py +++ b/shared-data/python/opentrons_shared_data/labware/labware_definition.py @@ -6,21 +6,19 @@ from __future__ import annotations from enum import Enum -from typing import TYPE_CHECKING, Dict, List, Optional, Union +from typing import Dict, List, Optional, Union from math import sqrt, asin from numpy import pi, trapz from functools import cached_property from pydantic import ( + ConfigDict, BaseModel, - Extra, Field, - conint, - confloat, StrictInt, StrictFloat, ) -from typing_extensions import Literal +from typing_extensions import Annotated, Literal from .constants import ( Conical, @@ -36,12 +34,8 @@ SAFE_STRING_REGEX = "^[a-z0-9._]+$" -if TYPE_CHECKING: - _StrictNonNegativeInt = int - _StrictNonNegativeFloat = float -else: - _StrictNonNegativeInt = conint(strict=True, ge=0) - _StrictNonNegativeFloat = confloat(strict=True, ge=0.0) +_StrictNonNegativeInt = Annotated[int, Field(strict=True, ge=0)] +_StrictNonNegativeFloat = Annotated[float, Field(strict=True, ge=0.0)] _Number = Union[StrictInt, StrictFloat] @@ -176,7 +170,7 @@ class Parameters(BaseModel): loadName: str = Field( ..., description="Name used to reference a labware definition", - regex=SAFE_STRING_REGEX, + pattern=SAFE_STRING_REGEX, ) isMagneticModuleCompatible: bool = Field( ..., @@ -199,8 +193,7 @@ class Dimensions(BaseModel): class WellDefinition(BaseModel): - class Config: - extra = Extra.allow + model_config = ConfigDict(extra="allow") depth: _NonNegativeNumber = Field(...) x: _NonNegativeNumber = Field( @@ -269,8 +262,7 @@ class SphericalSegment(BaseModel): def count(self) -> int: return self.xCount * self.yCount - class Config: - keep_untouched = (cached_property,) + model_config = ConfigDict(ignored_types=(cached_property,)) class ConicalFrustum(BaseModel): @@ -304,8 +296,7 @@ class ConicalFrustum(BaseModel): def count(self) -> int: return self.xCount * self.yCount - class Config: - keep_untouched = (cached_property,) + model_config = ConfigDict(ignored_types=(cached_property,)) class CuboidalFrustum(BaseModel): @@ -348,8 +339,7 @@ class CuboidalFrustum(BaseModel): def count(self) -> int: return self.xCount * self.yCount - class Config: - keep_untouched = (cached_property,) + model_config = ConfigDict(ignored_types=(cached_property,)) # A squared cone is the intersection of a cube and a cone that both @@ -490,8 +480,7 @@ def volume_to_height_table(self) -> Dict[float, float]: def count(self) -> int: return self.xCount * self.yCount - class Config: - keep_untouched = (cached_property,) + model_config = ConfigDict(ignored_types=(cached_property,)) """ @@ -616,8 +605,7 @@ class RoundedCuboidSegment(BaseModel): def count(self) -> int: return self.xCount * self.yCount - class Config: - keep_untouched = (cached_property,) + model_config = ConfigDict(ignored_types=(cached_property,)) class Metadata1(BaseModel): @@ -672,9 +660,9 @@ class LabwareDefinition(BaseModel): ..., description="Version of the labware definition itself " "(eg myPlate v1/v2/v3). An incrementing integer", - ge=1.0, + ge=1, ) - namespace: str = Field(..., regex=SAFE_STRING_REGEX) + namespace: str = Field(..., pattern=SAFE_STRING_REGEX) metadata: Metadata = Field( ..., description="Properties used for search and display" ) @@ -731,11 +719,11 @@ class LabwareDefinition(BaseModel): "during labware movement.", ) gripHeightFromLabwareBottom: Optional[float] = Field( - default_factory=None, + default=None, description="The Z-height, from labware bottom, where the gripper should grip the labware.", ) gripForce: Optional[float] = Field( - default_factory=None, + default=None, description="Force, in Newtons, with which the gripper should grip the labware.", ) innerLabwareGeometry: Optional[Dict[str, InnerWellGeometry]] = Field( diff --git a/shared-data/python/opentrons_shared_data/liquid_classes/liquid_class_definition.py b/shared-data/python/opentrons_shared_data/liquid_classes/liquid_class_definition.py index 2c2de84e07e..aca371d43e6 100644 --- a/shared-data/python/opentrons_shared_data/liquid_classes/liquid_class_definition.py +++ b/shared-data/python/opentrons_shared_data/liquid_classes/liquid_class_definition.py @@ -1,25 +1,22 @@ """Python shared data models for liquid class definitions.""" from enum import Enum -from typing import TYPE_CHECKING, Literal, Union, Optional, Dict, Any, Sequence, Tuple +from typing import Literal, Union, Optional, Sequence, Tuple, Any from pydantic import ( BaseModel, - validator, + field_validator, + ValidationInfo, Field, - conint, - confloat, StrictInt, StrictFloat, ) +from pydantic.json_schema import SkipJsonSchema +from typing_extensions import Annotated -if TYPE_CHECKING: - _StrictNonNegativeInt = int - _StrictNonNegativeFloat = float -else: - _StrictNonNegativeInt = conint(strict=True, ge=0) - _StrictNonNegativeFloat = confloat(strict=True, ge=0.0) +_StrictNonNegativeInt = Annotated[int, Field(strict=True, ge=0)] +_StrictNonNegativeFloat = Annotated[float, Field(strict=True, ge=0.0)] _Number = Union[StrictInt, StrictFloat] @@ -35,6 +32,10 @@ """Settings for correctionByVolume, which unlike other `byVolume` properties allows negative values with volume.""" +def _remove_default(s: dict[str, Any]) -> None: + s.pop("default") + + class PositionReference(Enum): """Positional reference for liquid handling operations.""" @@ -72,15 +73,18 @@ class DelayProperties(BaseModel): """Shared properties for delay..""" enable: bool = Field(..., description="Whether delay is enabled.") - params: Optional[DelayParams] = Field( - None, description="Parameters for the delay function." + params: DelayParams | SkipJsonSchema[None] = Field( + None, + description="Parameters for the delay function.", + json_schema_extra=_remove_default, ) - @validator("params") + @field_validator("params") + @classmethod def _validate_params( - cls, v: Optional[DelayParams], values: Dict[str, Any] + cls, v: Optional[DelayParams], info: ValidationInfo ) -> Optional[DelayParams]: - if v is None and values["enable"]: + if v is None and info.data.get("enable", False): raise ValueError("If enable is true parameters for delay must be defined.") return v @@ -108,15 +112,18 @@ class TouchTipProperties(BaseModel): """Shared properties for the touch-tip function.""" enable: bool = Field(..., description="Whether touch-tip is enabled.") - params: Optional[LiquidClassTouchTipParams] = Field( - None, description="Parameters for the touch-tip function." + params: LiquidClassTouchTipParams | SkipJsonSchema[None] = Field( + None, + description="Parameters for the touch-tip function.", + json_schema_extra=_remove_default, ) - @validator("params") + @field_validator("params") + @classmethod def _validate_params( - cls, v: Optional[LiquidClassTouchTipParams], values: Dict[str, Any] + cls, v: Optional[LiquidClassTouchTipParams], info: ValidationInfo ) -> Optional[LiquidClassTouchTipParams]: - if v is None and values["enable"]: + if v is None and info.data.get("enable", False): raise ValueError( "If enable is true parameters for touch tip must be defined." ) @@ -136,15 +143,18 @@ class MixProperties(BaseModel): """Mixing properties.""" enable: bool = Field(..., description="Whether mix is enabled.") - params: Optional[MixParams] = Field( - None, description="Parameters for the mix function." + params: MixParams | SkipJsonSchema[None] = Field( + None, + description="Parameters for the mix function.", + json_schema_extra=_remove_default, ) - @validator("params") + @field_validator("params") + @classmethod def _validate_params( - cls, v: Optional[MixParams], values: Dict[str, Any] + cls, v: Optional[MixParams], info: ValidationInfo ) -> Optional[MixParams]: - if v is None and values["enable"]: + if v is None and info.data.get("enable", False): raise ValueError("If enable is true parameters for mix must be defined.") return v @@ -164,15 +174,18 @@ class BlowoutProperties(BaseModel): """Blowout properties.""" enable: bool = Field(..., description="Whether blow-out is enabled.") - params: Optional[BlowoutParams] = Field( - None, description="Parameters for the blowout function." + params: BlowoutParams | SkipJsonSchema[None] = Field( + None, + description="Parameters for the blowout function.", + json_schema_extra=_remove_default, ) - @validator("params") + @field_validator("params") + @classmethod def _validate_params( - cls, v: Optional[BlowoutParams], values: Dict[str, Any] + cls, v: Optional[BlowoutParams], info: ValidationInfo ) -> Optional[BlowoutParams]: - if v is None and values["enable"]: + if v is None and info.data.get("enable", False): raise ValueError( "If enable is true parameters for blowout must be defined." ) @@ -344,8 +357,10 @@ class ByTipTypeSetting(BaseModel): singleDispense: SingleDispenseProperties = Field( ..., description="Single dispense parameters for this tip type." ) - multiDispense: Optional[MultiDispenseProperties] = Field( - None, description="Optional multi-dispense parameters for this tip type." + multiDispense: MultiDispenseProperties | SkipJsonSchema[None] = Field( + None, + description="Optional multi-dispense parameters for this tip type.", + json_schema_extra=_remove_default, ) diff --git a/shared-data/python/opentrons_shared_data/pipette/__init__.py b/shared-data/python/opentrons_shared_data/pipette/__init__.py index 1f3fce2b6d5..91473529a90 100644 --- a/shared-data/python/opentrons_shared_data/pipette/__init__.py +++ b/shared-data/python/opentrons_shared_data/pipette/__init__.py @@ -4,7 +4,7 @@ opentrons_shared_data.pipette: functions and types for pipette config """ import copy -from typing import TYPE_CHECKING, Dict +from typing import TYPE_CHECKING, Dict, Optional import json from functools import lru_cache @@ -63,7 +63,7 @@ def name_for_model(pipette_model: PipetteModel) -> PipetteName: def fuse_specs( - pipette_model: PipetteModel, pipette_name: PipetteName = None + pipette_model: PipetteModel, pipette_name: Optional[PipetteName] = None ) -> PipetteFusedSpec: """Combine the model and name spec for a given model. @@ -75,7 +75,7 @@ def fuse_specs( @lru_cache(maxsize=None) def _fuse_specs_cached( - pipette_model: PipetteModel, pipette_name: PipetteName = None + pipette_model: PipetteModel, pipette_name: Optional[PipetteName] = None ) -> PipetteFusedSpec: """ Do the work of fusing the specs inside an lru cache. This can't be the diff --git a/shared-data/python/opentrons_shared_data/pipette/pipette_definition.py b/shared-data/python/opentrons_shared_data/pipette/pipette_definition.py index 84566c4ea92..2e10ede5093 100644 --- a/shared-data/python/opentrons_shared_data/pipette/pipette_definition.py +++ b/shared-data/python/opentrons_shared_data/pipette/pipette_definition.py @@ -1,7 +1,12 @@ import re -from typing import List, Dict, Tuple, Optional -from pydantic import BaseModel, Field, validator -from typing_extensions import Literal +from typing import List, Dict, Tuple, Optional, Annotated, Literal, TypeVar +from pydantic import ( + field_validator, + BaseModel, + Field, + BeforeValidator, + PlainSerializer, +) from dataclasses import dataclass from . import types as pip_types, types @@ -16,6 +21,17 @@ NOZZLE_MAP_NAMES = re.compile(r"(?P[A-Z]+)(?P[0-9]+)") COLUMN_NAMES = re.compile(r"[0-9]+") ROW_NAMES = re.compile(r"[A-Z]+") +OT_TIPRACK_NAMES = re.compile(r"opentrons/[a-z0-9._]+/[0-9]") + + +def validate_opentrons_tiprack(v: str) -> str: + if not OT_TIPRACK_NAMES.match(v): + raise ValueError("{v} is not a valid tiprack name.") + return v + + +EnumType = TypeVar("EnumType") +EnumSerializer = Annotated[EnumType, PlainSerializer(lambda v: v.value)] # TODO (lc 12-5-2022) Ideally we can deprecate this @@ -257,10 +273,12 @@ class CamActionDropTipConfiguration(BaseModel): class DropTipConfigurations(BaseModel): plunger_eject: Optional[PlungerEjectDropTipConfiguration] = Field( - description="Configuration for tip drop via plunger eject", alias="plungerEject" + None, + description="Configuration for tip drop via plunger eject", + alias="plungerEject", ) cam_action: Optional[CamActionDropTipConfiguration] = Field( - description="Configuration for tip drop via cam action", alias="camAction" + None, description="Configuration for tip drop via cam action", alias="camAction" ) @@ -307,12 +325,12 @@ class PipettePhysicalPropertiesDefinition(BaseModel): description="A list of pipette names that are compatible with this pipette.", alias="backCompatNames", ) - pipette_type: pip_types.PipetteModelType = Field( + pipette_type: EnumSerializer[pip_types.PipetteModelType] = Field( ..., description="The pipette model type (related to number of channels).", alias="model", ) - display_category: pip_types.PipetteGenerationType = Field( + display_category: EnumSerializer[pip_types.PipetteGenerationType] = Field( ..., description="The product model of the pipette.", alias="displayCategory" ) pick_up_tip_configurations: PickUpTipConfigurations = Field( @@ -334,7 +352,7 @@ class PipettePhysicalPropertiesDefinition(BaseModel): partial_tip_configurations: PartialTipDefinition = Field( ..., alias="partialTipConfigurations" ) - channels: pip_types.PipetteChannelType = Field( + channels: EnumSerializer[pip_types.PipetteChannelType] = Field( ..., description="The maximum number of channels on the pipette." ) shaft_diameter: float = Field( @@ -350,7 +368,7 @@ class PipettePhysicalPropertiesDefinition(BaseModel): description="The distance of backlash on the plunger motor.", alias="backlashDistance", ) - quirks: List[pip_types.Quirks] = Field( + quirks: List[EnumSerializer[pip_types.Quirks]] = Field( ..., description="The list of quirks available for the loaded configuration" ) tip_presence_check_distance_mm: float = Field( @@ -364,44 +382,42 @@ class PipettePhysicalPropertiesDefinition(BaseModel): alias="endTipActionRetractDistanceMM", ) - @validator("pipette_type", pre=True) + @field_validator("pipette_type", mode="before") + @classmethod def convert_pipette_model_string(cls, v: str) -> pip_types.PipetteModelType: return pip_types.PipetteModelType(v) - @validator("channels", pre=True) + @field_validator("channels", mode="before") + @classmethod def convert_channels(cls, v: int) -> pip_types.PipetteChannelType: return pip_types.PipetteChannelType(v) - @validator("display_category", pre=True) + @field_validator("display_category", mode="before") + @classmethod def convert_display_category(cls, v: str) -> pip_types.PipetteGenerationType: if not v: return pip_types.PipetteGenerationType.GEN1 return pip_types.PipetteGenerationType(v) - @validator("quirks", pre=True) + @field_validator("quirks", mode="before") + @classmethod def convert_quirks(cls, v: List[str]) -> List[pip_types.Quirks]: return [pip_types.Quirks(q) for q in v] - @validator("plunger_positions_configurations", pre=True) + @field_validator("plunger_positions_configurations", mode="before") + @classmethod def convert_plunger_positions( cls, v: Dict[str, PlungerPositions] ) -> Dict[pip_types.LiquidClasses, PlungerPositions]: return {pip_types.LiquidClasses[key]: value for key, value in v.items()} - class Config: - json_encoders = { - pip_types.PipetteChannelType: lambda v: v.value, - pip_types.PipetteModelType: lambda v: v.value, - pip_types.PipetteGenerationType: lambda v: v.value, - pip_types.Quirks: lambda v: v.value, - } - class PipetteRowDefinition(BaseModel): key: str ordered_nozzles: List[str] = Field(..., alias="orderedNozzles") - @validator("key") + @field_validator("key") + @classmethod def check_key_is_row(cls, v: str) -> str: if not ROW_NAMES.search(v): raise ValueError(f"{v} is not a valid row name") @@ -412,7 +428,8 @@ class PipetteColumnDefinition(BaseModel): key: str ordered_nozzles: List[str] = Field(..., alias="orderedNozzles") - @validator("key") + @field_validator("key") + @classmethod def check_key_is_column(cls, v: str) -> str: if not COLUMN_NAMES.search(v): raise ValueError(f"{v} is not a valid column name") @@ -441,7 +458,8 @@ class PipetteGeometryDefinition(BaseModel): ordered_rows: List[PipetteRowDefinition] = Field(..., alias="orderedRows") lld_settings: Dict[str, Dict[str, float]] = Field(..., alias="lldSettings") - @validator("nozzle_map", pre=True) + @field_validator("nozzle_map", mode="before") + @classmethod def check_nonempty_strings( cls, v: Dict[str, List[float]] ) -> Dict[str, List[float]]: @@ -469,14 +487,16 @@ class PipetteLiquidPropertiesDefinition(BaseModel): description="The minimum supported volume of the pipette.", alias="minVolume", ) - default_tipracks: List[str] = Field( + default_tipracks: List[ + Annotated[str, BeforeValidator(validate_opentrons_tiprack)] + ] = Field( ..., description="A list of default tiprack paths.", - regex="opentrons/[a-z0-9._]+/[0-9]", alias="defaultTipracks", ) - @validator("supported_tips", pre=True) + @field_validator("supported_tips", mode="before") + @classmethod def convert_aspirate_key_to_channel_type( cls, v: Dict[str, SupportedTipsDefinition] ) -> Dict[pip_types.PipetteTipType, SupportedTipsDefinition]: @@ -501,7 +521,8 @@ class PipetteConfigurations( ..., description="A dictionary of liquid properties keyed by liquid classes." ) - @validator("liquid_properties", pre=True) + @field_validator("liquid_properties", mode="before") + @classmethod def convert_liquid_properties_key( cls, v: Dict[str, PipetteLiquidPropertiesDefinition] ) -> Dict[pip_types.LiquidClasses, PipetteLiquidPropertiesDefinition]: diff --git a/shared-data/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py b/shared-data/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py index d72a09e666b..740504501b0 100644 --- a/shared-data/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py +++ b/shared-data/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py @@ -68,9 +68,9 @@ def _change_to_camel_case(c: str) -> str: def list_configuration_keys() -> Tuple[List[str], Dict[int, str]]: """List out the model keys available to modify at the top level.""" - lookup = {i: v for (i, v) in enumerate(PipetteConfigurations.__fields__)} + lookup = {i: v for (i, v) in enumerate(PipetteConfigurations.model_fields)} return [ - f"{i}: {v}" for (i, v) in enumerate(PipetteConfigurations.__fields__) + f"{i}: {v}" for (i, v) in enumerate(PipetteConfigurations.model_fields) ], lookup @@ -84,7 +84,7 @@ def handle_subclass_model( ) -> List[str]: """Handle sub-classed basemodels and update the top level model as necessary.""" if is_basemodel: - if base_model.__fields__ == SupportedTipsDefinition.__fields__: + if base_model.model_fields == SupportedTipsDefinition.model_fields: # pydantic does something weird with the types in ModelFields so # we cannot use isinstance checks to confirm if the base model # is a supported tips definition @@ -96,8 +96,8 @@ def handle_subclass_model( ] top_level_configuration.append(tip_type.name) - lookup = {i: v for (i, v) in enumerate(base_model.__fields__)} - config_list = [f"{i}: {v}" for (i, v) in enumerate(base_model.__fields__)] + lookup = {i: v for (i, v) in enumerate(base_model.model_fields)} + config_list = [f"{i}: {v}" for (i, v) in enumerate(base_model.model_fields)] print(f"you selected the basemodel {base_model.__name__}:") # type: ignore[attr-defined] for row in config_list: print(f"\t{row}") @@ -105,7 +105,9 @@ def handle_subclass_model( configuration_to_update = lookup[ int(input("select a specific configuration from above\n")) ] - field_type = base_model.__fields__[configuration_to_update].type_ + field_type = base_model.model_fields[ + configuration_to_update + ].rebuild_annotation() is_basemodel = isinstance(field_type, ModelMetaclass) top_level_configuration.append(configuration_to_update) @@ -196,7 +198,7 @@ def load_and_update_file_from_config( """ camel_list_to_update = iter([_change_to_camel_case(i) for i in config_to_update]) - if config_to_update[0] in PipetteGeometryDefinition.__fields__: + if config_to_update[0] in PipetteGeometryDefinition.model_fields: geometry = _geometry( model_to_update.pipette_channels, model_to_update.pipette_type, @@ -229,7 +231,7 @@ def load_and_update_file_from_config( f"{model_to_update.pipette_version.major}_{model_to_update.pipette_version.minor}", geometry, ) - elif config_to_update[0] in PipettePhysicalPropertiesDefinition.__fields__: + elif config_to_update[0] in PipettePhysicalPropertiesDefinition.model_fields: physical = _physical( model_to_update.pipette_channels, model_to_update.pipette_type, @@ -401,9 +403,9 @@ def determine_models_to_update(update_all_models: bool) -> None: f"NOTE: updating the {configuration_to_update[0]} will automatically update the {NOZZLE_LOCATION_CONFIGS[1]}\n" ) - field_type = PipetteConfigurations.__fields__[ + field_type = PipetteConfigurations.model_fields[ configuration_to_update[0] - ].type_ + ].rebuild_annotation() is_basemodel = isinstance(field_type, ModelMetaclass) configuration_to_update = handle_subclass_model( diff --git a/shared-data/python/opentrons_shared_data/protocol/models/__init__.py b/shared-data/python/opentrons_shared_data/protocol/models/__init__.py index 76f8449d93d..ac9a0df7cba 100644 --- a/shared-data/python/opentrons_shared_data/protocol/models/__init__.py +++ b/shared-data/python/opentrons_shared_data/protocol/models/__init__.py @@ -2,7 +2,7 @@ from . import protocol_schema_v6, protocol_schema_v7, protocol_schema_v8 from .protocol_schema_v6 import ProtocolSchemaV6 from .protocol_schema_v7 import ProtocolSchemaV7 -from .protocol_schema_v8 import ProtocolSchemaV8 +from .protocol_schema_v8 import ProtocolSchemaV8, CommandSchemaId from .shared_models import ( Liquid, Labware, @@ -45,4 +45,5 @@ "Pipette", "Robot", "DesignerApplication", + "CommandSchemaId", ] diff --git a/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v6.py b/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v6.py index 24aeb1826bd..f8278d019f8 100644 --- a/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v6.py +++ b/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v6.py @@ -1,4 +1,9 @@ -from pydantic import BaseModel, Field, validator +from pydantic import ( + ConfigDict, + BaseModel, + Field, + model_validator, +) from typing import Any, List, Optional, Dict, Union from typing_extensions import Literal from opentrons_shared_data.labware.labware_definition import LabwareDefinition @@ -21,44 +26,44 @@ # TODO (tamar 3/15/22): split apart all the command payloads when we tackle #9583 class Params(BaseModel): - slotName: Optional[str] - axes: Optional[List[str]] - pipetteId: Optional[str] - mount: Optional[str] - moduleId: Optional[str] - location: Optional[Union[Location, Literal["offDeck"]]] - labwareId: Optional[str] - displayName: Optional[str] - liquidId: Optional[str] - volumeByWell: Optional[Dict[str, Any]] - wellName: Optional[str] - volume: Optional[float] - flowRate: Optional[float] - wellLocation: Optional[Union[WellLocation]] - waitForResume: Optional[Literal[True]] - seconds: Optional[float] - minimumZHeight: Optional[float] - forceDirect: Optional[bool] - speed: Optional[float] - message: Optional[str] - coordinates: Optional[OffsetVector] - axis: Optional[str] - distance: Optional[float] - positionId: Optional[str] - temperature: Optional[float] - celsius: Optional[float] - blockMaxVolumeUl: Optional[float] - rpm: Optional[float] - height: Optional[float] - offset: Optional[OffsetVector] - profile: Optional[List[ProfileStep]] - radius: Optional[float] + slotName: Optional[str] = None + axes: Optional[List[str]] = None + pipetteId: Optional[str] = None + mount: Optional[str] = None + moduleId: Optional[str] = None + location: Optional[Union[Location, Literal["offDeck"]]] = None + labwareId: Optional[str] = None + displayName: Optional[str] = None + liquidId: Optional[str] = None + volumeByWell: Optional[Dict[str, Any]] = None + wellName: Optional[str] = None + volume: Optional[float] = None + flowRate: Optional[float] = None + wellLocation: Optional[Union[WellLocation]] = None + waitForResume: Optional[Literal[True]] = None + seconds: Optional[float] = None + minimumZHeight: Optional[float] = None + forceDirect: Optional[bool] = None + speed: Optional[float] = None + message: Optional[str] = None + coordinates: Optional[OffsetVector] = None + axis: Optional[str] = None + distance: Optional[float] = None + positionId: Optional[str] = None + temperature: Optional[float] = None + celsius: Optional[float] = None + blockMaxVolumeUl: Optional[float] = None + rpm: Optional[float] = None + height: Optional[float] = None + offset: Optional[OffsetVector] = None + profile: Optional[List[ProfileStep]] = None + radius: Optional[float] = None class Command(BaseModel): commandType: str params: Params - key: Optional[str] + key: Optional[str] = None class ProtocolSchemaV6(BaseModel): @@ -73,38 +78,23 @@ class ProtocolSchemaV6(BaseModel): robot: Robot pipettes: Dict[str, Pipette] labware: Dict[str, Labware] - modules: Optional[Dict[str, Module]] - liquids: Optional[Dict[str, Liquid]] + modules: Optional[Dict[str, Module]] = None + liquids: Optional[Dict[str, Liquid]] = None labwareDefinitions: Dict[str, LabwareDefinition] # commands must be after pipettes, labware, etc. for its @validator to work. commands: List[Command] - commandAnnotations: Optional[List[CommandAnnotation]] - designerApplication: Optional[DesignerApplication] - - class Config: - # added for constructing the class with field name instead of alias - allow_population_by_field_name = True + commandAnnotations: Optional[List[CommandAnnotation]] = None + designerApplication: Optional[DesignerApplication] = None + model_config = ConfigDict(populate_by_name=True) - @validator("commands") - def _validate_commands( - cls, - value: List[Command], - values: Dict[str, Any], - ) -> List[Command]: - pipette_ids = set(values["pipettes"].keys()) if "pipettes" in values else set() - labware_ids = set(values["labware"].keys()) if "labware" in values else set() - module_ids = ( - set(values["modules"].keys()) - if "modules" in values and values["modules"] - else set() - ) - liquid_ids = ( - set(values["liquids"].keys()) - if "liquids" in values and values["liquids"] - else set() - ) + @model_validator(mode="after") + def _validate_commands(self) -> "ProtocolSchemaV6": + pipette_ids = set(self.pipettes.keys() if self.pipettes else []) + labware_ids = set(self.labware.keys() if self.labware else []) + module_ids = set(self.modules.keys() if self.modules else []) + liquid_ids = set(self.liquids.keys() if self.liquids else []) - for index, command in enumerate(value): + for index, command in enumerate(self.commands): if ( command.params.pipetteId is not None and command.params.pipetteId not in pipette_ids @@ -142,4 +132,4 @@ def _validate_commands( f" which doesn't exist." ) - return value + return self diff --git a/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v7.py b/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v7.py index 46eb242b990..97986ed385a 100644 --- a/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v7.py +++ b/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v7.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field +from pydantic import ConfigDict, BaseModel, Field from typing import Any, List, Optional, Dict, Union from typing_extensions import Literal @@ -19,59 +19,59 @@ # TODO (tamar 3/15/22): split apart all the command payloads when we tackle #9583 class Params(BaseModel): - slotName: Optional[str] - axes: Optional[List[str]] - pipetteId: Optional[str] - mount: Optional[str] - moduleId: Optional[str] - location: Optional[Union[Location, Literal["offDeck"]]] - labwareId: Optional[str] - displayName: Optional[str] - liquidId: Optional[str] - volumeByWell: Optional[Dict[str, Any]] - wellName: Optional[str] - volume: Optional[float] - flowRate: Optional[float] - wellLocation: Optional[WellLocation] - waitForResume: Optional[Literal[True]] - seconds: Optional[float] - minimumZHeight: Optional[float] - forceDirect: Optional[bool] - speed: Optional[float] - message: Optional[str] - coordinates: Optional[OffsetVector] - axis: Optional[str] - distance: Optional[float] - positionId: Optional[str] - temperature: Optional[float] - celsius: Optional[float] - blockMaxVolumeUl: Optional[float] - rpm: Optional[float] - height: Optional[float] - offset: Optional[OffsetVector] - profile: Optional[List[ProfileStep]] - radius: Optional[float] + slotName: Optional[str] = None + axes: Optional[List[str]] = None + pipetteId: Optional[str] = None + mount: Optional[str] = None + moduleId: Optional[str] = None + location: Optional[Union[Location, Literal["offDeck"]]] = None + labwareId: Optional[str] = None + displayName: Optional[str] = None + liquidId: Optional[str] = None + volumeByWell: Optional[Dict[str, Any]] = None + wellName: Optional[str] = None + volume: Optional[float] = None + flowRate: Optional[float] = None + wellLocation: Optional[WellLocation] = None + waitForResume: Optional[Literal[True]] = None + seconds: Optional[float] = None + minimumZHeight: Optional[float] = None + forceDirect: Optional[bool] = None + speed: Optional[float] = None + message: Optional[str] = None + coordinates: Optional[OffsetVector] = None + axis: Optional[str] = None + distance: Optional[float] = None + positionId: Optional[str] = None + temperature: Optional[float] = None + celsius: Optional[float] = None + blockMaxVolumeUl: Optional[float] = None + rpm: Optional[float] = None + height: Optional[float] = None + offset: Optional[OffsetVector] = None + profile: Optional[List[ProfileStep]] = None + radius: Optional[float] = None # schema v7 add-ons - newLocation: Optional[Union[Location, Literal["offDeck"]]] - strategy: Optional[str] - pickUpOffset: Optional[OffsetVector] - dropOffset: Optional[OffsetVector] - homeAfter: Optional[bool] - alternateDropLocation: Optional[bool] - holdTimeSeconds: Optional[float] - maintenancePosition: Optional[str] - pipetteName: Optional[str] - model: Optional[str] - loadName: Optional[str] - namespace: Optional[str] - version: Optional[int] - pushOut: Optional[float] + newLocation: Optional[Union[Location, Literal["offDeck"]]] = None + strategy: Optional[str] = None + pickUpOffset: Optional[OffsetVector] = None + dropOffset: Optional[OffsetVector] = None + homeAfter: Optional[bool] = None + alternateDropLocation: Optional[bool] = None + holdTimeSeconds: Optional[float] = None + maintenancePosition: Optional[str] = None + pipetteName: Optional[str] = None + model: Optional[str] = None + loadName: Optional[str] = None + namespace: Optional[str] = None + version: Optional[int] = None + pushOut: Optional[float] = None class Command(BaseModel): commandType: str params: Params - key: Optional[str] + key: Optional[str] = None class ProtocolSchemaV7(BaseModel): @@ -84,12 +84,9 @@ class ProtocolSchemaV7(BaseModel): schemaVersion: Literal[7] metadata: Metadata robot: Robot - liquids: Optional[Dict[str, Liquid]] + liquids: Optional[Dict[str, Liquid]] = None labwareDefinitions: Dict[str, LabwareDefinition] commands: List[Command] - commandAnnotations: Optional[List[CommandAnnotation]] - designerApplication: Optional[DesignerApplication] - - class Config: - # added for constructing the class with field name instead of alias - allow_population_by_field_name = True + commandAnnotations: Optional[List[CommandAnnotation]] = None + designerApplication: Optional[DesignerApplication] = None + model_config = ConfigDict(populate_by_name=True) diff --git a/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v8.py b/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v8.py index 11beddb96c0..08b6457c206 100644 --- a/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v8.py +++ b/shared-data/python/opentrons_shared_data/protocol/models/protocol_schema_v8.py @@ -2,7 +2,7 @@ from typing import Any, List, Optional, Dict from typing_extensions import Literal -from pydantic import BaseModel, Field, Extra +from pydantic import BaseModel, Field, ConfigDict from opentrons_shared_data.labware.labware_definition import LabwareDefinition from opentrons_shared_data.command import known_schema_ids @@ -18,19 +18,19 @@ class Command(BaseModel): commandType: str params: Dict[str, Any] - key: Optional[str] + key: Optional[str] = None class CommandAnnotation(BaseModel): commandKeys: List[str] annotationType: str - - class Config: - extra = Extra.allow + model_config = ConfigDict(extra="allow") CommandSchemaId = Enum( # type: ignore[misc] - "CommandSchemaId", ((schema_id, schema_id) for schema_id in known_schema_ids()) + "CommandSchemaId", + ((schema_id, schema_id) for schema_id in known_schema_ids()), + type=str, ) @@ -52,8 +52,5 @@ class ProtocolSchemaV8(BaseModel): commands: List[Command] commandAnnotationSchemaId: Literal["opentronsCommandAnnotationSchemaV1"] commandAnnotations: List[CommandAnnotation] - designerApplication: Optional[DesignerApplication] - - class Config: - # added for constructing the class with field name instead of alias - allow_population_by_field_name = True + designerApplication: Optional[DesignerApplication] = None + model_config = ConfigDict(populate_by_name=True) diff --git a/shared-data/python/opentrons_shared_data/protocol/models/shared_models.py b/shared-data/python/opentrons_shared_data/protocol/models/shared_models.py index 8cf3276f71f..148ca44cc7e 100644 --- a/shared-data/python/opentrons_shared_data/protocol/models/shared_models.py +++ b/shared-data/python/opentrons_shared_data/protocol/models/shared_models.py @@ -1,5 +1,4 @@ -from typing import Optional, List, Dict, Any -from typing_extensions import Literal +from typing import Optional, List, Dict, Any, Literal from enum import Enum from pydantic import BaseModel @@ -31,20 +30,20 @@ class WellDefinition(BaseModel): x: float y: float z: float - diameter: Optional[float] - yDimension: Optional[float] - xDimension: Optional[float] + diameter: Optional[float] = None + yDimension: Optional[float] = None + xDimension: Optional[float] = None class Metadata(BaseModel): - protocolName: Optional[str] - author: Optional[str] - description: Optional[str] - created: Optional[int] - lastModified: Optional[int] - category: Optional[str] - subcategory: Optional[str] - tags: Optional[List[str]] + protocolName: Optional[str] = None + author: Optional[str] = None + description: Optional[str] = None + created: Optional[int] = None + lastModified: Optional[int] = None + category: Optional[str] = None + subcategory: Optional[str] = None + tags: Optional[List[str]] = None class Module(BaseModel): @@ -61,9 +60,9 @@ class Robot(BaseModel): class DesignerApplication(BaseModel): - name: Optional[str] - version: Optional[str] - data: Optional[Dict[str, Any]] + name: Optional[str] = None + version: Optional[str] = None + data: Optional[Dict[str, Any]] = None class CommandAnnotation(BaseModel): @@ -72,16 +71,16 @@ class CommandAnnotation(BaseModel): class OffsetVector(BaseModel): - x: Optional[float] - y: Optional[float] - z: Optional[float] + x: Optional[float] = None + y: Optional[float] = None + z: Optional[float] = None class Location(BaseModel): - slotName: Optional[str] - moduleId: Optional[str] - labwareId: Optional[str] - addressableAreaName: Optional[str] + slotName: Optional[str] = None + moduleId: Optional[str] = None + labwareId: Optional[str] = None + addressableAreaName: Optional[str] = None class ProfileStep(BaseModel): @@ -90,22 +89,22 @@ class ProfileStep(BaseModel): class WellLocation(BaseModel): - origin: Optional[str] - offset: Optional[OffsetVector] + origin: Optional[str] = None + offset: Optional[OffsetVector] = None class Liquid(BaseModel): displayName: str description: str - displayColor: Optional[str] + displayColor: Optional[str] = None class Labware(BaseModel): - displayName: Optional[str] + displayName: Optional[str] = None definitionId: str class NozzleConfigurationParams(BaseModel): style: str - primaryNozzle: Optional[str] - frontRightNozzle: Optional[str] + primaryNozzle: Optional[str] = None + frontRightNozzle: Optional[str] = None diff --git a/shared-data/python/setup.py b/shared-data/python/setup.py index 4e1720cb610..d58ed77c94d 100644 --- a/shared-data/python/setup.py +++ b/shared-data/python/setup.py @@ -141,9 +141,9 @@ def get_version(): ) PACKAGES = find_packages(where=".", exclude=["tests", "tests.*"]) INSTALL_REQUIRES = [ - "jsonschema>=3.0.1,<4.18.0", + "jsonschema>=4.0.0,<5", "typing-extensions>=4.0.0,<5", - "pydantic>=1.10.9,<2.0.0", + "pydantic>=2.0.0,<3.0.0", ] diff --git a/shared-data/python/tests/deck/test_typechecks.py b/shared-data/python/tests/deck/test_typechecks.py index a5fa3747e99..9477f9c6292 100644 --- a/shared-data/python/tests/deck/test_typechecks.py +++ b/shared-data/python/tests/deck/test_typechecks.py @@ -12,12 +12,12 @@ @pytest.mark.parametrize("defname", list_deck_definition_names(version=3)) -def test_v3_defs(defname): +def test_v3_defs(defname: str) -> None: defn = load_deck_definition(name=defname, version=3) typeguard.check_type(defn, DeckDefinitionV3) @pytest.mark.parametrize("defname", list_deck_definition_names(version=5)) -def test_v5_defs(defname): +def test_v5_defs(defname: str) -> None: defn = load_deck_definition(name=defname, version=5) typeguard.check_type(defn, DeckDefinitionV5) diff --git a/shared-data/python/tests/labware/test_typechecks.py b/shared-data/python/tests/labware/test_typechecks.py index b62dd27cc70..0e9a8b4b724 100644 --- a/shared-data/python/tests/labware/test_typechecks.py +++ b/shared-data/python/tests/labware/test_typechecks.py @@ -8,6 +8,6 @@ @pytest.mark.parametrize("loadname,version", get_ot_defs()) -def test_opentrons_definition_types(loadname, version): +def test_opentrons_definition_types(loadname: str, version: int) -> None: defdict = load_definition(loadname, version) typeguard.check_type(defdict, LabwareDefinition) diff --git a/shared-data/python/tests/pipette/test_typechecks.py b/shared-data/python/tests/pipette/test_typechecks.py index a44b673d3ed..e953443846f 100644 --- a/shared-data/python/tests/pipette/test_typechecks.py +++ b/shared-data/python/tests/pipette/test_typechecks.py @@ -1,6 +1,8 @@ import pytest import typeguard +from typing import Generator, Tuple + from opentrons_shared_data.pipette import ( model_config, name_config, @@ -11,20 +13,22 @@ PipetteModelSpecs, PipetteNameSpecs, PipetteFusedSpec, + PipetteName, + PipetteModel, ) -def test_model_config_check(): +def test_model_config_check() -> None: defdict = model_config() typeguard.check_type(defdict, PipetteModelSpecs) -def test_name_config_check(): +def test_name_config_check() -> None: defdict = name_config() typeguard.check_type(defdict, PipetteNameSpecs) -def build_model_name_pairs(): +def build_model_name_pairs() -> Generator[Tuple[PipetteModel, PipetteName], None, None]: for model, conf in model_config()["config"].items(): yield model, conf["name"] for bcn in conf.get("backCompatNames", []): @@ -32,12 +36,12 @@ def build_model_name_pairs(): @pytest.mark.parametrize("model,name", list(build_model_name_pairs())) -def test_fuse(model, name): +def test_fuse(model: PipetteModel, name: PipetteName) -> None: defdict = fuse_specs(model, name) typeguard.check_type(defdict, PipetteFusedSpec) @pytest.mark.parametrize("name", list(name_config().keys())) -def test_model_for_name(name): +def test_model_for_name(name: PipetteName) -> None: model = dummy_model_for_name(name) assert model in model_config()["config"] diff --git a/shared-data/python/tests/pipette/test_validate_schema.py b/shared-data/python/tests/pipette/test_validate_schema.py index 57f19dfe3ad..a29d59f4eda 100644 --- a/shared-data/python/tests/pipette/test_validate_schema.py +++ b/shared-data/python/tests/pipette/test_validate_schema.py @@ -13,10 +13,10 @@ from opentrons_shared_data.pipette.pipette_load_name_conversions import ( convert_pipette_model, ) -from opentrons_shared_data.pipette.types import PipetteModel +from opentrons_shared_data.pipette import types -def iterate_models() -> Iterator[PipetteModel]: +def iterate_models() -> Iterator[types.PipetteModel]: """Get an iterator of all pipette models.""" _channel_model_str = { "single_channel": "single", @@ -31,7 +31,7 @@ def iterate_models() -> Iterator[PipetteModel]: for lc_dir in model_dir.iterdir(): for version_file in lc_dir.iterdir(): version_list = version_file.stem.split("_") - yield PipetteModel( + yield types.PipetteModel( f"{model_dir.stem}_{_channel_model_str[channel_dir.stem]}_v{version_list[0]}.{version_list[1]}" ) @@ -72,7 +72,7 @@ def test_pick_up_configs_configuration_by_nozzle_map_keys() -> None: for version_file in os.listdir(paths_to_validate / channel_dir / model_dir): print(version_file) version_list = version_file.split(".json")[0].split("_") - built_model: PipetteModel = PipetteModel( + built_model: types.PipetteModel = types.PipetteModel( f"{model_dir}_{_channel_model_str[channel_dir]}_v{version_list[0]}.{version_list[1]}" ) @@ -114,7 +114,7 @@ def test_pick_up_configs_configuration_ordered_from_smallest_to_largest() -> Non for model_dir in os.listdir(paths_to_validate / channel_dir): for version_file in os.listdir(paths_to_validate / channel_dir / model_dir): version_list = version_file.split(".json")[0].split("_") - built_model: PipetteModel = PipetteModel( + built_model: types.PipetteModel = types.PipetteModel( f"{model_dir}_{_channel_model_str[channel_dir]}_v{version_list[0]}.{version_list[1]}" ) @@ -145,3 +145,48 @@ def test_pick_up_configs_configuration_ordered_from_smallest_to_largest() -> Non assert len(valid_nozzle_maps.maps[pipette_maps[i]]) <= len( valid_nozzle_maps.maps[key] ) + + +def test_serializer() -> None: + """Verify that the serializer works as expected.""" + + loaded_model = load_definition( + types.PipetteModelType.p1000, + types.PipetteChannelType.NINETY_SIX_CHANNEL, + types.PipetteVersionType(3, 3), + ) + quirk_0 = types.Quirks.pickupTipShake + quirk_1 = types.Quirks.dropTipShake + loaded_model.quirks = [quirk_0, quirk_1] + + assert loaded_model.pipette_type == types.PipetteModelType.p1000 + assert loaded_model.display_category == types.PipetteGenerationType.FLEX + assert loaded_model.channels == types.PipetteChannelType.NINETY_SIX_CHANNEL + + model_dict = loaded_model.dict() + # each field should be the value of the enum class + assert ( + isinstance(model_dict["pipette_type"], str) + and model_dict["pipette_type"] == loaded_model.pipette_type.value + ) + assert ( + isinstance(model_dict["display_category"], str) + and model_dict["display_category"] == loaded_model.display_category.value + ) + assert ( + isinstance(model_dict["channels"], int) + and model_dict["channels"] == loaded_model.channels.value + ) + + assert len(model_dict["quirks"]) == 2 + dict_quirk_0 = model_dict["quirks"][0] + dict_quirk_1 = model_dict["quirks"][1] + assert isinstance(dict_quirk_0, str) and dict_quirk_0 == quirk_0.value + assert isinstance(dict_quirk_1, str) and dict_quirk_1 == quirk_1.value + + +# TODO: (AA, 4/9/2024) we should add a test to validate the dumped json to make +# sure we can re-load it as the BaseModel class. But we haven't added serializer +# for other enums yet, such as LiquidClass, and since we haven't been +# creating the definition files using model_dump/model_dump_json, it is okay to +# skip this for now. diff --git a/shared-data/python/tests/protocol/test_protocol_schema_v6.py b/shared-data/python/tests/protocol/test_protocol_schema_v6.py index cf8a073eafc..051219f5408 100644 --- a/shared-data/python/tests/protocol/test_protocol_schema_v6.py +++ b/shared-data/python/tests/protocol/test_protocol_schema_v6.py @@ -1,6 +1,7 @@ import json import pytest from typing import Any, Dict +from pathlib import Path from opentrons_shared_data import load_shared_data from opentrons_shared_data.protocol.models import ( protocol_schema_v6, @@ -16,9 +17,9 @@ @pytest.mark.parametrize("defpath", list_fixtures(6)) -def test_v6_types(defpath): +def test_v6_types(defpath: Path) -> None: def_data = load_shared_data(defpath) - def_model = protocol_schema_v6.ProtocolSchemaV6.parse_raw(def_data) + def_model = protocol_schema_v6.ProtocolSchemaV6.model_validate_json(def_data) def_dict_from_model = def_model.dict( exclude_unset=True, # 'schemaVersion' in python is '$schemaVersion' in JSON diff --git a/shared-data/python/tests/protocol/test_protocol_schema_v7.py b/shared-data/python/tests/protocol/test_protocol_schema_v7.py index 8ccb9bd725b..4045ccf35d7 100644 --- a/shared-data/python/tests/protocol/test_protocol_schema_v7.py +++ b/shared-data/python/tests/protocol/test_protocol_schema_v7.py @@ -1,6 +1,7 @@ import json import pytest from typing import Any, Dict +from pathlib import Path from opentrons_shared_data import load_shared_data from opentrons_shared_data.protocol.models import protocol_schema_v7 @@ -9,9 +10,9 @@ @pytest.mark.parametrize("defpath", list_fixtures(7)) -def test_v7_types(defpath): +def test_v7_types(defpath: Path) -> None: def_data = load_shared_data(defpath) - def_model = protocol_schema_v7.ProtocolSchemaV7.parse_raw(def_data) + def_model = protocol_schema_v7.ProtocolSchemaV7.model_validate_json(def_data) def_dict_from_model = def_model.dict( exclude_unset=True, # 'schemaVersion' in python is '$schemaVersion' in JSON diff --git a/shared-data/python/tests/protocol/test_protocol_schema_v8.py b/shared-data/python/tests/protocol/test_protocol_schema_v8.py index 63d00db571d..48c9b6d242c 100644 --- a/shared-data/python/tests/protocol/test_protocol_schema_v8.py +++ b/shared-data/python/tests/protocol/test_protocol_schema_v8.py @@ -1,5 +1,6 @@ import json import pytest +from pathlib import Path from opentrons_shared_data import load_shared_data from opentrons_shared_data.protocol.models import protocol_schema_v8 @@ -8,15 +9,9 @@ @pytest.mark.parametrize("defpath", list_fixtures(8)) -def test_v8_types(defpath): +def test_v8_types(defpath: Path) -> None: def_data = load_shared_data(defpath) - def_model = protocol_schema_v8.ProtocolSchemaV8.parse_raw(def_data) - def_dict_from_model = json.loads( - def_model.json( - exclude_unset=True, - # 'schemaVersion' in python is '$schemaVersion' in JSON - by_alias=True, - ) - ) + def_model = protocol_schema_v8.ProtocolSchemaV8.model_validate_json(def_data) + def_dict_from_model = def_model.dict(by_alias=True, exclude_unset=True) expected_def_dict = json.loads(def_data) assert def_dict_from_model == expected_def_dict diff --git a/shared-data/python/tests/protocol/test_typechecks.py b/shared-data/python/tests/protocol/test_typechecks.py index 0b52f15c24e..0b4f20511a8 100644 --- a/shared-data/python/tests/protocol/test_typechecks.py +++ b/shared-data/python/tests/protocol/test_typechecks.py @@ -1,5 +1,6 @@ import json import pytest +from pathlib import Path import typeguard from opentrons_shared_data import load_shared_data @@ -12,18 +13,18 @@ @pytest.mark.parametrize("defpath", list_fixtures(3)) -def test_v3_types(defpath): +def test_v3_types(defpath: Path) -> None: defn = json.loads(load_shared_data(defpath)) typeguard.check_type(defn, JsonProtocolV3) @pytest.mark.parametrize("defpath", list_fixtures(4)) -def test_v4_types(defpath): +def test_v4_types(defpath: Path) -> None: defn = json.loads(load_shared_data(defpath)) typeguard.check_type(defn, JsonProtocolV4) @pytest.mark.parametrize("defpath", list_fixtures(5)) -def test_v5_types(defpath): +def test_v5_types(defpath: Path) -> None: defn = json.loads(load_shared_data(defpath)) typeguard.check_type(defn, JsonProtocolV5) diff --git a/system-server/Pipfile b/system-server/Pipfile index d1ce7f43f6a..7f71cb61d77 100644 --- a/system-server/Pipfile +++ b/system-server/Pipfile @@ -4,13 +4,14 @@ verify_ssl = true name = "pypi" [packages] -fastapi = "==0.99.1" +fastapi = "==0.100.0" uvicorn = "==0.27.0.post1" anyio = "==3.7.1" typing-extensions = ">=4.0.0,<5" python-dotenv = "==1.0.1" python-multipart = "==0.0.6" -pydantic = "==1.10.12" +pydantic = "==2.9.0" +pydantic-settings = "==2.4.0" importlib-metadata = ">=4.13.0,<5" sqlalchemy = "==1.4.51" pyjwt = "==2.6.0" @@ -37,7 +38,7 @@ coverage = "==7.4.0" atomicwrites = { version = "==1.4.0", markers="sys_platform=='win32'" } colorama = { version = "==0.4.4", markers="sys_platform=='win32'" } sqlalchemy2-stubs = "==0.0.2a21" -mypy = "==1.8.0" +mypy = "==1.11.0" black = "==22.3.0" decoy = "==2.1.1" mock = "~=5.1.0" diff --git a/system-server/Pipfile.lock b/system-server/Pipfile.lock index d7d315362f2..f36f806b824 100644 --- a/system-server/Pipfile.lock +++ b/system-server/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a0353342ca006092f2014adfa5aab4abaa720a1ddc89c0dfe34d77b72ed525b1" + "sha256": "b9d3786493ef92719c2aa2738e20b27d06ac68d25a0c9ae998088b8f36d98316" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,14 @@ ] }, "default": { + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "anyio": { "hashes": [ "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780", @@ -35,20 +43,20 @@ }, "exceptiongroup": { "hashes": [ - "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", - "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.0" + "version": "==1.2.2" }, "fastapi": { "hashes": [ - "sha256:976df7bab51ac7beda9f68c4513b8c4490b5c1135c72aafd0a5ee4023ec5282e", - "sha256:ac78f717cd80d657bd183f94d33b9bda84aa376a46a9dab513586b8eef1dc6fc" + "sha256:271662daf986da8fa98dc2b7c7f61c4abdfdccfb4786d79ed8b2878f172c6d5f", + "sha256:acb5f941ea8215663283c10018323ba7ea737c571b67fc7e88e9469c7eb1d12e" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.99.1" + "version": "==0.100.0" }, "filetype": { "hashes": [ @@ -68,11 +76,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.6" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "importlib-metadata": { "hashes": [ @@ -85,46 +93,116 @@ }, "pydantic": { "hashes": [ - "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303", - "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe", - "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47", - "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494", - "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33", - "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86", - "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d", - "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c", - "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a", - "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565", - "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb", - "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62", - "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62", - "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0", - "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523", - "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d", - "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405", - "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f", - "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b", - "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718", - "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed", - "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb", - "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5", - "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc", - "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942", - "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe", - "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246", - "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350", - "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303", - "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09", - "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33", - "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8", - "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a", - "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1", - "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6", - "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d" + "sha256:c7a8a9fdf7d100afa49647eae340e2d23efa382466a8d177efcd1381e9be5598", + "sha256:f66a7073abd93214a20c5f7b32d56843137a7a2e70d02111f3be287035c45370" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.10.12" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" + }, + "pydantic-core": { + "hashes": [ + "sha256:0102e49ac7d2df3379ef8d658d3bc59d3d769b0bdb17da189b75efa861fc07b4", + "sha256:0123655fedacf035ab10c23450163c2f65a4174f2bb034b188240a6cf06bb123", + "sha256:043ef8469f72609c4c3a5e06a07a1f713d53df4d53112c6d49207c0bd3c3bd9b", + "sha256:0448b81c3dfcde439551bb04a9f41d7627f676b12701865c8a2574bcea034437", + "sha256:05b366fb8fe3d8683b11ac35fa08947d7b92be78ec64e3277d03bd7f9b7cda79", + "sha256:07049ec9306ec64e955b2e7c40c8d77dd78ea89adb97a2013d0b6e055c5ee4c5", + "sha256:084414ffe9a85a52940b49631321d636dadf3576c30259607b75516d131fecd0", + "sha256:086c5db95157dc84c63ff9d96ebb8856f47ce113c86b61065a066f8efbe80acf", + "sha256:12625e69b1199e94b0ae1c9a95d000484ce9f0182f9965a26572f054b1537e44", + "sha256:16b25a4a120a2bb7dab51b81e3d9f3cde4f9a4456566c403ed29ac81bf49744f", + "sha256:19f1352fe4b248cae22a89268720fc74e83f008057a652894f08fa931e77dced", + "sha256:1a2ab4f410f4b886de53b6bddf5dd6f337915a29dd9f22f20f3099659536b2f6", + "sha256:1c7b81beaf7c7ebde978377dc53679c6cba0e946426fc7ade54251dfe24a7604", + "sha256:1cf842265a3a820ebc6388b963ead065f5ce8f2068ac4e1c713ef77a67b71f7c", + "sha256:1eb37f7d6a8001c0f86dc8ff2ee8d08291a536d76e49e78cda8587bb54d8b329", + "sha256:23af245b8f2f4ee9e2c99cb3f93d0e22fb5c16df3f2f643f5a8da5caff12a653", + "sha256:257d6a410a0d8aeb50b4283dea39bb79b14303e0fab0f2b9d617701331ed1515", + "sha256:276ae78153a94b664e700ac362587c73b84399bd1145e135287513442e7dfbc7", + "sha256:2b1a195efd347ede8bcf723e932300292eb13a9d2a3c1f84eb8f37cbbc905b7f", + "sha256:329a721253c7e4cbd7aad4a377745fbcc0607f9d72a3cc2102dd40519be75ed2", + "sha256:358331e21a897151e54d58e08d0219acf98ebb14c567267a87e971f3d2a3be59", + "sha256:3649bd3ae6a8ebea7dc381afb7f3c6db237fc7cebd05c8ac36ca8a4187b03b30", + "sha256:3713dc093d5048bfaedbba7a8dbc53e74c44a140d45ede020dc347dda18daf3f", + "sha256:3ef71ec876fcc4d3bbf2ae81961959e8d62f8d74a83d116668409c224012e3af", + "sha256:41ae8537ad371ec018e3c5da0eb3f3e40ee1011eb9be1da7f965357c4623c501", + "sha256:4a801c5e1e13272e0909c520708122496647d1279d252c9e6e07dac216accc41", + "sha256:4c83c64d05ffbbe12d4e8498ab72bdb05bcc1026340a4a597dc647a13c1605ec", + "sha256:4cebb9794f67266d65e7e4cbe5dcf063e29fc7b81c79dc9475bd476d9534150e", + "sha256:5668b3173bb0b2e65020b60d83f5910a7224027232c9f5dc05a71a1deac9f960", + "sha256:56e6a12ec8d7679f41b3750ffa426d22b44ef97be226a9bab00a03365f217b2b", + "sha256:582871902e1902b3c8e9b2c347f32a792a07094110c1bca6c2ea89b90150caac", + "sha256:5c8aa40f6ca803f95b1c1c5aeaee6237b9e879e4dfb46ad713229a63651a95fb", + "sha256:5d813fd871b3d5c3005157622ee102e8908ad6011ec915a18bd8fde673c4360e", + "sha256:5dd0ec5f514ed40e49bf961d49cf1bc2c72e9b50f29a163b2cc9030c6742aa73", + "sha256:5f3cf3721eaf8741cffaf092487f1ca80831202ce91672776b02b875580e174a", + "sha256:6294907eaaccf71c076abdd1c7954e272efa39bb043161b4b8aa1cd76a16ce43", + "sha256:64d094ea1aa97c6ded4748d40886076a931a8bf6f61b6e43e4a1041769c39dd2", + "sha256:6650a7bbe17a2717167e3e23c186849bae5cef35d38949549f1c116031b2b3aa", + "sha256:67b6655311b00581914aba481729971b88bb8bc7996206590700a3ac85e457b8", + "sha256:6b06c5d4e8701ac2ba99a2ef835e4e1b187d41095a9c619c5b185c9068ed2a49", + "sha256:6ce883906810b4c3bd90e0ada1f9e808d9ecf1c5f0b60c6b8831d6100bcc7dd6", + "sha256:6db09153d8438425e98cdc9a289c5fade04a5d2128faff8f227c459da21b9703", + "sha256:6f80fba4af0cb1d2344869d56430e304a51396b70d46b91a55ed4959993c0589", + "sha256:743e5811b0c377eb830150d675b0847a74a44d4ad5ab8845923d5b3a756d8100", + "sha256:753294d42fb072aa1775bfe1a2ba1012427376718fa4c72de52005a3d2a22178", + "sha256:7568f682c06f10f30ef643a1e8eec4afeecdafde5c4af1b574c6df079e96f96c", + "sha256:7706e15cdbf42f8fab1e6425247dfa98f4a6f8c63746c995d6a2017f78e619ae", + "sha256:785e7f517ebb9890813d31cb5d328fa5eda825bb205065cde760b3150e4de1f7", + "sha256:7a05c0240f6c711eb381ac392de987ee974fa9336071fb697768dfdb151345ce", + "sha256:7ce7eaf9a98680b4312b7cebcdd9352531c43db00fca586115845df388f3c465", + "sha256:7ce8e26b86a91e305858e018afc7a6e932f17428b1eaa60154bd1f7ee888b5f8", + "sha256:7d0324a35ab436c9d768753cbc3c47a865a2cbc0757066cb864747baa61f6ece", + "sha256:7e9b24cca4037a561422bf5dc52b38d390fb61f7bfff64053ce1b72f6938e6b2", + "sha256:810ca06cca91de9107718dc83d9ac4d2e86efd6c02cba49a190abcaf33fb0472", + "sha256:820f6ee5c06bc868335e3b6e42d7ef41f50dfb3ea32fbd523ab679d10d8741c0", + "sha256:82764c0bd697159fe9947ad59b6db6d7329e88505c8f98990eb07e84cc0a5d81", + "sha256:8ae65fdfb8a841556b52935dfd4c3f79132dc5253b12c0061b96415208f4d622", + "sha256:8d5b0ff3218858859910295df6953d7bafac3a48d5cd18f4e3ed9999efd2245f", + "sha256:95d6bf449a1ac81de562d65d180af5d8c19672793c81877a2eda8fde5d08f2fd", + "sha256:964c7aa318da542cdcc60d4a648377ffe1a2ef0eb1e996026c7f74507b720a78", + "sha256:96ef39add33ff58cd4c112cbac076726b96b98bb8f1e7f7595288dcfb2f10b57", + "sha256:a6612c2a844043e4d10a8324c54cdff0042c558eef30bd705770793d70b224aa", + "sha256:a8031074a397a5925d06b590121f8339d34a5a74cfe6970f8a1124eb8b83f4ac", + "sha256:aab9e522efff3993a9e98ab14263d4e20211e62da088298089a03056980a3e69", + "sha256:ae579143826c6f05a361d9546446c432a165ecf1c0b720bbfd81152645cb897d", + "sha256:ae90b9e50fe1bd115b24785e962b51130340408156d34d67b5f8f3fa6540938e", + "sha256:b18cf68255a476b927910c6873d9ed00da692bb293c5b10b282bd48a0afe3ae2", + "sha256:b7efb12e5071ad8d5b547487bdad489fbd4a5a35a0fc36a1941517a6ad7f23e0", + "sha256:c4d9f15ffe68bcd3898b0ad7233af01b15c57d91cd1667f8d868e0eacbfe3f87", + "sha256:c53100c8ee5a1e102766abde2158077d8c374bee0639201f11d3032e3555dfbc", + "sha256:c57e493a0faea1e4c38f860d6862ba6832723396c884fbf938ff5e9b224200e2", + "sha256:c8319e0bd6a7b45ad76166cc3d5d6a36c97d0c82a196f478c3ee5346566eebfd", + "sha256:caffda619099cfd4f63d48462f6aadbecee3ad9603b4b88b60cb821c1b258576", + "sha256:cc0c316fba3ce72ac3ab7902a888b9dc4979162d320823679da270c2d9ad0cad", + "sha256:cdd02a08205dc90238669f082747612cb3c82bd2c717adc60f9b9ecadb540f80", + "sha256:d50ac34835c6a4a0d456b5db559b82047403c4317b3bc73b3455fefdbdc54b0a", + "sha256:d6b9dd6aa03c812017411734e496c44fef29b43dba1e3dd1fa7361bbacfc1354", + "sha256:da3131ef2b940b99106f29dfbc30d9505643f766704e14c5d5e504e6a480c35e", + "sha256:da43cbe593e3c87d07108d0ebd73771dc414488f1f91ed2e204b0370b94b37ac", + "sha256:dd59638025160056687d598b054b64a79183f8065eae0d3f5ca523cde9943940", + "sha256:e1895e949f8849bc2757c0dbac28422a04be031204df46a56ab34bcf98507342", + "sha256:e1a79ad49f346aa1a2921f31e8dbbab4d64484823e813a002679eaa46cba39e1", + "sha256:e460475719721d59cd54a350c1f71c797c763212c836bf48585478c5514d2854", + "sha256:e64ffaf8f6e17ca15eb48344d86a7a741454526f3a3fa56bc493ad9d7ec63936", + "sha256:e6e3ccebdbd6e53474b0bb7ab8b88e83c0cfe91484b25e058e581348ee5a01a5", + "sha256:e758d271ed0286d146cf7c04c539a5169a888dd0b57026be621547e756af55bc", + "sha256:f087879f1ffde024dd2788a30d55acd67959dcf6c431e9d3682d1c491a0eb474", + "sha256:f477d26183e94eaafc60b983ab25af2a809a1b48ce4debb57b343f671b7a90b6", + "sha256:fc535cb898ef88333cf317777ecdfe0faac1c2a3187ef7eb061b6f7ecf7e6bae" + ], + "markers": "python_version >= '3.8'", + "version": "==2.23.2" + }, + "pydantic-settings": { + "hashes": [ + "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315", + "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.4.0" }, "pyjwt": { "hashes": [ @@ -159,11 +237,11 @@ }, "sniffio": { "hashes": [ - "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", - "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" + "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", + "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" ], "markers": "python_version >= '3.7'", - "version": "==1.3.0" + "version": "==1.3.1" }, "sqlalchemy": { "hashes": [ @@ -239,12 +317,20 @@ }, "typing-extensions": { "hashes": [ - "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", - "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.11.0" + "version": "==4.12.2" + }, + "tzdata": { + "hashes": [ + "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", + "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.1" }, "uvicorn": { "hashes": [ @@ -265,11 +351,11 @@ }, "zipp": { "hashes": [ - "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31", - "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0" + "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064", + "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b" ], "markers": "python_version >= '3.8'", - "version": "==3.17.0" + "version": "==3.20.1" } }, "develop": { @@ -283,11 +369,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "black": { "hashes": [ @@ -321,11 +407,11 @@ }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.8.30" }, "charset-normalizer": { "hashes": [ @@ -430,19 +516,19 @@ }, "exceptiongroup": { "hashes": [ - "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", - "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.0" + "version": "==1.2.2" }, "execnet": { "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" + "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", + "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==2.1.1" }, "flake8": { "hashes": [ @@ -482,11 +568,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.6" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "iniconfig": { "hashes": [ @@ -506,11 +592,11 @@ }, "jsonschema": { "hashes": [ - "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f", - "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5" + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" ], "markers": "python_version >= '3.8'", - "version": "==4.21.1" + "version": "==4.23.0" }, "jsonschema-specifications": { "hashes": [ @@ -539,37 +625,37 @@ }, "mypy": { "hashes": [ - "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6", - "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d", - "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02", - "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d", - "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3", - "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3", - "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", - "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66", - "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259", - "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", - "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd", - "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", - "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8", - "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", - "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b", - "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e", - "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6", - "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", - "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9", - "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", - "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a", - "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592", - "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218", - "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", - "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4", - "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410", - "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" + "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", + "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095", + "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac", + "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6", + "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", + "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", + "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00", + "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", + "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7", + "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13", + "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be", + "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", + "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850", + "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287", + "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", + "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229", + "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", + "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c", + "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac", + "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", + "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", + "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", + "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9", + "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", + "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf", + "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe", + "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.8.0" + "version": "==1.11.0" }, "mypy-extensions": { "hashes": [ @@ -581,11 +667,11 @@ }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==23.2" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "paho-mqtt": { "hashes": [ @@ -603,27 +689,27 @@ }, "pbr": { "hashes": [ - "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda", - "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9" + "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24", + "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a" ], "markers": "python_version >= '2.6'", - "version": "==6.0.0" + "version": "==6.1.0" }, "platformdirs": { "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", + "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" ], "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.2.2" }, "pluggy": { "hashes": [ - "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", - "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.4.0" + "version": "==1.5.0" }, "py": { "hashes": [ @@ -750,76 +836,78 @@ }, "python-dateutil": { "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" + "version": "==2.9.0.post0" }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "referencing": { "hashes": [ - "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5", - "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7" + "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", + "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" ], "markers": "python_version >= '3.8'", - "version": "==0.33.0" + "version": "==0.35.1" }, "requests": { "hashes": [ @@ -832,116 +920,120 @@ }, "rpds-py": { "hashes": [ - "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147", - "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7", - "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2", - "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68", - "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1", - "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382", - "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d", - "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921", - "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38", - "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4", - "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a", - "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d", - "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518", - "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e", - "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d", - "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf", - "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5", - "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba", - "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6", - "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59", - "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253", - "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6", - "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f", - "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3", - "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea", - "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1", - "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76", - "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93", - "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad", - "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad", - "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc", - "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049", - "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d", - "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90", - "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d", - "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd", - "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25", - "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2", - "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f", - "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6", - "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4", - "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c", - "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8", - "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d", - "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b", - "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19", - "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453", - "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9", - "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde", - "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296", - "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58", - "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec", - "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99", - "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a", - "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb", - "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383", - "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d", - "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896", - "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc", - "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6", - "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b", - "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7", - "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22", - "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf", - "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394", - "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0", - "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57", - "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74", - "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83", - "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29", - "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9", - "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f", - "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745", - "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb", - "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811", - "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55", - "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342", - "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23", - "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82", - "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041", - "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb", - "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066", - "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55", - "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6", - "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a", - "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140", - "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b", - "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9", - "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256", - "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c", - "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772", - "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4", - "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae", - "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920", - "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a", - "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b", - "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361", - "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8", - "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a" + "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c", + "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585", + "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5", + "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6", + "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef", + "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2", + "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29", + "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318", + "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b", + "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399", + "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739", + "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee", + "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174", + "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a", + "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344", + "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2", + "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03", + "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5", + "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22", + "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e", + "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96", + "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91", + "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752", + "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075", + "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253", + "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee", + "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad", + "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5", + "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce", + "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7", + "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b", + "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8", + "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57", + "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3", + "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec", + "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209", + "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921", + "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045", + "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074", + "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580", + "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7", + "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5", + "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3", + "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0", + "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24", + "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139", + "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db", + "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc", + "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789", + "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f", + "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2", + "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c", + "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232", + "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6", + "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c", + "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29", + "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489", + "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94", + "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751", + "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2", + "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda", + "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9", + "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51", + "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c", + "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8", + "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989", + "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511", + "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1", + "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2", + "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150", + "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c", + "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965", + "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f", + "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58", + "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b", + "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f", + "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d", + "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821", + "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de", + "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121", + "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855", + "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272", + "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60", + "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02", + "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1", + "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140", + "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879", + "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940", + "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364", + "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4", + "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e", + "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420", + "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5", + "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24", + "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c", + "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf", + "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f", + "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e", + "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab", + "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08", + "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92", + "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a", + "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8" ], "markers": "python_version >= '3.8'", - "version": "==0.17.1" + "version": "==0.20.0" }, "ruamel.yaml": { "hashes": [ - "sha256:61917e3a35a569c1133a8f772e1226961bf5a1198bea7e23f06a0841dea1ab0e", - "sha256:a013ac02f99a69cdd6277d9664689eb1acba07069f912823177c5eced21a6ada" + "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636", + "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b" ], "markers": "python_version >= '3.7'", - "version": "==0.18.5" + "version": "==0.18.6" }, "ruamel.yaml.clib": { "hashes": [ @@ -1033,12 +1125,12 @@ }, "tavern": { "hashes": [ - "sha256:056c4c45e27c97552ae9a3eb6a249701820a09465b4131cc4e71489166d8442d", - "sha256:21ce0c29f9e15e4b613f5f43df6da96ed0e115e5d52b4b8c1501e898708e9d35" + "sha256:5a7c4234ab9e3aaaafb9b0e72c589d735d9b04cdee1fb082f6682e80f9a806f8", + "sha256:a3ad7e843452c84170e2865414d8629a57263100fa5875ed2414853f7720943a" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.9.1" + "version": "==2.9.3" }, "tomli": { "hashes": [ @@ -1066,20 +1158,20 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.12.2" }, "urllib3": { "hashes": [ - "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07", - "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0" + "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", + "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.18" + "version": "==1.26.20" } } } diff --git a/system-server/setup.py b/system-server/setup.py index 4aeed436d55..232786cca4f 100644 --- a/system-server/setup.py +++ b/system-server/setup.py @@ -50,6 +50,7 @@ def get_version(): "pyjwt==2.6.0", "systemd-python==234; sys_platform=='linux'", "sqlalchemy==1.4.51", + "pydantic-settings==2.4.0", ] diff --git a/system-server/system_server/settings/settings.py b/system-server/system_server/settings/settings.py index 32e34079ebd..d7b90658e8f 100644 --- a/system-server/system_server/settings/settings.py +++ b/system-server/system_server/settings/settings.py @@ -2,8 +2,9 @@ import typing from functools import lru_cache -from pydantic import BaseSettings, Field +from pydantic import Field from dotenv import load_dotenv, set_key +from pydantic_settings import BaseSettings, SettingsConfigDict @lru_cache(maxsize=1) @@ -23,11 +24,7 @@ class Environment(BaseSettings): default=None, description="Path to a .env file to define system server settings.", ) - - class Config: - """Prefix configuration for environment variables.""" - - env_prefix = "OT_SYSTEM_SERVER_" + model_config = SettingsConfigDict(env_prefix="OT_SYSTEM_SERVER_") # If you update this, also update the generated settings_schema.json. @@ -69,19 +66,16 @@ class SystemServerSettings(BaseSettings): " the splash screen changes when the flag is enabled/disabled." ), ) - - class Config: - """Prefix configuration for environment variables.""" - - env_file = Environment().dot_env_path - env_prefix = "OT_SYSTEM_SERVER_" + model_config = SettingsConfigDict( + env_file=Environment().dot_env_path, env_prefix="OT_SYSTEM_SERVER_" + ) def save_settings(settings: SystemServerSettings) -> bool: """Save the settings to the dotenv file.""" env_path = Environment().dot_env_path env_path = env_path or f"{settings.persistence_directory}/system.env" - prefix = settings.Config.env_prefix + prefix = settings.model_config.get("env_prefix") try: for key, val in settings.dict().items(): name = f"{prefix}{key}" diff --git a/update-server/Pipfile b/update-server/Pipfile index 975e075afb9..c8d57b66a99 100644 --- a/update-server/Pipfile +++ b/update-server/Pipfile @@ -22,7 +22,7 @@ coverage = "==7.4.1" # https://github.com/pypa/pipenv/issues/4408#issuecomment-668324177 atomicwrites = {version="==1.4.0", markers="sys_platform=='win32'"} colorama = {version="==0.4.4", markers="sys_platform=='win32'"} -mypy = "==1.8.0" +mypy = "==1.11.0" black = "==22.3.0" decoy = "~=2.1.1" diff --git a/update-server/Pipfile.lock b/update-server/Pipfile.lock index 9f26d21c134..b45abf00681 100644 --- a/update-server/Pipfile.lock +++ b/update-server/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "115cd9d2eae2f695378fed0db8301eb63a0d84ac581e0ee0b606f0d77293206e" + "sha256": "125917af563c336d6ac51990931ecbc50c3da52f83b1e274290fc436da72f97c" }, "pipfile-spec": 6, "requires": { @@ -116,11 +116,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "frozenlist": { "hashes": [ @@ -207,11 +207,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.6" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "multidict": { "hashes": [ @@ -315,111 +315,121 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.12.2" }, "yarl": { "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" + "sha256:0324506afab4f2e176a93cb08b8abcb8b009e1f324e6cbced999a8f5dd9ddb76", + "sha256:0a205ec6349879f5e75dddfb63e069a24f726df5330b92ce76c4752a436aac01", + "sha256:0b0c70c451d2a86f8408abced5b7498423e2487543acf6fcf618b03f6e669b0a", + "sha256:0b2a8e5eb18181060197e3d5db7e78f818432725c0759bc1e5a9d603d9246389", + "sha256:0cbcc2c54084b2bda4109415631db017cf2960f74f9e8fd1698e1400e4f8aae2", + "sha256:17107b4b8c43e66befdcbe543fff2f9c93f7a3a9f8e3a9c9ac42bffeba0e8828", + "sha256:1c82126817492bb2ebc946e74af1ffa10aacaca81bee360858477f96124be39a", + "sha256:1cdb8f5bb0534986776a43df84031da7ff04ac0cf87cb22ae8a6368231949c40", + "sha256:21e56c30e39a1833e4e3fd0112dde98c2abcbc4c39b077e6105c76bb63d2aa04", + "sha256:224f8186c220ff00079e64bf193909829144d4e5174bb58665ef0da8bf6955c4", + "sha256:2d1c81c3b92bef0c1c180048e43a5a85754a61b4f69d6f84df8e4bd615bef25d", + "sha256:30f201bc65941a4aa59c1236783efe89049ec5549dafc8cd2b63cc179d3767b0", + "sha256:3a26a24bbd19241283d601173cea1e5b93dec361a223394e18a1e8e5b0ef20bd", + "sha256:3fcd056cb7dff3aea5b1ee1b425b0fbaa2fbf6a1c6003e88caf524f01de5f395", + "sha256:441049d3a449fb8756b0535be72c6a1a532938a33e1cf03523076700a5f87a01", + "sha256:4567cc08f479ad80fb07ed0c9e1bcb363a4f6e3483a490a39d57d1419bf1c4c7", + "sha256:475e09a67f8b09720192a170ad9021b7abf7827ffd4f3a83826317a705be06b7", + "sha256:47c0a3dc8076a8dd159de10628dea04215bc7ddaa46c5775bf96066a0a18f82b", + "sha256:4915818ac850c3b0413e953af34398775b7a337babe1e4d15f68c8f5c4872553", + "sha256:498439af143b43a2b2314451ffd0295410aa0dcbdac5ee18fc8633da4670b605", + "sha256:4ae079573efeaa54e5978ce86b77f4175cd32f42afcaf9bfb8a0677e91f84e4e", + "sha256:4d368e3b9ecd50fa22017a20c49e356471af6ae91c4d788c6e9297e25ddf5a62", + "sha256:4e4f820fde9437bb47297194f43d29086433e6467fa28fe9876366ad357bd7bb", + "sha256:504d19320c92532cabc3495fb7ed6bb599f3c2bfb45fed432049bf4693dbd6d0", + "sha256:51a6f770ac86477cd5c553f88a77a06fe1f6f3b643b053fcc7902ab55d6cbe14", + "sha256:545f2fbfa0c723b446e9298b5beba0999ff82ce2c126110759e8dac29b5deaf4", + "sha256:54cc24be98d7f4ff355ca2e725a577e19909788c0db6beead67a0dda70bd3f82", + "sha256:55a67dd29367ce7c08a0541bb602ec0a2c10d46c86b94830a1a665f7fd093dfa", + "sha256:569309a3efb8369ff5d32edb2a0520ebaf810c3059f11d34477418c90aa878fd", + "sha256:58081cea14b8feda57c7ce447520e9d0a96c4d010cce54373d789c13242d7083", + "sha256:5b593acd45cdd4cf6664d342ceacedf25cd95263b83b964fddd6c78930ea5211", + "sha256:5c23f6dc3d7126b4c64b80aa186ac2bb65ab104a8372c4454e462fb074197bc6", + "sha256:614fa50fd0db41b79f426939a413d216cdc7bab8d8c8a25844798d286a999c5a", + "sha256:61ec0e80970b21a8f3c4b97fa6c6d181c6c6a135dbc7b4a601a78add3feeb209", + "sha256:63a5dc2866791236779d99d7a422611d22bb3a3d50935bafa4e017ea13e51469", + "sha256:675004040f847c0284827f44a1fa92d8baf425632cc93e7e0aa38408774b07c1", + "sha256:67abcb7df27952864440c9c85f1c549a4ad94afe44e2655f77d74b0d25895454", + "sha256:6de3fa29e76fd1518a80e6af4902c44f3b1b4d7fed28eb06913bba4727443de3", + "sha256:6ff184002ee72e4b247240e35d5dce4c2d9a0e81fdbef715dde79ab4718aa541", + "sha256:70194da6e99713250aa3f335a7fa246b36adf53672a2bcd0ddaa375d04e53dc0", + "sha256:7230007ab67d43cf19200ec15bc6b654e6b85c402f545a6fc565d254d34ff754", + "sha256:735b285ea46ca7e86ad261a462a071d0968aade44e1a3ea2b7d4f3d63b5aab12", + "sha256:752c0d33b4aacdb147871d0754b88f53922c6dc2aff033096516b3d5f0c02a0f", + "sha256:752f4b5cf93268dc73c2ae994cc6d684b0dad5118bc87fbd965fd5d6dca20f45", + "sha256:755ae9cff06c429632d750aa8206f08df2e3d422ca67be79567aadbe74ae64cc", + "sha256:79e08c691deae6fcac2fdde2e0515ac561dd3630d7c8adf7b1e786e22f1e193b", + "sha256:7d2dee7d6485807c0f64dd5eab9262b7c0b34f760e502243dd83ec09d647d5e1", + "sha256:8503989860d7ac10c85cb5b607fec003a45049cf7a5b4b72451e87893c6bb990", + "sha256:85333d38a4fa5997fa2ff6fd169be66626d814b34fa35ec669e8c914ca50a097", + "sha256:8c2cf0c7ad745e1c6530fe6521dfb19ca43338239dfcc7da165d0ef2332c0882", + "sha256:8d6e1c1562b53bd26efd38e886fc13863b8d904d559426777990171020c478a9", + "sha256:8d7b717f77846a9631046899c6cc730ea469c0e2fb252ccff1cc119950dbc296", + "sha256:8e8ed183c7a8f75e40068333fc185566472a8f6c77a750cf7541e11810576ea5", + "sha256:9137975a4ccc163ad5d7a75aad966e6e4e95dedee08d7995eab896a639a0bce2", + "sha256:91c478741d7563a12162f7a2db96c0d23d93b0521563f1f1f0ece46ea1702d33", + "sha256:922ba3b74f0958a0b5b9c14ff1ef12714a381760c08018f2b9827632783a590c", + "sha256:94f71d54c5faf715e92c8434b4a0b968c4d1043469954d228fc031d51086f143", + "sha256:95adc179a02949c4560ef40f8f650a008380766eb253d74232eb9c024747c111", + "sha256:9636e4519f6c7558fdccf8f91e6e3b98df2340dc505c4cc3286986d33f2096c2", + "sha256:9e290de5db4fd4859b4ed57cddfe793fcb218504e65781854a8ac283ab8d5518", + "sha256:9fae7ec5c9a4fe22abb995804e6ce87067dfaf7e940272b79328ce37c8f22097", + "sha256:a5706821e1cf3c70dfea223e4e0958ea354f4e2af9420a1bd45c6b547297fb97", + "sha256:a744bdeda6c86cf3025c94eb0e01ccabe949cf385cd75b6576a3ac9669404b68", + "sha256:aaeffcb84faceb2923a94a8a9aaa972745d3c728ab54dd011530cc30a3d5d0c1", + "sha256:aeba4aaa59cb709edb824fa88a27cbbff4e0095aaf77212b652989276c493c00", + "sha256:afcac5bda602b74ff701e1f683feccd8cce0d5a21dbc68db81bf9bd8fd93ba56", + "sha256:b30703a7ade2b53f02e09a30685b70cd54f65ed314a8d9af08670c9a5391af1b", + "sha256:b3dfe17b4aed832c627319da22a33f27f282bd32633d6b145c726d519c89fbaf", + "sha256:b4a0e724a28d7447e4d549c8f40779f90e20147e94bf949d490402eee09845c6", + "sha256:b8f847cc092c2b85d22e527f91ea83a6cf51533e727e2461557a47a859f96734", + "sha256:c189bf01af155ac9882e128d9f3b3ad68a1f2c2f51404afad7201305df4e12b1", + "sha256:c1db9a4384694b5d20bdd9cb53f033b0831ac816416ab176c8d0997835015d22", + "sha256:c305c1bdf10869b5e51facf50bd5b15892884aeae81962ae4ba061fc11217103", + "sha256:c335342d482e66254ae94b1231b1532790afb754f89e2e0c646f7f19d09740aa", + "sha256:c59b23886234abeba62087fd97d10fb6b905d9e36e2f3465d1886ce5c0ca30df", + "sha256:c5b7b307140231ea4f7aad5b69355aba2a67f2d7bc34271cffa3c9c324d35b27", + "sha256:c6f6c87665a9e18a635f0545ea541d9640617832af2317d4f5ad389686b4ed3d", + "sha256:c7548a90cb72b67652e2cd6ae80e2683ee08fde663104528ac7df12d8ef271d2", + "sha256:ca35996e0a4bed28fa0640d9512d37952f6b50dea583bcc167d4f0b1e112ac7f", + "sha256:cc295969f8c2172b5d013c0871dccfec7a0e1186cf961e7ea575d47b4d5cbd32", + "sha256:ce2bd986b1e44528677c237b74d59f215c8bfcdf2d69442aa10f62fd6ab2951c", + "sha256:d65ad67f981e93ea11f87815f67d086c4f33da4800cf2106d650dd8a0b79dda4", + "sha256:d93c612b2024ac25a3dc01341fd98fdd19c8c5e2011f3dcd084b3743cba8d756", + "sha256:ddad5cfcda729e22422bb1c85520bdf2770ce6d975600573ac9017fe882f4b7e", + "sha256:dfa9b9d5c9c0dbe69670f5695264452f5e40947590ec3a38cfddc9640ae8ff89", + "sha256:e4a8c3dedd081cca134a21179aebe58b6e426e8d1e0202da9d1cafa56e01af3c", + "sha256:e5f50a2e26cc2b89186f04c97e0ec0ba107ae41f1262ad16832d46849864f914", + "sha256:e700eb26635ce665c018c8cfea058baff9b843ed0cc77aa61849d807bb82a64c", + "sha256:ef9610b2f5a73707d4d8bac040f0115ca848e510e3b1f45ca53e97f609b54130", + "sha256:f568d70b7187f4002b6b500c0996c37674a25ce44b20716faebe5fdb8bd356e7", + "sha256:fee45b3bd4d8d5786472e056aa1359cc4dc9da68aded95a10cd7929a0ec661fe", + "sha256:ff64f575d71eacb5a4d6f0696bfe991993d979423ea2241f23ab19ff63f0f9d1" ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" + "markers": "python_version >= '3.8'", + "version": "==1.9.11" } }, "develop": { + "aiohappyeyeballs": { + "hashes": [ + "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2", + "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd" + ], + "markers": "python_version >= '3.8'", + "version": "==2.4.0" + }, "aiohttp": { "hashes": [ "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168", @@ -528,11 +538,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "black": { "hashes": [ @@ -659,11 +669,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", - "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.0" + "version": "==1.2.2" }, "flake8": { "hashes": [ @@ -786,11 +796,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.6" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "iniconfig": { "hashes": [ @@ -906,37 +916,37 @@ }, "mypy": { "hashes": [ - "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6", - "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d", - "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02", - "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d", - "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3", - "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3", - "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", - "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66", - "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259", - "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", - "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd", - "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", - "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8", - "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", - "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b", - "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e", - "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6", - "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", - "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9", - "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", - "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a", - "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592", - "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218", - "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", - "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4", - "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410", - "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" + "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", + "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095", + "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac", + "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6", + "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", + "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", + "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00", + "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", + "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7", + "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13", + "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be", + "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", + "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850", + "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287", + "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", + "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229", + "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", + "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c", + "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac", + "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", + "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", + "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", + "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9", + "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", + "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf", + "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe", + "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.8.0" + "version": "==1.11.0" }, "mypy-extensions": { "hashes": [ @@ -948,11 +958,11 @@ }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==23.2" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pathspec": { "hashes": [ @@ -964,19 +974,19 @@ }, "platformdirs": { "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", + "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" ], "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.2.2" }, "pluggy": { "hashes": [ - "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", - "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.4.0" + "version": "==1.5.0" }, "pycodestyle": { "hashes": [ @@ -1022,11 +1032,11 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2", - "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef" + "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", + "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3" ], "markers": "python_version >= '3.8'", - "version": "==0.23.4" + "version": "==0.23.8" }, "pytest-cov": { "hashes": [ @@ -1061,141 +1071,146 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.12.2" }, "watchdog": { "hashes": [ - "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a", - "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100", - "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8", - "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc", - "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae", - "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41", - "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0", - "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f", - "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c", - "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9", - "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3", - "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709", - "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83", - "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759", - "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9", - "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3", - "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7", - "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f", - "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346", - "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674", - "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397", - "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96", - "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d", - "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a", - "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64", - "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44", - "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33" + "sha256:14dd4ed023d79d1f670aa659f449bcd2733c33a35c8ffd88689d9d243885198b", + "sha256:29e4a2607bd407d9552c502d38b45a05ec26a8e40cc7e94db9bb48f861fa5abc", + "sha256:3960136b2b619510569b90f0cd96408591d6c251a75c97690f4553ca88889769", + "sha256:3e8d5ff39f0a9968952cce548e8e08f849141a4fcc1290b1c17c032ba697b9d7", + "sha256:53ed1bf71fcb8475dd0ef4912ab139c294c87b903724b6f4a8bd98e026862e6d", + "sha256:5597c051587f8757798216f2485e85eac583c3b343e9aa09127a3a6f82c65ee8", + "sha256:638bcca3d5b1885c6ec47be67bf712b00a9ab3d4b22ec0881f4889ad870bc7e8", + "sha256:6bec703ad90b35a848e05e1b40bf0050da7ca28ead7ac4be724ae5ac2653a1a0", + "sha256:726eef8f8c634ac6584f86c9c53353a010d9f311f6c15a034f3800a7a891d941", + "sha256:72990192cb63872c47d5e5fefe230a401b87fd59d257ee577d61c9e5564c62e5", + "sha256:7d1aa7e4bb0f0c65a1a91ba37c10e19dabf7eaaa282c5787e51371f090748f4b", + "sha256:8c47150aa12f775e22efff1eee9f0f6beee542a7aa1a985c271b1997d340184f", + "sha256:901ee48c23f70193d1a7bc2d9ee297df66081dd5f46f0ca011be4f70dec80dab", + "sha256:963f7c4c91e3f51c998eeff1b3fb24a52a8a34da4f956e470f4b068bb47b78ee", + "sha256:9814adb768c23727a27792c77812cf4e2fd9853cd280eafa2bcfa62a99e8bd6e", + "sha256:aa9cd6e24126d4afb3752a3e70fce39f92d0e1a58a236ddf6ee823ff7dba28ee", + "sha256:b6dc8f1d770a8280997e4beae7b9a75a33b268c59e033e72c8a10990097e5fde", + "sha256:b84bff0391ad4abe25c2740c7aec0e3de316fdf7764007f41e248422a7760a7f", + "sha256:ba32efcccfe2c58f4d01115440d1672b4eb26cdd6fc5b5818f1fb41f7c3e1889", + "sha256:bda40c57115684d0216556671875e008279dea2dc00fcd3dde126ac8e0d7a2fb", + "sha256:c4a440f725f3b99133de610bfec93d570b13826f89616377715b9cd60424db6e", + "sha256:d010be060c996db725fbce7e3ef14687cdcc76f4ca0e4339a68cc4532c382a73", + "sha256:d2ab34adc9bf1489452965cdb16a924e97d4452fcf88a50b21859068b50b5c3b", + "sha256:d7594a6d32cda2b49df3fd9abf9b37c8d2f3eab5df45c24056b4a671ac661619", + "sha256:d961f4123bb3c447d9fcdcb67e1530c366f10ab3a0c7d1c0c9943050936d4877", + "sha256:dae7a1879918f6544201d33666909b040a46421054a50e0f773e0d870ed7438d", + "sha256:dcebf7e475001d2cdeb020be630dc5b687e9acdd60d16fea6bb4508e7b94cf76", + "sha256:f627c5bf5759fdd90195b0c0431f99cff4867d212a67b384442c51136a098ed7", + "sha256:f8b2918c19e0d48f5f20df458c84692e2a054f02d9df25e6c3c930063eca64c1", + "sha256:fb223456db6e5f7bd9bbd5cd969f05aae82ae21acc00643b60d81c770abd402b" ], - "markers": "python_version >= '3.7'", - "version": "==3.0.0" + "markers": "python_version >= '3.9'", + "version": "==5.0.2" }, "yarl": { "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" + "sha256:0324506afab4f2e176a93cb08b8abcb8b009e1f324e6cbced999a8f5dd9ddb76", + "sha256:0a205ec6349879f5e75dddfb63e069a24f726df5330b92ce76c4752a436aac01", + "sha256:0b0c70c451d2a86f8408abced5b7498423e2487543acf6fcf618b03f6e669b0a", + "sha256:0b2a8e5eb18181060197e3d5db7e78f818432725c0759bc1e5a9d603d9246389", + "sha256:0cbcc2c54084b2bda4109415631db017cf2960f74f9e8fd1698e1400e4f8aae2", + "sha256:17107b4b8c43e66befdcbe543fff2f9c93f7a3a9f8e3a9c9ac42bffeba0e8828", + "sha256:1c82126817492bb2ebc946e74af1ffa10aacaca81bee360858477f96124be39a", + "sha256:1cdb8f5bb0534986776a43df84031da7ff04ac0cf87cb22ae8a6368231949c40", + "sha256:21e56c30e39a1833e4e3fd0112dde98c2abcbc4c39b077e6105c76bb63d2aa04", + "sha256:224f8186c220ff00079e64bf193909829144d4e5174bb58665ef0da8bf6955c4", + "sha256:2d1c81c3b92bef0c1c180048e43a5a85754a61b4f69d6f84df8e4bd615bef25d", + "sha256:30f201bc65941a4aa59c1236783efe89049ec5549dafc8cd2b63cc179d3767b0", + "sha256:3a26a24bbd19241283d601173cea1e5b93dec361a223394e18a1e8e5b0ef20bd", + "sha256:3fcd056cb7dff3aea5b1ee1b425b0fbaa2fbf6a1c6003e88caf524f01de5f395", + "sha256:441049d3a449fb8756b0535be72c6a1a532938a33e1cf03523076700a5f87a01", + "sha256:4567cc08f479ad80fb07ed0c9e1bcb363a4f6e3483a490a39d57d1419bf1c4c7", + "sha256:475e09a67f8b09720192a170ad9021b7abf7827ffd4f3a83826317a705be06b7", + "sha256:47c0a3dc8076a8dd159de10628dea04215bc7ddaa46c5775bf96066a0a18f82b", + "sha256:4915818ac850c3b0413e953af34398775b7a337babe1e4d15f68c8f5c4872553", + "sha256:498439af143b43a2b2314451ffd0295410aa0dcbdac5ee18fc8633da4670b605", + "sha256:4ae079573efeaa54e5978ce86b77f4175cd32f42afcaf9bfb8a0677e91f84e4e", + "sha256:4d368e3b9ecd50fa22017a20c49e356471af6ae91c4d788c6e9297e25ddf5a62", + "sha256:4e4f820fde9437bb47297194f43d29086433e6467fa28fe9876366ad357bd7bb", + "sha256:504d19320c92532cabc3495fb7ed6bb599f3c2bfb45fed432049bf4693dbd6d0", + "sha256:51a6f770ac86477cd5c553f88a77a06fe1f6f3b643b053fcc7902ab55d6cbe14", + "sha256:545f2fbfa0c723b446e9298b5beba0999ff82ce2c126110759e8dac29b5deaf4", + "sha256:54cc24be98d7f4ff355ca2e725a577e19909788c0db6beead67a0dda70bd3f82", + "sha256:55a67dd29367ce7c08a0541bb602ec0a2c10d46c86b94830a1a665f7fd093dfa", + "sha256:569309a3efb8369ff5d32edb2a0520ebaf810c3059f11d34477418c90aa878fd", + "sha256:58081cea14b8feda57c7ce447520e9d0a96c4d010cce54373d789c13242d7083", + "sha256:5b593acd45cdd4cf6664d342ceacedf25cd95263b83b964fddd6c78930ea5211", + "sha256:5c23f6dc3d7126b4c64b80aa186ac2bb65ab104a8372c4454e462fb074197bc6", + "sha256:614fa50fd0db41b79f426939a413d216cdc7bab8d8c8a25844798d286a999c5a", + "sha256:61ec0e80970b21a8f3c4b97fa6c6d181c6c6a135dbc7b4a601a78add3feeb209", + "sha256:63a5dc2866791236779d99d7a422611d22bb3a3d50935bafa4e017ea13e51469", + "sha256:675004040f847c0284827f44a1fa92d8baf425632cc93e7e0aa38408774b07c1", + "sha256:67abcb7df27952864440c9c85f1c549a4ad94afe44e2655f77d74b0d25895454", + "sha256:6de3fa29e76fd1518a80e6af4902c44f3b1b4d7fed28eb06913bba4727443de3", + "sha256:6ff184002ee72e4b247240e35d5dce4c2d9a0e81fdbef715dde79ab4718aa541", + "sha256:70194da6e99713250aa3f335a7fa246b36adf53672a2bcd0ddaa375d04e53dc0", + "sha256:7230007ab67d43cf19200ec15bc6b654e6b85c402f545a6fc565d254d34ff754", + "sha256:735b285ea46ca7e86ad261a462a071d0968aade44e1a3ea2b7d4f3d63b5aab12", + "sha256:752c0d33b4aacdb147871d0754b88f53922c6dc2aff033096516b3d5f0c02a0f", + "sha256:752f4b5cf93268dc73c2ae994cc6d684b0dad5118bc87fbd965fd5d6dca20f45", + "sha256:755ae9cff06c429632d750aa8206f08df2e3d422ca67be79567aadbe74ae64cc", + "sha256:79e08c691deae6fcac2fdde2e0515ac561dd3630d7c8adf7b1e786e22f1e193b", + "sha256:7d2dee7d6485807c0f64dd5eab9262b7c0b34f760e502243dd83ec09d647d5e1", + "sha256:8503989860d7ac10c85cb5b607fec003a45049cf7a5b4b72451e87893c6bb990", + "sha256:85333d38a4fa5997fa2ff6fd169be66626d814b34fa35ec669e8c914ca50a097", + "sha256:8c2cf0c7ad745e1c6530fe6521dfb19ca43338239dfcc7da165d0ef2332c0882", + "sha256:8d6e1c1562b53bd26efd38e886fc13863b8d904d559426777990171020c478a9", + "sha256:8d7b717f77846a9631046899c6cc730ea469c0e2fb252ccff1cc119950dbc296", + "sha256:8e8ed183c7a8f75e40068333fc185566472a8f6c77a750cf7541e11810576ea5", + "sha256:9137975a4ccc163ad5d7a75aad966e6e4e95dedee08d7995eab896a639a0bce2", + "sha256:91c478741d7563a12162f7a2db96c0d23d93b0521563f1f1f0ece46ea1702d33", + "sha256:922ba3b74f0958a0b5b9c14ff1ef12714a381760c08018f2b9827632783a590c", + "sha256:94f71d54c5faf715e92c8434b4a0b968c4d1043469954d228fc031d51086f143", + "sha256:95adc179a02949c4560ef40f8f650a008380766eb253d74232eb9c024747c111", + "sha256:9636e4519f6c7558fdccf8f91e6e3b98df2340dc505c4cc3286986d33f2096c2", + "sha256:9e290de5db4fd4859b4ed57cddfe793fcb218504e65781854a8ac283ab8d5518", + "sha256:9fae7ec5c9a4fe22abb995804e6ce87067dfaf7e940272b79328ce37c8f22097", + "sha256:a5706821e1cf3c70dfea223e4e0958ea354f4e2af9420a1bd45c6b547297fb97", + "sha256:a744bdeda6c86cf3025c94eb0e01ccabe949cf385cd75b6576a3ac9669404b68", + "sha256:aaeffcb84faceb2923a94a8a9aaa972745d3c728ab54dd011530cc30a3d5d0c1", + "sha256:aeba4aaa59cb709edb824fa88a27cbbff4e0095aaf77212b652989276c493c00", + "sha256:afcac5bda602b74ff701e1f683feccd8cce0d5a21dbc68db81bf9bd8fd93ba56", + "sha256:b30703a7ade2b53f02e09a30685b70cd54f65ed314a8d9af08670c9a5391af1b", + "sha256:b3dfe17b4aed832c627319da22a33f27f282bd32633d6b145c726d519c89fbaf", + "sha256:b4a0e724a28d7447e4d549c8f40779f90e20147e94bf949d490402eee09845c6", + "sha256:b8f847cc092c2b85d22e527f91ea83a6cf51533e727e2461557a47a859f96734", + "sha256:c189bf01af155ac9882e128d9f3b3ad68a1f2c2f51404afad7201305df4e12b1", + "sha256:c1db9a4384694b5d20bdd9cb53f033b0831ac816416ab176c8d0997835015d22", + "sha256:c305c1bdf10869b5e51facf50bd5b15892884aeae81962ae4ba061fc11217103", + "sha256:c335342d482e66254ae94b1231b1532790afb754f89e2e0c646f7f19d09740aa", + "sha256:c59b23886234abeba62087fd97d10fb6b905d9e36e2f3465d1886ce5c0ca30df", + "sha256:c5b7b307140231ea4f7aad5b69355aba2a67f2d7bc34271cffa3c9c324d35b27", + "sha256:c6f6c87665a9e18a635f0545ea541d9640617832af2317d4f5ad389686b4ed3d", + "sha256:c7548a90cb72b67652e2cd6ae80e2683ee08fde663104528ac7df12d8ef271d2", + "sha256:ca35996e0a4bed28fa0640d9512d37952f6b50dea583bcc167d4f0b1e112ac7f", + "sha256:cc295969f8c2172b5d013c0871dccfec7a0e1186cf961e7ea575d47b4d5cbd32", + "sha256:ce2bd986b1e44528677c237b74d59f215c8bfcdf2d69442aa10f62fd6ab2951c", + "sha256:d65ad67f981e93ea11f87815f67d086c4f33da4800cf2106d650dd8a0b79dda4", + "sha256:d93c612b2024ac25a3dc01341fd98fdd19c8c5e2011f3dcd084b3743cba8d756", + "sha256:ddad5cfcda729e22422bb1c85520bdf2770ce6d975600573ac9017fe882f4b7e", + "sha256:dfa9b9d5c9c0dbe69670f5695264452f5e40947590ec3a38cfddc9640ae8ff89", + "sha256:e4a8c3dedd081cca134a21179aebe58b6e426e8d1e0202da9d1cafa56e01af3c", + "sha256:e5f50a2e26cc2b89186f04c97e0ec0ba107ae41f1262ad16832d46849864f914", + "sha256:e700eb26635ce665c018c8cfea058baff9b843ed0cc77aa61849d807bb82a64c", + "sha256:ef9610b2f5a73707d4d8bac040f0115ca848e510e3b1f45ca53e97f609b54130", + "sha256:f568d70b7187f4002b6b500c0996c37674a25ce44b20716faebe5fdb8bd356e7", + "sha256:fee45b3bd4d8d5786472e056aa1359cc4dc9da68aded95a10cd7929a0ec661fe", + "sha256:ff64f575d71eacb5a4d6f0696bfe991993d979423ea2241f23ab19ff63f0f9d1" ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" + "markers": "python_version >= '3.8'", + "version": "==1.9.11" } } } diff --git a/update-server/otupdate/common/update_actions.py b/update-server/otupdate/common/update_actions.py index 56bd94f0abe..493029c066d 100644 --- a/update-server/otupdate/common/update_actions.py +++ b/update-server/otupdate/common/update_actions.py @@ -69,8 +69,8 @@ def write_update( self, rootfs_filepath: str, progress_callback: Callable[[float], None], - chunk_size: int, - file_size: Optional[int], + chunk_size: int = -1, + file_size: Optional[int] = None, ) -> Partition: """ Write the object to a specific rootfs path diff --git a/usb-bridge/Pipfile b/usb-bridge/Pipfile index 2743d3ab675..f5eb483758c 100644 --- a/usb-bridge/Pipfile +++ b/usb-bridge/Pipfile @@ -27,7 +27,7 @@ coverage = "==7.4.1" # https://github.com/pypa/pipenv/issues/4408#issuecomment-668324177 atomicwrites = {version="==1.4.0", markers="sys_platform=='win32'"} colorama = {version="==0.4.4", markers="sys_platform=='win32'"} -mypy = "==1.8.0" +mypy = "==1.11.0" black = "==22.3.0" decoy = "==2.1.1" mock = "~=5.1.0" diff --git a/usb-bridge/Pipfile.lock b/usb-bridge/Pipfile.lock index 6b7e9e62891..d67941d6143 100644 --- a/usb-bridge/Pipfile.lock +++ b/usb-bridge/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "0b53af0693972f92ea86d9477ff4af66c57874db5089a27727368fb15b48e534" + "sha256": "5c727aa6b7962e7cb9abe6cc03e205b5e4fcad066e4a2fc728a99c093b7060ac" }, "pipfile-spec": 6, "requires": { @@ -46,96 +46,119 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.12.2" } }, "develop": { + "aiohappyeyeballs": { + "hashes": [ + "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2", + "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd" + ], + "markers": "python_version >= '3.8'", + "version": "==2.4.0" + }, "aiohttp": { "hashes": [ - "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168", - "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb", - "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5", - "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f", - "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc", - "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c", - "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29", - "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4", - "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc", - "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc", - "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63", - "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e", - "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d", - "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a", - "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60", - "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38", - "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b", - "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2", - "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53", - "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5", - "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4", - "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96", - "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58", - "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa", - "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321", - "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae", - "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce", - "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8", - "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194", - "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c", - "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf", - "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d", - "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869", - "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b", - "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52", - "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528", - "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5", - "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1", - "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4", - "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8", - "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d", - "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7", - "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5", - "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54", - "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3", - "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5", - "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c", - "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29", - "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3", - "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747", - "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672", - "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5", - "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11", - "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca", - "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768", - "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6", - "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2", - "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533", - "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6", - "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266", - "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d", - "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec", - "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5", - "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1", - "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b", - "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679", - "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283", - "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb", - "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b", - "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3", - "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051", - "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511", - "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e", - "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d", - "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542", - "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f" + "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277", + "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1", + "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe", + "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb", + "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca", + "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91", + "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972", + "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a", + "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3", + "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa", + "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77", + "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b", + "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8", + "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599", + "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc", + "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf", + "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511", + "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699", + "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487", + "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987", + "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff", + "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db", + "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022", + "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce", + "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a", + "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5", + "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7", + "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820", + "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf", + "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e", + "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf", + "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5", + "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6", + "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6", + "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91", + "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3", + "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a", + "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d", + "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088", + "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc", + "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f", + "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75", + "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471", + "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e", + "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697", + "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092", + "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69", + "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3", + "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32", + "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589", + "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178", + "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92", + "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2", + "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e", + "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058", + "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857", + "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1", + "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6", + "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22", + "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0", + "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b", + "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57", + "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f", + "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e", + "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16", + "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1", + "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f", + "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6", + "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04", + "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae", + "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d", + "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b", + "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f", + "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862", + "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689", + "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c", + "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683", + "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef", + "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f", + "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12", + "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73", + "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061", + "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072", + "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11", + "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691", + "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77", + "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385", + "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172", + "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569", + "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f", + "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5" ], "markers": "python_version >= '3.8'", - "version": "==3.9.3" + "version": "==3.10.5" }, "aiosignal": { "hashes": [ @@ -163,11 +186,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "black": { "hashes": [ @@ -294,19 +317,19 @@ }, "exceptiongroup": { "hashes": [ - "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", - "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.0" + "version": "==1.2.2" }, "execnet": { "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" + "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", + "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==2.1.1" }, "flake8": { "hashes": [ @@ -429,11 +452,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.6" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "iniconfig": { "hashes": [ @@ -558,37 +581,37 @@ }, "mypy": { "hashes": [ - "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6", - "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d", - "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02", - "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d", - "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3", - "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3", - "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", - "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66", - "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259", - "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", - "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd", - "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", - "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8", - "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", - "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b", - "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e", - "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6", - "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", - "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9", - "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", - "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a", - "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592", - "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218", - "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", - "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4", - "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410", - "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" + "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", + "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095", + "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac", + "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6", + "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", + "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", + "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00", + "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", + "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7", + "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13", + "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be", + "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", + "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850", + "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287", + "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", + "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229", + "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", + "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c", + "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac", + "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", + "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", + "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", + "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9", + "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", + "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf", + "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe", + "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.8.0" + "version": "==1.11.0" }, "mypy-extensions": { "hashes": [ @@ -600,11 +623,11 @@ }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==23.2" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pathspec": { "hashes": [ @@ -616,19 +639,19 @@ }, "platformdirs": { "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", + "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" ], "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.2.2" }, "pluggy": { "hashes": [ - "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", - "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.4.0" + "version": "==1.5.0" }, "py": { "hashes": [ @@ -682,12 +705,12 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2", - "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef" + "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", + "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.23.4" + "version": "==0.23.8" }, "pytest-cov": { "hashes": [ @@ -747,150 +770,155 @@ }, "types-mock": { "hashes": [ - "sha256:13ca379d5710ccb3f18f69ade5b08881874cb83383d8fb49b1d4dac9d5c5d090", - "sha256:3d116955495935b0bcba14954b38d97e507cd43eca3e3700fc1b8e4f5c6bf2c7" + "sha256:5281a645d72e827d70043e3cc144fe33b1c003db084f789dc203aa90e812a5a4", + "sha256:d586a01d39ad919d3ddcd73de6cde73ca7f3c69707219f722d1b8d7733641ad7" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==5.1.0.20240106" + "version": "==5.1.0.20240425" }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.12.2" }, "watchdog": { "hashes": [ - "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a", - "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100", - "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8", - "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc", - "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae", - "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41", - "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0", - "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f", - "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c", - "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9", - "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3", - "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709", - "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83", - "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759", - "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9", - "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3", - "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7", - "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f", - "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346", - "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674", - "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397", - "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96", - "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d", - "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a", - "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64", - "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44", - "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33" - ], - "markers": "python_version >= '3.7'", - "version": "==3.0.0" + "sha256:14dd4ed023d79d1f670aa659f449bcd2733c33a35c8ffd88689d9d243885198b", + "sha256:29e4a2607bd407d9552c502d38b45a05ec26a8e40cc7e94db9bb48f861fa5abc", + "sha256:3960136b2b619510569b90f0cd96408591d6c251a75c97690f4553ca88889769", + "sha256:3e8d5ff39f0a9968952cce548e8e08f849141a4fcc1290b1c17c032ba697b9d7", + "sha256:53ed1bf71fcb8475dd0ef4912ab139c294c87b903724b6f4a8bd98e026862e6d", + "sha256:5597c051587f8757798216f2485e85eac583c3b343e9aa09127a3a6f82c65ee8", + "sha256:638bcca3d5b1885c6ec47be67bf712b00a9ab3d4b22ec0881f4889ad870bc7e8", + "sha256:6bec703ad90b35a848e05e1b40bf0050da7ca28ead7ac4be724ae5ac2653a1a0", + "sha256:726eef8f8c634ac6584f86c9c53353a010d9f311f6c15a034f3800a7a891d941", + "sha256:72990192cb63872c47d5e5fefe230a401b87fd59d257ee577d61c9e5564c62e5", + "sha256:7d1aa7e4bb0f0c65a1a91ba37c10e19dabf7eaaa282c5787e51371f090748f4b", + "sha256:8c47150aa12f775e22efff1eee9f0f6beee542a7aa1a985c271b1997d340184f", + "sha256:901ee48c23f70193d1a7bc2d9ee297df66081dd5f46f0ca011be4f70dec80dab", + "sha256:963f7c4c91e3f51c998eeff1b3fb24a52a8a34da4f956e470f4b068bb47b78ee", + "sha256:9814adb768c23727a27792c77812cf4e2fd9853cd280eafa2bcfa62a99e8bd6e", + "sha256:aa9cd6e24126d4afb3752a3e70fce39f92d0e1a58a236ddf6ee823ff7dba28ee", + "sha256:b6dc8f1d770a8280997e4beae7b9a75a33b268c59e033e72c8a10990097e5fde", + "sha256:b84bff0391ad4abe25c2740c7aec0e3de316fdf7764007f41e248422a7760a7f", + "sha256:ba32efcccfe2c58f4d01115440d1672b4eb26cdd6fc5b5818f1fb41f7c3e1889", + "sha256:bda40c57115684d0216556671875e008279dea2dc00fcd3dde126ac8e0d7a2fb", + "sha256:c4a440f725f3b99133de610bfec93d570b13826f89616377715b9cd60424db6e", + "sha256:d010be060c996db725fbce7e3ef14687cdcc76f4ca0e4339a68cc4532c382a73", + "sha256:d2ab34adc9bf1489452965cdb16a924e97d4452fcf88a50b21859068b50b5c3b", + "sha256:d7594a6d32cda2b49df3fd9abf9b37c8d2f3eab5df45c24056b4a671ac661619", + "sha256:d961f4123bb3c447d9fcdcb67e1530c366f10ab3a0c7d1c0c9943050936d4877", + "sha256:dae7a1879918f6544201d33666909b040a46421054a50e0f773e0d870ed7438d", + "sha256:dcebf7e475001d2cdeb020be630dc5b687e9acdd60d16fea6bb4508e7b94cf76", + "sha256:f627c5bf5759fdd90195b0c0431f99cff4867d212a67b384442c51136a098ed7", + "sha256:f8b2918c19e0d48f5f20df458c84692e2a054f02d9df25e6c3c930063eca64c1", + "sha256:fb223456db6e5f7bd9bbd5cd969f05aae82ae21acc00643b60d81c770abd402b" + ], + "markers": "python_version >= '3.9'", + "version": "==5.0.2" }, "yarl": { "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" + "sha256:0324506afab4f2e176a93cb08b8abcb8b009e1f324e6cbced999a8f5dd9ddb76", + "sha256:0a205ec6349879f5e75dddfb63e069a24f726df5330b92ce76c4752a436aac01", + "sha256:0b0c70c451d2a86f8408abced5b7498423e2487543acf6fcf618b03f6e669b0a", + "sha256:0b2a8e5eb18181060197e3d5db7e78f818432725c0759bc1e5a9d603d9246389", + "sha256:0cbcc2c54084b2bda4109415631db017cf2960f74f9e8fd1698e1400e4f8aae2", + "sha256:17107b4b8c43e66befdcbe543fff2f9c93f7a3a9f8e3a9c9ac42bffeba0e8828", + "sha256:1c82126817492bb2ebc946e74af1ffa10aacaca81bee360858477f96124be39a", + "sha256:1cdb8f5bb0534986776a43df84031da7ff04ac0cf87cb22ae8a6368231949c40", + "sha256:21e56c30e39a1833e4e3fd0112dde98c2abcbc4c39b077e6105c76bb63d2aa04", + "sha256:224f8186c220ff00079e64bf193909829144d4e5174bb58665ef0da8bf6955c4", + "sha256:2d1c81c3b92bef0c1c180048e43a5a85754a61b4f69d6f84df8e4bd615bef25d", + "sha256:30f201bc65941a4aa59c1236783efe89049ec5549dafc8cd2b63cc179d3767b0", + "sha256:3a26a24bbd19241283d601173cea1e5b93dec361a223394e18a1e8e5b0ef20bd", + "sha256:3fcd056cb7dff3aea5b1ee1b425b0fbaa2fbf6a1c6003e88caf524f01de5f395", + "sha256:441049d3a449fb8756b0535be72c6a1a532938a33e1cf03523076700a5f87a01", + "sha256:4567cc08f479ad80fb07ed0c9e1bcb363a4f6e3483a490a39d57d1419bf1c4c7", + "sha256:475e09a67f8b09720192a170ad9021b7abf7827ffd4f3a83826317a705be06b7", + "sha256:47c0a3dc8076a8dd159de10628dea04215bc7ddaa46c5775bf96066a0a18f82b", + "sha256:4915818ac850c3b0413e953af34398775b7a337babe1e4d15f68c8f5c4872553", + "sha256:498439af143b43a2b2314451ffd0295410aa0dcbdac5ee18fc8633da4670b605", + "sha256:4ae079573efeaa54e5978ce86b77f4175cd32f42afcaf9bfb8a0677e91f84e4e", + "sha256:4d368e3b9ecd50fa22017a20c49e356471af6ae91c4d788c6e9297e25ddf5a62", + "sha256:4e4f820fde9437bb47297194f43d29086433e6467fa28fe9876366ad357bd7bb", + "sha256:504d19320c92532cabc3495fb7ed6bb599f3c2bfb45fed432049bf4693dbd6d0", + "sha256:51a6f770ac86477cd5c553f88a77a06fe1f6f3b643b053fcc7902ab55d6cbe14", + "sha256:545f2fbfa0c723b446e9298b5beba0999ff82ce2c126110759e8dac29b5deaf4", + "sha256:54cc24be98d7f4ff355ca2e725a577e19909788c0db6beead67a0dda70bd3f82", + "sha256:55a67dd29367ce7c08a0541bb602ec0a2c10d46c86b94830a1a665f7fd093dfa", + "sha256:569309a3efb8369ff5d32edb2a0520ebaf810c3059f11d34477418c90aa878fd", + "sha256:58081cea14b8feda57c7ce447520e9d0a96c4d010cce54373d789c13242d7083", + "sha256:5b593acd45cdd4cf6664d342ceacedf25cd95263b83b964fddd6c78930ea5211", + "sha256:5c23f6dc3d7126b4c64b80aa186ac2bb65ab104a8372c4454e462fb074197bc6", + "sha256:614fa50fd0db41b79f426939a413d216cdc7bab8d8c8a25844798d286a999c5a", + "sha256:61ec0e80970b21a8f3c4b97fa6c6d181c6c6a135dbc7b4a601a78add3feeb209", + "sha256:63a5dc2866791236779d99d7a422611d22bb3a3d50935bafa4e017ea13e51469", + "sha256:675004040f847c0284827f44a1fa92d8baf425632cc93e7e0aa38408774b07c1", + "sha256:67abcb7df27952864440c9c85f1c549a4ad94afe44e2655f77d74b0d25895454", + "sha256:6de3fa29e76fd1518a80e6af4902c44f3b1b4d7fed28eb06913bba4727443de3", + "sha256:6ff184002ee72e4b247240e35d5dce4c2d9a0e81fdbef715dde79ab4718aa541", + "sha256:70194da6e99713250aa3f335a7fa246b36adf53672a2bcd0ddaa375d04e53dc0", + "sha256:7230007ab67d43cf19200ec15bc6b654e6b85c402f545a6fc565d254d34ff754", + "sha256:735b285ea46ca7e86ad261a462a071d0968aade44e1a3ea2b7d4f3d63b5aab12", + "sha256:752c0d33b4aacdb147871d0754b88f53922c6dc2aff033096516b3d5f0c02a0f", + "sha256:752f4b5cf93268dc73c2ae994cc6d684b0dad5118bc87fbd965fd5d6dca20f45", + "sha256:755ae9cff06c429632d750aa8206f08df2e3d422ca67be79567aadbe74ae64cc", + "sha256:79e08c691deae6fcac2fdde2e0515ac561dd3630d7c8adf7b1e786e22f1e193b", + "sha256:7d2dee7d6485807c0f64dd5eab9262b7c0b34f760e502243dd83ec09d647d5e1", + "sha256:8503989860d7ac10c85cb5b607fec003a45049cf7a5b4b72451e87893c6bb990", + "sha256:85333d38a4fa5997fa2ff6fd169be66626d814b34fa35ec669e8c914ca50a097", + "sha256:8c2cf0c7ad745e1c6530fe6521dfb19ca43338239dfcc7da165d0ef2332c0882", + "sha256:8d6e1c1562b53bd26efd38e886fc13863b8d904d559426777990171020c478a9", + "sha256:8d7b717f77846a9631046899c6cc730ea469c0e2fb252ccff1cc119950dbc296", + "sha256:8e8ed183c7a8f75e40068333fc185566472a8f6c77a750cf7541e11810576ea5", + "sha256:9137975a4ccc163ad5d7a75aad966e6e4e95dedee08d7995eab896a639a0bce2", + "sha256:91c478741d7563a12162f7a2db96c0d23d93b0521563f1f1f0ece46ea1702d33", + "sha256:922ba3b74f0958a0b5b9c14ff1ef12714a381760c08018f2b9827632783a590c", + "sha256:94f71d54c5faf715e92c8434b4a0b968c4d1043469954d228fc031d51086f143", + "sha256:95adc179a02949c4560ef40f8f650a008380766eb253d74232eb9c024747c111", + "sha256:9636e4519f6c7558fdccf8f91e6e3b98df2340dc505c4cc3286986d33f2096c2", + "sha256:9e290de5db4fd4859b4ed57cddfe793fcb218504e65781854a8ac283ab8d5518", + "sha256:9fae7ec5c9a4fe22abb995804e6ce87067dfaf7e940272b79328ce37c8f22097", + "sha256:a5706821e1cf3c70dfea223e4e0958ea354f4e2af9420a1bd45c6b547297fb97", + "sha256:a744bdeda6c86cf3025c94eb0e01ccabe949cf385cd75b6576a3ac9669404b68", + "sha256:aaeffcb84faceb2923a94a8a9aaa972745d3c728ab54dd011530cc30a3d5d0c1", + "sha256:aeba4aaa59cb709edb824fa88a27cbbff4e0095aaf77212b652989276c493c00", + "sha256:afcac5bda602b74ff701e1f683feccd8cce0d5a21dbc68db81bf9bd8fd93ba56", + "sha256:b30703a7ade2b53f02e09a30685b70cd54f65ed314a8d9af08670c9a5391af1b", + "sha256:b3dfe17b4aed832c627319da22a33f27f282bd32633d6b145c726d519c89fbaf", + "sha256:b4a0e724a28d7447e4d549c8f40779f90e20147e94bf949d490402eee09845c6", + "sha256:b8f847cc092c2b85d22e527f91ea83a6cf51533e727e2461557a47a859f96734", + "sha256:c189bf01af155ac9882e128d9f3b3ad68a1f2c2f51404afad7201305df4e12b1", + "sha256:c1db9a4384694b5d20bdd9cb53f033b0831ac816416ab176c8d0997835015d22", + "sha256:c305c1bdf10869b5e51facf50bd5b15892884aeae81962ae4ba061fc11217103", + "sha256:c335342d482e66254ae94b1231b1532790afb754f89e2e0c646f7f19d09740aa", + "sha256:c59b23886234abeba62087fd97d10fb6b905d9e36e2f3465d1886ce5c0ca30df", + "sha256:c5b7b307140231ea4f7aad5b69355aba2a67f2d7bc34271cffa3c9c324d35b27", + "sha256:c6f6c87665a9e18a635f0545ea541d9640617832af2317d4f5ad389686b4ed3d", + "sha256:c7548a90cb72b67652e2cd6ae80e2683ee08fde663104528ac7df12d8ef271d2", + "sha256:ca35996e0a4bed28fa0640d9512d37952f6b50dea583bcc167d4f0b1e112ac7f", + "sha256:cc295969f8c2172b5d013c0871dccfec7a0e1186cf961e7ea575d47b4d5cbd32", + "sha256:ce2bd986b1e44528677c237b74d59f215c8bfcdf2d69442aa10f62fd6ab2951c", + "sha256:d65ad67f981e93ea11f87815f67d086c4f33da4800cf2106d650dd8a0b79dda4", + "sha256:d93c612b2024ac25a3dc01341fd98fdd19c8c5e2011f3dcd084b3743cba8d756", + "sha256:ddad5cfcda729e22422bb1c85520bdf2770ce6d975600573ac9017fe882f4b7e", + "sha256:dfa9b9d5c9c0dbe69670f5695264452f5e40947590ec3a38cfddc9640ae8ff89", + "sha256:e4a8c3dedd081cca134a21179aebe58b6e426e8d1e0202da9d1cafa56e01af3c", + "sha256:e5f50a2e26cc2b89186f04c97e0ec0ba107ae41f1262ad16832d46849864f914", + "sha256:e700eb26635ce665c018c8cfea058baff9b843ed0cc77aa61849d807bb82a64c", + "sha256:ef9610b2f5a73707d4d8bac040f0115ca848e510e3b1f45ca53e97f609b54130", + "sha256:f568d70b7187f4002b6b500c0996c37674a25ce44b20716faebe5fdb8bd356e7", + "sha256:fee45b3bd4d8d5786472e056aa1359cc4dc9da68aded95a10cd7929a0ec661fe", + "sha256:ff64f575d71eacb5a4d6f0696bfe991993d979423ea2241f23ab19ff63f0f9d1" ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" + "markers": "python_version >= '3.8'", + "version": "==1.9.11" } } } From a56e919816f4da8eec582572d959ba3e3565f52e Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Wed, 18 Dec 2024 17:36:01 -0500 Subject: [PATCH 34/42] refactor: Rename Pydantic v1 methods to their v2 counterparts (#17123) --- api/pytest.ini | 11 +- .../calibration_storage/deck_configuration.py | 4 +- .../calibration_storage/file_operators.py | 4 +- .../calibration_storage/ot2/tip_length.py | 8 +- api/src/opentrons/execute.py | 4 +- .../emulation/module_server/client.py | 2 +- .../emulation/module_server/server.py | 8 +- .../instruments/ot2/instrument_calibration.py | 3 +- .../instruments/ot2/pipette.py | 10 +- .../instruments/ot3/gripper.py | 4 +- .../instruments/ot3/pipette.py | 8 +- .../hardware_control/ot3_calibration.py | 2 +- .../hardware_control/robot_calibration.py | 2 +- .../protocol_api/core/engine/labware.py | 8 +- .../protocol_api/core/engine/protocol.py | 2 +- .../commands/absorbance_reader/read.py | 10 +- .../commands/calibration/calibrate_gripper.py | 4 +- .../commands/calibration/calibrate_pipette.py | 4 +- .../commands/configure_nozzle_layout.py | 8 +- .../protocol_engine/commands/custom.py | 2 +- .../commands/movement_common.py | 8 +- .../protocol_engine/commands/touch_tip.py | 2 +- .../errors/error_occurrence.py | 2 +- .../execution/command_executor.py | 2 +- .../opentrons/protocol_engine/notes/notes.py | 2 +- .../resources/labware_data_provider.py | 2 +- .../resources/module_data_provider.py | 2 +- .../protocol_engine/slot_standardization.py | 18 +-- .../protocol_engine/state/geometry.py | 2 +- .../protocol_engine/state/labware.py | 10 +- .../protocol_engine/state/modules.py | 2 +- .../opentrons/protocol_engine/state/state.py | 2 +- api/src/opentrons/protocol_engine/types.py | 2 +- .../extract_labware_definitions.py | 2 +- .../protocol_reader/file_format_validator.py | 10 +- .../protocol_runner/json_translator.py | 16 +-- .../protocol_runner/legacy_command_mapper.py | 124 +++++++++--------- .../python_protocol_wrappers.py | 2 +- api/src/opentrons/simulate.py | 4 +- .../test_file_operators.py | 2 +- .../test_tip_length_ot2.py | 2 +- .../hardware_control/test_gripper.py | 4 +- .../commands/test_air_gap_in_place.py | 4 +- .../protocol_engine/commands/test_aspirate.py | 8 +- .../commands/test_aspirate_in_place.py | 4 +- .../protocol_engine/commands/test_blow_out.py | 4 +- .../commands/test_blow_out_in_place.py | 2 +- .../protocol_engine/commands/test_dispense.py | 10 +- .../commands/test_dispense_in_place.py | 4 +- .../protocol_engine/commands/test_drop_tip.py | 8 +- .../commands/test_drop_tip_in_place.py | 2 +- .../commands/test_liquid_probe.py | 4 +- .../commands/test_load_liquid_class.py | 2 +- .../commands/test_move_relative.py | 2 +- .../commands/test_move_to_addressable_area.py | 2 +- ...t_move_to_addressable_area_for_drop_tip.py | 2 +- .../commands/test_move_to_coordinates.py | 2 +- .../commands/test_move_to_well.py | 2 +- .../commands/test_pick_up_tip.py | 4 +- .../commands/test_prepare_to_aspirate.py | 2 +- .../opentrons/protocol_engine/conftest.py | 30 +++-- .../resources/test_labware_data_provider.py | 6 +- .../state/test_command_history.py | 6 +- .../smoke_tests/test_legacy_command_mapper.py | 66 +++++----- .../smoke_tests/test_legacy_custom_labware.py | 2 +- .../test_legacy_module_commands.py | 12 +- .../smoke_tests/test_protocol_runner.py | 32 ++--- .../protocol_runner/test_json_translator.py | 28 ++-- .../test_legacy_command_mapper.py | 28 ++-- .../protocol_runner/test_run_orchestrator.py | 6 +- .../protocols/models/test_json_protocol.py | 4 +- hardware/pytest.ini | 6 + robot-server/pytest.ini | 8 +- .../robot_server/client_data/router.py | 8 +- robot-server/robot_server/commands/router.py | 10 +- .../robot_server/data_files/router.py | 18 +-- .../deck_configuration/defaults.py | 52 ++++---- .../robot_server/deck_configuration/router.py | 6 +- .../robot_server/deck_configuration/store.py | 8 +- .../error_recovery/settings/router.py | 4 +- .../robot_server/errors/error_responses.py | 2 +- .../robot_server/errors/global_errors.py | 2 +- .../robot_server/instruments/router.py | 18 +-- .../robot_server/labware_offsets/models.py | 7 +- .../robot_server/labware_offsets/router.py | 14 +- .../maintenance_run_data_manager.py | 4 +- .../maintenance_runs/router/base_router.py | 10 +- .../router/commands_router.py | 14 +- .../maintenance_runs/router/labware_router.py | 6 +- robot-server/robot_server/modules/router.py | 4 +- .../persistence/_migrations/up_to_2.py | 4 +- .../persistence/_migrations/up_to_3.py | 5 +- .../robot_server/persistence/pydantic.py | 6 +- .../robot_server/protocols/analysis_store.py | 10 +- robot-server/robot_server/protocols/router.py | 40 +++--- .../robot_server/robot/control/router.py | 8 +- .../runs/router/actions_router.py | 2 +- .../robot_server/runs/router/base_router.py | 26 ++-- .../runs/router/commands_router.py | 16 +-- .../router/error_recovery_policy_router.py | 6 +- .../runs/router/labware_router.py | 8 +- .../robot_server/runs/run_data_manager.py | 6 +- robot-server/robot_server/service/errors.py | 2 +- .../robot_server/service/json_api/response.py | 24 +++- .../service/legacy/routers/networking.py | 4 +- .../notifications/notification_client.py | 8 +- .../command_execution/callable_executor.py | 2 +- .../robot_server/service/session/router.py | 2 +- .../robot_server/subsystems/router.py | 26 ++-- robot-server/tests/instruments/test_router.py | 10 +- .../router/test_labware_router.py | 2 +- .../maintenance_runs/test_engine_store.py | 2 +- .../tests/modules/test_module_data_mapper.py | 8 +- robot-server/tests/modules/test_router.py | 4 +- .../tests/persistence/test_pydantic.py | 4 +- .../tests/protocols/test_protocol_analyzer.py | 2 +- .../tests/protocols/test_protocols_router.py | 2 +- .../tests/runs/router/test_base_router.py | 4 +- .../tests/runs/router/test_labware_router.py | 4 +- .../tests/runs/test_error_recovery_mapping.py | 8 +- .../tests/runs/test_run_data_manager.py | 2 +- .../tests/runs/test_run_orchestrator_store.py | 2 +- robot-server/tests/runs/test_run_store.py | 6 +- .../tests/service/json_api/test_request.py | 18 +-- .../service/json_api/test_resource_links.py | 6 +- .../tests/service/json_api/test_response.py | 2 +- .../service/session/models/test_command.py | 4 +- robot-server/tests/subsystems/test_router.py | 24 ++-- server-utils/pytest.ini | 6 + .../opentrons_shared_data/gripper/__init__.py | 2 +- .../liquid_classes/__init__.py | 7 +- .../pipette/load_data.py | 10 +- .../pipette/mutable_configurations.py | 8 +- .../pipette/scripts/build_json_script.py | 16 +-- .../scripts/update_configuration_files.py | 8 +- shared-data/python/pytest.ini | 6 + .../python/tests/gripper/test_definition.py | 6 +- .../python/tests/labware/test_validations.py | 4 +- .../python/tests/liquid_classes/test_load.py | 4 +- .../python/tests/pipette/test_load_data.py | 2 +- .../pipette/test_mutable_configurations.py | 4 +- .../tests/pipette/test_pipette_definition.py | 8 +- .../tests/pipette/test_validate_schema.py | 2 +- .../tests/protocol/test_protocol_schema_v6.py | 2 +- .../tests/protocol/test_protocol_schema_v7.py | 2 +- .../tests/protocol/test_protocol_schema_v8.py | 2 +- system-server/pytest.ini | 6 + .../system_server/settings/settings.py | 2 +- 148 files changed, 659 insertions(+), 586 deletions(-) diff --git a/api/pytest.ini b/api/pytest.ini index 61288b3f3c1..78115d41057 100644 --- a/api/pytest.ini +++ b/api/pytest.ini @@ -6,8 +6,13 @@ markers = addopts = --color=yes --strict-markers asyncio_mode = auto -# TODO this should be looked into being removed upon updating the Decoy library. The purpose of this warning is to -# catch missing attributes, but it raises for any property referenced in a test which accounts for about ~250 warnings -# which aren't serving any useful purpose and obscure other warnings. filterwarnings = + # TODO this should be looked into being removed upon updating the Decoy library. The purpose of this warning is to + # catch missing attributes, but it raises for any property referenced in a test which accounts for about ~250 warnings + # which aren't serving any useful purpose and obscure other warnings. ignore::decoy.warnings.MissingSpecAttributeWarning + # Pydantic's shims for its legacy v1 methods (e.g. `BaseModel.construct()`) + # are not type-checked properly. Forbid them, so we're forced to use their newer + # v2 replacements which are type-checked (e.g. ``BaseModel.model_construct()`) + error::pydantic.PydanticDeprecatedSince20 + diff --git a/api/src/opentrons/calibration_storage/deck_configuration.py b/api/src/opentrons/calibration_storage/deck_configuration.py index 5c97ab37f25..857c2c22d3f 100644 --- a/api/src/opentrons/calibration_storage/deck_configuration.py +++ b/api/src/opentrons/calibration_storage/deck_configuration.py @@ -24,9 +24,9 @@ def serialize_deck_configuration( cutout_fixture_placements: List[CutoutFixturePlacement], last_modified: datetime ) -> bytes: """Serialize a deck configuration for storing on the filesystem.""" - data = _DeckConfigurationModel.construct( + data = _DeckConfigurationModel.model_construct( cutoutFixtures=[ - _CutoutFixturePlacementModel.construct( + _CutoutFixturePlacementModel.model_construct( cutoutId=e.cutout_id, cutoutFixtureId=e.cutout_fixture_id, opentronsModuleSerialNumber=e.opentrons_module_serial_number, diff --git a/api/src/opentrons/calibration_storage/file_operators.py b/api/src/opentrons/calibration_storage/file_operators.py index ddc046fd828..bf80a034d54 100644 --- a/api/src/opentrons/calibration_storage/file_operators.py +++ b/api/src/opentrons/calibration_storage/file_operators.py @@ -103,7 +103,7 @@ def save_to_file( directory_path.mkdir(parents=True, exist_ok=True) file_path = directory_path / f"{file_name}.json" json_data = ( - data.json() + data.model_dump_json() if isinstance(data, pydantic.BaseModel) else json.dumps(data, cls=encoder) ) @@ -112,7 +112,7 @@ def save_to_file( def serialize_pydantic_model(data: pydantic.BaseModel) -> bytes: """Safely serialize data from a Pydantic model into a form suitable for storing on disk.""" - return data.json(by_alias=True).encode("utf-8") + return data.model_dump_json(by_alias=True).encode("utf-8") _ModelT = typing.TypeVar("_ModelT", bound=pydantic.BaseModel) diff --git a/api/src/opentrons/calibration_storage/ot2/tip_length.py b/api/src/opentrons/calibration_storage/ot2/tip_length.py index a63472c9cea..979916bd85e 100644 --- a/api/src/opentrons/calibration_storage/ot2/tip_length.py +++ b/api/src/opentrons/calibration_storage/ot2/tip_length.py @@ -31,7 +31,7 @@ def _convert_tip_length_model_to_dict( # add encoders when converting to a dict. dict_of_tip_lengths = {} for key, item in to_dict.items(): - dict_of_tip_lengths[key] = json.loads(item.json()) + dict_of_tip_lengths[key] = json.loads(item.model_dump_json()) return dict_of_tip_lengths @@ -176,12 +176,14 @@ def delete_tip_length_calibration( io.save_to_file(tip_length_dir, pipette_id, dict_of_tip_lengths) else: io.delete_file(tip_length_dir / f"{pipette_id}.json") - elif tiprack_hash and any(tiprack_hash in v.dict() for v in tip_lengths.values()): + elif tiprack_hash and any( + tiprack_hash in v.model_dump() for v in tip_lengths.values() + ): # NOTE this is for backwards compatibilty only # TODO delete this check once the tip_length DELETE router # no longer depends on a tiprack hash for k, v in tip_lengths.items(): - if tiprack_hash in v.dict(): + if tiprack_hash in v.model_dump(): tip_lengths.pop(k) if tip_lengths: dict_of_tip_lengths = _convert_tip_length_model_to_dict(tip_lengths) diff --git a/api/src/opentrons/execute.py b/api/src/opentrons/execute.py index a9b3562d82b..998d6bc6597 100644 --- a/api/src/opentrons/execute.py +++ b/api/src/opentrons/execute.py @@ -560,7 +560,9 @@ def _create_live_context_pe( # Non-async would use call_soon_threadsafe(), which makes the waiting harder. async def add_all_extra_labware() -> None: for labware_definition_dict in extra_labware.values(): - labware_definition = LabwareDefinition.parse_obj(labware_definition_dict) + labware_definition = LabwareDefinition.model_validate( + labware_definition_dict + ) pe.add_labware_definition(labware_definition) # Add extra_labware to ProtocolEngine, being careful not to modify ProtocolEngine from this diff --git a/api/src/opentrons/hardware_control/emulation/module_server/client.py b/api/src/opentrons/hardware_control/emulation/module_server/client.py index 4108fe76069..5adcde0f267 100644 --- a/api/src/opentrons/hardware_control/emulation/module_server/client.py +++ b/api/src/opentrons/hardware_control/emulation/module_server/client.py @@ -66,7 +66,7 @@ async def read(self) -> Message: """Read a message from the module server.""" try: b = await self._reader.readuntil(MessageDelimiter) - m: Message = Message.parse_raw(b) + m: Message = Message.model_validate_json(b) return m except LimitOverrunError as e: raise ModuleServerClientError(str(e)) diff --git a/api/src/opentrons/hardware_control/emulation/module_server/server.py b/api/src/opentrons/hardware_control/emulation/module_server/server.py index 5a3d696eb7b..36878c342e3 100644 --- a/api/src/opentrons/hardware_control/emulation/module_server/server.py +++ b/api/src/opentrons/hardware_control/emulation/module_server/server.py @@ -53,7 +53,9 @@ def on_server_connected( self._connections[identifier] = connection for c in self._clients: c.write( - Message(status="connected", connections=[connection]).json().encode() + Message(status="connected", connections=[connection]) + .model_dump_json() + .encode() ) c.write(b"\n") @@ -72,7 +74,7 @@ def on_server_disconnected(self, identifier: str) -> None: for c in self._clients: c.write( Message(status="disconnected", connections=[connection]) - .json() + .model_dump_json() .encode() ) c.write(MessageDelimiter) @@ -95,7 +97,7 @@ async def _handle_connection( # A client connected. Send a dump of all connected modules. m = Message(status="dump", connections=list(self._connections.values())) - writer.write(m.json().encode()) + writer.write(m.model_dump_json().encode()) writer.write(MessageDelimiter) self._clients.add(writer) diff --git a/api/src/opentrons/hardware_control/instruments/ot2/instrument_calibration.py b/api/src/opentrons/hardware_control/instruments/ot2/instrument_calibration.py index e093763dcd1..b3b82b22421 100644 --- a/api/src/opentrons/hardware_control/instruments/ot2/instrument_calibration.py +++ b/api/src/opentrons/hardware_control/instruments/ot2/instrument_calibration.py @@ -123,7 +123,8 @@ def load_tip_length_for_pipette( ) -> TipLengthCalibration: if isinstance(tiprack, LabwareDefinition): tiprack = typing.cast( - "TypeDictLabwareDef", tiprack.dict(exclude_none=True, exclude_unset=True) + "TypeDictLabwareDef", + tiprack.model_dump(exclude_none=True, exclude_unset=True), ) tip_length_data = calibration_storage.load_tip_length_calibration( diff --git a/api/src/opentrons/hardware_control/instruments/ot2/pipette.py b/api/src/opentrons/hardware_control/instruments/ot2/pipette.py index 2d63342cf19..0881999d435 100644 --- a/api/src/opentrons/hardware_control/instruments/ot2/pipette.py +++ b/api/src/opentrons/hardware_control/instruments/ot2/pipette.py @@ -96,7 +96,7 @@ def __init__( use_old_aspiration_functions: bool = False, ) -> None: self._config = config - self._config_as_dict = config.dict() + self._config_as_dict = config.model_dump() self._pipette_offset = pipette_offset_cal self._pipette_type = self._config.pipette_type self._pipette_version = self._config.version @@ -273,7 +273,7 @@ def update_config_item( self._config, elements, liquid_class ) # Update the cached dict representation - self._config_as_dict = self._config.dict() + self._config_as_dict = self._config.model_dump() def reload_configurations(self) -> None: self._config = load_pipette_data.load_definition( @@ -281,7 +281,7 @@ def reload_configurations(self) -> None: self._pipette_model.pipette_channels, self._pipette_model.pipette_version, ) - self._config_as_dict = self._config.dict() + self._config_as_dict = self._config.model_dump() def reset_state(self) -> None: self._current_volume = 0.0 @@ -656,8 +656,8 @@ def _reload_and_check_skip( # Same config, good enough return attached_instr, True else: - newdict = new_config.dict() - olddict = attached_instr.config.dict() + newdict = new_config.model_dump() + olddict = attached_instr.config.model_dump() changed: Set[str] = set() for k in newdict.keys(): if newdict[k] != olddict[k]: diff --git a/api/src/opentrons/hardware_control/instruments/ot3/gripper.py b/api/src/opentrons/hardware_control/instruments/ot3/gripper.py index ba49ea7d5e7..bd70547ee45 100644 --- a/api/src/opentrons/hardware_control/instruments/ot3/gripper.py +++ b/api/src/opentrons/hardware_control/instruments/ot3/gripper.py @@ -318,8 +318,8 @@ def _reload_gripper( # Same config, good enough return attached_instr, True else: - newdict = new_config.dict() - olddict = attached_instr.config.dict() + newdict = new_config.model_dump() + olddict = attached_instr.config.model_dump() changed: Set[str] = set() for k in newdict.keys(): if newdict[k] != olddict[k]: diff --git a/api/src/opentrons/hardware_control/instruments/ot3/pipette.py b/api/src/opentrons/hardware_control/instruments/ot3/pipette.py index b9355874906..6098b88b964 100644 --- a/api/src/opentrons/hardware_control/instruments/ot3/pipette.py +++ b/api/src/opentrons/hardware_control/instruments/ot3/pipette.py @@ -79,7 +79,7 @@ def __init__( use_old_aspiration_functions: bool = False, ) -> None: self._config = config - self._config_as_dict = config.dict() + self._config_as_dict = config.model_dump() self._plunger_motor_current = config.plunger_motor_configurations self._pick_up_configurations = config.pick_up_tip_configurations self._plunger_homing_configurations = config.plunger_homing_configurations @@ -251,7 +251,7 @@ def reload_configurations(self) -> None: self._pipette_model.pipette_channels, self._pipette_model.pipette_version, ) - self._config_as_dict = self._config.dict() + self._config_as_dict = self._config.model_dump() def reset_state(self) -> None: self._current_volume = 0.0 @@ -770,8 +770,8 @@ def _reload_and_check_skip( # Same config, good enough return attached_instr, True else: - newdict = new_config.dict() - olddict = attached_instr.config.dict() + newdict = new_config.model_dump() + olddict = attached_instr.config.model_dump() changed: Set[str] = set() for k in newdict.keys(): if newdict[k] != olddict[k]: diff --git a/api/src/opentrons/hardware_control/ot3_calibration.py b/api/src/opentrons/hardware_control/ot3_calibration.py index b0ebcd027ce..9303add23d6 100644 --- a/api/src/opentrons/hardware_control/ot3_calibration.py +++ b/api/src/opentrons/hardware_control/ot3_calibration.py @@ -968,7 +968,7 @@ def load_attitude_matrix(to_default: bool = True) -> DeckCalibration: return DeckCalibration( attitude=apply_machine_transform(calibration_data.attitude), source=calibration_data.source, - status=types.CalibrationStatus(**calibration_data.status.dict()), + status=types.CalibrationStatus(**calibration_data.status.model_dump()), belt_attitude=calibration_data.attitude, last_modified=calibration_data.lastModified, pipette_calibrated_with=calibration_data.pipetteCalibratedWith, diff --git a/api/src/opentrons/hardware_control/robot_calibration.py b/api/src/opentrons/hardware_control/robot_calibration.py index 270344fff2f..8ecf6b67be6 100644 --- a/api/src/opentrons/hardware_control/robot_calibration.py +++ b/api/src/opentrons/hardware_control/robot_calibration.py @@ -154,7 +154,7 @@ def load_attitude_matrix() -> DeckCalibration: return DeckCalibration( attitude=calibration_data.attitude, source=calibration_data.source, - status=types.CalibrationStatus(**calibration_data.status.dict()), + status=types.CalibrationStatus(**calibration_data.status.model_dump()), last_modified=calibration_data.last_modified, pipette_calibrated_with=calibration_data.pipette_calibrated_with, tiprack=calibration_data.tiprack, diff --git a/api/src/opentrons/protocol_api/core/engine/labware.py b/api/src/opentrons/protocol_api/core/engine/labware.py index 4d868bd30ac..d462401927f 100644 --- a/api/src/opentrons/protocol_api/core/engine/labware.py +++ b/api/src/opentrons/protocol_api/core/engine/labware.py @@ -92,12 +92,14 @@ def get_name(self) -> str: def get_definition(self) -> LabwareDefinitionDict: """Get the labware's definition as a plain dictionary.""" - return cast(LabwareDefinitionDict, self._definition.dict(exclude_none=True)) + return cast( + LabwareDefinitionDict, self._definition.model_dump(exclude_none=True) + ) def get_parameters(self) -> LabwareParametersDict: return cast( LabwareParametersDict, - self._definition.parameters.dict(exclude_none=True), + self._definition.parameters.model_dump(exclude_none=True), ) def get_quirks(self) -> List[str]: @@ -118,7 +120,7 @@ def set_calibration(self, delta: Point) -> None: details={"kind": "labware-not-in-slot"}, ) - request = LabwareOffsetCreate.construct( + request = LabwareOffsetCreate.model_construct( definitionUri=self.get_uri(), location=offset_location, vector=LabwareOffsetVector(x=delta.x, y=delta.y, z=delta.z), diff --git a/api/src/opentrons/protocol_api/core/engine/protocol.py b/api/src/opentrons/protocol_api/core/engine/protocol.py index cf0a8e1dfd7..bfc808c3091 100644 --- a/api/src/opentrons/protocol_api/core/engine/protocol.py +++ b/api/src/opentrons/protocol_api/core/engine/protocol.py @@ -193,7 +193,7 @@ def add_labware_definition( ) -> LabwareLoadParams: """Add a labware definition to the set of loadable definitions.""" uri = self._engine_client.add_labware_definition( - LabwareDefinition.parse_obj(definition) + LabwareDefinition.model_validate(definition) ) return LabwareLoadParams.from_uri(uri) diff --git a/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py b/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py index c557028c283..b06a2527cc8 100644 --- a/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py +++ b/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py @@ -124,7 +124,9 @@ async def execute( # noqa: C901 ) asbsorbance_result[wavelength] = converted_values transform_results.append( - ReadData.construct(wavelength=wavelength, data=converted_values) + ReadData.model_construct( + wavelength=wavelength, data=converted_values + ) ) # Handle the virtual module case for data creation (all zeroes) elif self._state_view.config.use_virtual_modules: @@ -138,7 +140,9 @@ async def execute( # noqa: C901 ) asbsorbance_result[wavelength] = converted_values transform_results.append( - ReadData.construct(wavelength=wavelength, data=converted_values) + ReadData.model_construct( + wavelength=wavelength, data=converted_values + ) ) else: raise CannotPerformModuleAction( @@ -153,7 +157,7 @@ async def execute( # noqa: C901 file_ids: list[str] = [] if params.fileName is not None: # Create the Plate Reader Transform - plate_read_result = PlateReaderData.construct( + plate_read_result = PlateReaderData.model_construct( read_results=transform_results, reference_wavelength=abs_reader_substate.reference_wavelength, start_time=start_time, diff --git a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_gripper.py b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_gripper.py index 2dac135c4f5..25ab19e2cd4 100644 --- a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +++ b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_gripper.py @@ -125,8 +125,8 @@ async def execute( calibration_data = result return SuccessData( - public=CalibrateGripperResult.construct( - jawOffset=Vec3f.construct( + public=CalibrateGripperResult.model_construct( + jawOffset=Vec3f.model_construct( x=probe_offset.x, y=probe_offset.y, z=probe_offset.z ), savedCalibration=calibration_data, diff --git a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_pipette.py b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_pipette.py index 70daeecb6d6..cb0eb93876c 100644 --- a/api/src/opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +++ b/api/src/opentrons/protocol_engine/commands/calibration/calibrate_pipette.py @@ -65,8 +65,8 @@ async def execute( await ot3_api.save_instrument_offset(mount=ot3_mount, delta=pipette_offset) return SuccessData( - public=CalibratePipetteResult.construct( - pipetteOffset=InstrumentOffsetVector.construct( + public=CalibratePipetteResult.model_construct( + pipetteOffset=InstrumentOffsetVector.model_construct( x=pipette_offset.x, y=pipette_offset.y, z=pipette_offset.z ) ), diff --git a/api/src/opentrons/protocol_engine/commands/configure_nozzle_layout.py b/api/src/opentrons/protocol_engine/commands/configure_nozzle_layout.py index db06491ab14..072307a0609 100644 --- a/api/src/opentrons/protocol_engine/commands/configure_nozzle_layout.py +++ b/api/src/opentrons/protocol_engine/commands/configure_nozzle_layout.py @@ -61,9 +61,11 @@ async def execute( self, params: ConfigureNozzleLayoutParams ) -> SuccessData[ConfigureNozzleLayoutResult]: """Check that requested pipette can support the requested nozzle layout.""" - primary_nozzle = params.configurationParams.dict().get("primaryNozzle") - front_right_nozzle = params.configurationParams.dict().get("frontRightNozzle") - back_left_nozzle = params.configurationParams.dict().get("backLeftNozzle") + primary_nozzle = params.configurationParams.model_dump().get("primaryNozzle") + front_right_nozzle = params.configurationParams.model_dump().get( + "frontRightNozzle" + ) + back_left_nozzle = params.configurationParams.model_dump().get("backLeftNozzle") nozzle_params = await self._tip_handler.available_for_nozzle_layout( pipette_id=params.pipetteId, style=params.configurationParams.style, diff --git a/api/src/opentrons/protocol_engine/commands/custom.py b/api/src/opentrons/protocol_engine/commands/custom.py index 3190385f2d2..b15b5cdb8d3 100644 --- a/api/src/opentrons/protocol_engine/commands/custom.py +++ b/api/src/opentrons/protocol_engine/commands/custom.py @@ -44,7 +44,7 @@ class CustomImplementation( async def execute(self, params: CustomParams) -> SuccessData[CustomResult]: """A custom command does nothing when executed directly.""" return SuccessData( - public=CustomResult.construct(), + public=CustomResult.model_construct(), ) diff --git a/api/src/opentrons/protocol_engine/commands/movement_common.py b/api/src/opentrons/protocol_engine/commands/movement_common.py index 786b59921b2..babf70b29d9 100644 --- a/api/src/opentrons/protocol_engine/commands/movement_common.py +++ b/api/src/opentrons/protocol_engine/commands/movement_common.py @@ -182,7 +182,7 @@ async def move_to_well( state_update=StateUpdate().clear_all_pipette_locations(), ) else: - deck_point = DeckPoint.construct(x=position.x, y=position.y, z=position.z) + deck_point = DeckPoint.model_construct(x=position.x, y=position.y, z=position.z) return SuccessData( public=DestinationPositionResult( position=deck_point, @@ -222,7 +222,7 @@ async def move_relative( state_update=StateUpdate().clear_all_pipette_locations(), ) else: - deck_point = DeckPoint.construct(x=position.x, y=position.y, z=position.z) + deck_point = DeckPoint.model_construct(x=position.x, y=position.y, z=position.z) return SuccessData( public=DestinationPositionResult( position=deck_point, @@ -277,7 +277,7 @@ async def move_to_addressable_area( .set_addressable_area_used(addressable_area_name=addressable_area_name), ) else: - deck_point = DeckPoint.construct(x=x, y=y, z=z) + deck_point = DeckPoint.model_construct(x=x, y=y, z=z) return SuccessData( public=DestinationPositionResult(position=deck_point), state_update=StateUpdate() @@ -324,7 +324,7 @@ async def move_to_coordinates( state_update=StateUpdate().clear_all_pipette_locations(), ) else: - deck_point = DeckPoint.construct(x=x, y=y, z=z) + deck_point = DeckPoint.model_construct(x=x, y=y, z=z) return SuccessData( public=DestinationPositionResult(position=DeckPoint(x=x, y=y, z=z)), diff --git a/api/src/opentrons/protocol_engine/commands/touch_tip.py b/api/src/opentrons/protocol_engine/commands/touch_tip.py index 4ccced4b3d3..d4591bf1d27 100644 --- a/api/src/opentrons/protocol_engine/commands/touch_tip.py +++ b/api/src/opentrons/protocol_engine/commands/touch_tip.py @@ -154,7 +154,7 @@ async def execute( waypoints=touch_waypoints, speed=touch_speed, ) - final_deck_point = DeckPoint.construct( + final_deck_point = DeckPoint.model_construct( x=final_point.x, y=final_point.y, z=final_point.z ) state_update = center_result.state_update.set_pipette_location( diff --git a/api/src/opentrons/protocol_engine/errors/error_occurrence.py b/api/src/opentrons/protocol_engine/errors/error_occurrence.py index 34f3e1d2ac7..002596d0172 100644 --- a/api/src/opentrons/protocol_engine/errors/error_occurrence.py +++ b/api/src/opentrons/protocol_engine/errors/error_occurrence.py @@ -29,7 +29,7 @@ def from_failed( wrappedErrors = [ cls.from_failed(id, createdAt, err) for err in error.wrapping ] - return cls.construct( + return cls.model_construct( id=id, createdAt=createdAt, errorType=type(error).__name__, diff --git a/api/src/opentrons/protocol_engine/execution/command_executor.py b/api/src/opentrons/protocol_engine/execution/command_executor.py index b6c686e0b11..47184d94ef2 100644 --- a/api/src/opentrons/protocol_engine/execution/command_executor.py +++ b/api/src/opentrons/protocol_engine/execution/command_executor.py @@ -188,7 +188,7 @@ async def execute(self, command_id: str) -> None: "completedAt": self._model_utils.get_timestamp(), "notes": note_tracker.get_notes(), } - succeeded_command = running_command.copy(update=update) + succeeded_command = running_command.model_copy(update=update) self._action_dispatcher.dispatch( SucceedCommandAction( command=succeeded_command, diff --git a/api/src/opentrons/protocol_engine/notes/notes.py b/api/src/opentrons/protocol_engine/notes/notes.py index 8c349d167cd..2ec71d90b55 100644 --- a/api/src/opentrons/protocol_engine/notes/notes.py +++ b/api/src/opentrons/protocol_engine/notes/notes.py @@ -35,7 +35,7 @@ def make_error_recovery_debug_note(type: "ErrorRecoveryType") -> CommandNote: This is intended to be read by developers and support people, not computers. """ message = f"Handling this command failure with {type.name}." - return CommandNote.construct( + return CommandNote.model_construct( noteKind="debugErrorRecovery", shortMessage=message, longMessage=message, diff --git a/api/src/opentrons/protocol_engine/resources/labware_data_provider.py b/api/src/opentrons/protocol_engine/resources/labware_data_provider.py index 0b08720d4e9..8d5cdfc7899 100644 --- a/api/src/opentrons/protocol_engine/resources/labware_data_provider.py +++ b/api/src/opentrons/protocol_engine/resources/labware_data_provider.py @@ -44,7 +44,7 @@ async def get_labware_definition( def _get_labware_definition_sync( load_name: str, namespace: str, version: int ) -> LabwareDefinition: - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( get_labware_definition(load_name, namespace, version) ) diff --git a/api/src/opentrons/protocol_engine/resources/module_data_provider.py b/api/src/opentrons/protocol_engine/resources/module_data_provider.py index a12b85ee5b3..3ee7b5d6bd9 100644 --- a/api/src/opentrons/protocol_engine/resources/module_data_provider.py +++ b/api/src/opentrons/protocol_engine/resources/module_data_provider.py @@ -22,7 +22,7 @@ class ModuleDataProvider: def get_definition(model: ModuleModel) -> ModuleDefinition: """Get the module definition.""" data = load_definition(model_or_loadname=model.value, version="3") - return ModuleDefinition.parse_obj(data) + return ModuleDefinition.model_validate(data) @staticmethod def load_module_calibrations() -> Dict[str, ModuleOffsetData]: diff --git a/api/src/opentrons/protocol_engine/slot_standardization.py b/api/src/opentrons/protocol_engine/slot_standardization.py index b600258bbf0..d940517eebe 100644 --- a/api/src/opentrons/protocol_engine/slot_standardization.py +++ b/api/src/opentrons/protocol_engine/slot_standardization.py @@ -35,9 +35,9 @@ def standardize_labware_offset( original: LabwareOffsetCreate, robot_type: RobotType ) -> LabwareOffsetCreate: """Convert the deck slot in the given `LabwareOffsetCreate` to match the given robot type.""" - return original.copy( + return original.model_copy( update={ - "location": original.location.copy( + "location": original.location.model_copy( update={ "slotName": original.location.slotName.to_equivalent_for_robot_type( robot_type @@ -70,40 +70,40 @@ def standardize_command( def _standardize_load_labware( original: commands.LoadLabwareCreate, robot_type: RobotType ) -> commands.LoadLabwareCreate: - params = original.params.copy( + params = original.params.model_copy( update={ "location": _standardize_labware_location( original.params.location, robot_type ) } ) - return original.copy(update={"params": params}) + return original.model_copy(update={"params": params}) def _standardize_load_module( original: commands.LoadModuleCreate, robot_type: RobotType ) -> commands.LoadModuleCreate: - params = original.params.copy( + params = original.params.model_copy( update={ "location": _standardize_deck_slot_location( original.params.location, robot_type ) } ) - return original.copy(update={"params": params}) + return original.model_copy(update={"params": params}) def _standardize_move_labware( original: commands.MoveLabwareCreate, robot_type: RobotType ) -> commands.MoveLabwareCreate: - params = original.params.copy( + params = original.params.model_copy( update={ "newLocation": _standardize_labware_location( original.params.newLocation, robot_type ) } ) - return original.copy(update={"params": params}) + return original.model_copy(update={"params": params}) _standardize_command_functions: Dict[ @@ -135,6 +135,6 @@ def _standardize_labware_location( def _standardize_deck_slot_location( original: DeckSlotLocation, robot_type: RobotType ) -> DeckSlotLocation: - return original.copy( + return original.model_copy( update={"slotName": original.slotName.to_equivalent_for_robot_type(robot_type)} ) diff --git a/api/src/opentrons/protocol_engine/state/geometry.py b/api/src/opentrons/protocol_engine/state/geometry.py index ed915530b90..e0d9cb1afa1 100644 --- a/api/src/opentrons/protocol_engine/state/geometry.py +++ b/api/src/opentrons/protocol_engine/state/geometry.py @@ -489,7 +489,7 @@ def get_well_position( well_depth=well_depth, operation_volume=operation_volume, ) - offset = offset.copy(update={"z": offset.z + offset_adjustment}) + offset = offset.model_copy(update={"z": offset.z + offset_adjustment}) self.validate_well_position( well_location=well_location, z_offset=offset.z, pipette_id=pipette_id ) diff --git a/api/src/opentrons/protocol_engine/state/labware.py b/api/src/opentrons/protocol_engine/state/labware.py index d81d5bfa756..3f00ad14de7 100644 --- a/api/src/opentrons/protocol_engine/state/labware.py +++ b/api/src/opentrons/protocol_engine/state/labware.py @@ -131,7 +131,7 @@ def __init__( for fixed_labware in deck_fixed_labware } labware_by_id = { - fixed_labware.labware_id: LoadedLabware.construct( + fixed_labware.labware_id: LoadedLabware.model_construct( id=fixed_labware.labware_id, location=fixed_labware.location, loadName=fixed_labware.definition.parameters.loadName, @@ -159,7 +159,7 @@ def handle_action(self, action: Action) -> None: self._set_labware_location(state_update) if isinstance(action, AddLabwareOffsetAction): - labware_offset = LabwareOffset.construct( + labware_offset = LabwareOffset.model_construct( id=action.labware_offset_id, createdAt=action.created_at, definitionUri=action.request.definitionUri, @@ -212,7 +212,7 @@ def _add_loaded_labware(self, state_update: update_types.StateUpdate) -> None: self._state.labware_by_id[ loaded_labware_update.labware_id - ] = LoadedLabware.construct( + ] = LoadedLabware.model_construct( id=loaded_labware_update.labware_id, location=location, loadName=loaded_labware_update.definition.parameters.loadName, @@ -998,12 +998,12 @@ def get_child_gripper_offsets( return None else: return LabwareMovementOffsetData( - pickUpOffset=LabwareOffsetVector.construct( + pickUpOffset=LabwareOffsetVector.model_construct( x=parsed_offsets[offset_key].pickUpOffset.x, y=parsed_offsets[offset_key].pickUpOffset.y, z=parsed_offsets[offset_key].pickUpOffset.z, ), - dropOffset=LabwareOffsetVector.construct( + dropOffset=LabwareOffsetVector.model_construct( x=parsed_offsets[offset_key].dropOffset.x, y=parsed_offsets[offset_key].dropOffset.y, z=parsed_offsets[offset_key].dropOffset.z, diff --git a/api/src/opentrons/protocol_engine/state/modules.py b/api/src/opentrons/protocol_engine/state/modules.py index ebf503c51fb..a0b22f14fcb 100644 --- a/api/src/opentrons/protocol_engine/state/modules.py +++ b/api/src/opentrons/protocol_engine/state/modules.py @@ -654,7 +654,7 @@ def get(self, module_id: str) -> LoadedModule: DeckSlotLocation(slotName=slot_name) if slot_name is not None else None ) - return LoadedModule.construct( + return LoadedModule.model_construct( id=module_id, location=location, model=attached_module.definition.model, diff --git a/api/src/opentrons/protocol_engine/state/state.py b/api/src/opentrons/protocol_engine/state/state.py index 58e977cc2f4..5ff12b739f3 100644 --- a/api/src/opentrons/protocol_engine/state/state.py +++ b/api/src/opentrons/protocol_engine/state/state.py @@ -143,7 +143,7 @@ def get_summary(self) -> StateSummary: """Get protocol run data.""" error = self._commands.get_error() # TODO maybe add summary here for AA - return StateSummary.construct( + return StateSummary.model_construct( status=self._commands.get_status(), errors=[] if error is None else [error], pipettes=self._pipettes.get_all(), diff --git a/api/src/opentrons/protocol_engine/types.py b/api/src/opentrons/protocol_engine/types.py index 2a4ff4bd726..b1388d58212 100644 --- a/api/src/opentrons/protocol_engine/types.py +++ b/api/src/opentrons/protocol_engine/types.py @@ -878,7 +878,7 @@ def dict_to_tuple(d: dict[str, Any]) -> tuple[tuple[str, Any], ...]: for field_name, value in d.items() ) - return hash(dict_to_tuple(self.dict())) + return hash(dict_to_tuple(self.model_dump())) class LiquidClassRecordWithId(LiquidClassRecord, frozen=True): diff --git a/api/src/opentrons/protocol_reader/extract_labware_definitions.py b/api/src/opentrons/protocol_reader/extract_labware_definitions.py index 6bf8946404b..88d7e256a07 100644 --- a/api/src/opentrons/protocol_reader/extract_labware_definitions.py +++ b/api/src/opentrons/protocol_reader/extract_labware_definitions.py @@ -55,7 +55,7 @@ def extract_sync(path: Path) -> List[LabwareDefinition]: # which require this labwareDefinitions key. unvalidated_definitions = json_contents["labwareDefinitions"].values() validated_definitions = [ - LabwareDefinition.parse_obj(u) for u in unvalidated_definitions + LabwareDefinition.model_validate(u) for u in unvalidated_definitions ] return validated_definitions diff --git a/api/src/opentrons/protocol_reader/file_format_validator.py b/api/src/opentrons/protocol_reader/file_format_validator.py index df119ac3ffa..17969fc70fe 100644 --- a/api/src/opentrons/protocol_reader/file_format_validator.py +++ b/api/src/opentrons/protocol_reader/file_format_validator.py @@ -60,7 +60,7 @@ async def validate(files: Iterable[IdentifiedFile]) -> None: async def _validate_labware_definition(info: IdentifiedLabwareDefinition) -> None: def validate_sync() -> None: try: - LabwareDefinition.parse_obj(info.unvalidated_json) + LabwareDefinition.model_validate(info.unvalidated_json) except PydanticValidationError as e: raise FileFormatValidationError( message=f"{info.original_file.name} could not be read as a labware definition.", @@ -133,17 +133,17 @@ async def _validate_json_protocol(info: IdentifiedJsonMain) -> None: def validate_sync() -> None: if info.schema_version == 8: try: - JsonProtocolV8.parse_obj(info.unvalidated_json) + JsonProtocolV8.model_validate(info.unvalidated_json) except PydanticValidationError as pve: _handle_v8_json_protocol_validation_error(info, pve) else: try: if info.schema_version == 7: - JsonProtocolV7.parse_obj(info.unvalidated_json) + JsonProtocolV7.model_validate(info.unvalidated_json) elif info.schema_version == 6: - JsonProtocolV6.parse_obj(info.unvalidated_json) + JsonProtocolV6.model_validate(info.unvalidated_json) else: - JsonProtocolUpToV5.parse_obj(info.unvalidated_json) + JsonProtocolUpToV5.model_validate(info.unvalidated_json) except PydanticValidationError as e: raise FileFormatValidationError._generic_json_failure(info, e) from e diff --git a/api/src/opentrons/protocol_runner/json_translator.py b/api/src/opentrons/protocol_runner/json_translator.py index f75b0d51348..f20bb3464d8 100644 --- a/api/src/opentrons/protocol_runner/json_translator.py +++ b/api/src/opentrons/protocol_runner/json_translator.py @@ -63,7 +63,7 @@ def _translate_labware_command( namespace=protocol.labwareDefinitions[definition_id].namespace, loadName=protocol.labwareDefinitions[definition_id].parameters.loadName, location=LabwareLocationAdapter.validate_python( - location.dict() if isinstance(location, Location) else location + location.model_dump() if isinstance(location, Location) else location ), ), key=command.key, @@ -91,7 +91,7 @@ def _translate_v7_labware_command( namespace=command.params.namespace, loadName=command.params.loadName, location=LabwareLocationAdapter.validate_python( - location.dict() if isinstance(location, Location) else location + location.model_dump() if isinstance(location, Location) else location ), ), key=command.key, @@ -114,8 +114,8 @@ def _translate_module_command( translated_obj = pe_commands.LoadModuleCreate( params=pe_commands.LoadModuleParams( model=ModuleModel(modules[module_id].model), - location=DeckSlotLocation.parse_obj( - location.dict() if isinstance(location, Location) else location + location=DeckSlotLocation.model_validate( + location.model_dump() if isinstance(location, Location) else location ), moduleId=command.params.moduleId, ), @@ -136,8 +136,8 @@ def _translate_v7_module_command( translated_obj = pe_commands.LoadModuleCreate( params=pe_commands.LoadModuleParams( model=ModuleModel(command.params.model), - location=DeckSlotLocation.parse_obj( - location.dict() if isinstance(location, Location) else location + location=DeckSlotLocation.model_validate( + location.model_dump() if isinstance(location, Location) else location ), moduleId=command.params.moduleId, ), @@ -191,7 +191,7 @@ def _translate_simple_command( protocol_schema_v8.Command, ], ) -> pe_commands.CommandCreate: - dict_command = command.dict(exclude_none=True) + dict_command = command.model_dump(exclude_none=True) # map deprecated `delay` commands to `waitForResume` / `waitForDuration` if dict_command["commandType"] == "delay": @@ -305,7 +305,7 @@ def translate_command_annotations( else: command_annotations: List[CommandAnnotation] = [ CommandAnnotationAdapter.validate_python( - command_annotation.dict(), + command_annotation.model_dump(), ) for command_annotation in protocol.commandAnnotations ] diff --git a/api/src/opentrons/protocol_runner/legacy_command_mapper.py b/api/src/opentrons/protocol_runner/legacy_command_mapper.py index 1dbf99e6e6e..f7d50e539d8 100644 --- a/api/src/opentrons/protocol_runner/legacy_command_mapper.py +++ b/api/src/opentrons/protocol_runner/legacy_command_mapper.py @@ -177,9 +177,9 @@ def map_command( # noqa: C901 completed_command: pe_commands.Command if command_error is None: if isinstance(running_command, pe_commands.PickUpTip): - completed_command = running_command.copy( + completed_command = running_command.model_copy( update={ - "result": pe_commands.PickUpTipResult.construct( + "result": pe_commands.PickUpTipResult.model_construct( tipVolume=command["payload"]["location"].max_volume, # type: ignore[typeddict-item] tipLength=command["payload"]["instrument"].hw_pipette[ # type: ignore[typeddict-item] "tip_length" @@ -192,9 +192,9 @@ def map_command( # noqa: C901 } ) elif isinstance(running_command, pe_commands.DropTip): - completed_command = running_command.copy( + completed_command = running_command.model_copy( update={ - "result": pe_commands.DropTipResult.construct( + "result": pe_commands.DropTipResult.model_construct( position=pe_types.DeckPoint(x=0, y=0, z=0) ), "status": pe_commands.CommandStatus.SUCCEEDED, @@ -203,9 +203,9 @@ def map_command( # noqa: C901 } ) elif isinstance(running_command, pe_commands.Aspirate): - completed_command = running_command.copy( + completed_command = running_command.model_copy( update={ - # Don't .construct() result, because we want to validate + # Don't .model_construct() result, because we want to validate # volume. "result": pe_commands.AspirateResult( volume=running_command.params.volume, @@ -217,9 +217,9 @@ def map_command( # noqa: C901 } ) elif isinstance(running_command, pe_commands.Dispense): - completed_command = running_command.copy( + completed_command = running_command.model_copy( update={ - # Don't .construct() result, because we want to validate + # Don't .model_construct() result, because we want to validate # volume. "result": pe_commands.DispenseResult( volume=running_command.params.volume, @@ -231,9 +231,9 @@ def map_command( # noqa: C901 } ) elif isinstance(running_command, pe_commands.BlowOut): - completed_command = running_command.copy( + completed_command = running_command.model_copy( update={ - "result": pe_commands.BlowOutResult.construct( + "result": pe_commands.BlowOutResult.model_construct( position=pe_types.DeckPoint(x=0, y=0, z=0) ), "status": pe_commands.CommandStatus.SUCCEEDED, @@ -242,18 +242,18 @@ def map_command( # noqa: C901 } ) elif isinstance(running_command, pe_commands.Comment): - completed_command = running_command.copy( + completed_command = running_command.model_copy( update={ - "result": pe_commands.CommentResult.construct(), + "result": pe_commands.CommentResult.model_construct(), "status": pe_commands.CommandStatus.SUCCEEDED, "completedAt": now, "notes": [], } ) elif isinstance(running_command, pe_commands.Custom): - completed_command = running_command.copy( + completed_command = running_command.model_copy( update={ - "result": pe_commands.CustomResult.construct(), + "result": pe_commands.CustomResult.model_construct(), "status": pe_commands.CommandStatus.SUCCEEDED, "completedAt": now, "notes": [], @@ -263,7 +263,7 @@ def map_command( # noqa: C901 # TODO(mm, 2024-06-13): This looks potentially wrong. # We're creating a `SUCCEEDED` command that does not have a `result`, # which is not normally possible. - completed_command = running_command.copy( + completed_command = running_command.model_copy( update={ "status": pe_commands.CommandStatus.SUCCEEDED, "completedAt": now, @@ -333,51 +333,51 @@ def _build_initial_command( elif command["name"] == legacy_command_types.BLOW_OUT: return self._build_blow_out(command=command, command_id=command_id, now=now) elif command["name"] == legacy_command_types.PAUSE: - wait_for_resume_running = pe_commands.WaitForResume.construct( + wait_for_resume_running = pe_commands.WaitForResume.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - params=pe_commands.WaitForResumeParams.construct( + params=pe_commands.WaitForResumeParams.model_construct( message=command["payload"]["userMessage"], ), ) wait_for_resume_create: pe_commands.CommandCreate = ( - pe_commands.WaitForResumeCreate.construct( + pe_commands.WaitForResumeCreate.model_construct( key=wait_for_resume_running.key, params=wait_for_resume_running.params, ) ) return wait_for_resume_create, wait_for_resume_running elif command["name"] == legacy_command_types.COMMENT: - comment_running = pe_commands.Comment.construct( + comment_running = pe_commands.Comment.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - params=pe_commands.CommentParams.construct( + params=pe_commands.CommentParams.model_construct( message=command["payload"]["text"], ), ) - comment_create = pe_commands.CommentCreate.construct( + comment_create = pe_commands.CommentCreate.model_construct( key=comment_running.key, params=comment_running.params ) return comment_create, comment_running else: - custom_running = pe_commands.Custom.construct( + custom_running = pe_commands.Custom.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - params=LegacyCommandParams.construct( + params=LegacyCommandParams.model_construct( legacyCommandType=command["name"], legacyCommandText=command["payload"]["text"], ), ) - custom_create = pe_commands.CustomCreate.construct( + custom_create = pe_commands.CustomCreate.model_construct( key=custom_running.key, params=custom_running.params, ) @@ -398,19 +398,19 @@ def _build_drop_tip( labware_id = self._labware_id_by_slot[slot] pipette_id = self._pipette_id_by_mount[mount] - running = pe_commands.DropTip.construct( + running = pe_commands.DropTip.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - params=pe_commands.DropTipParams.construct( + params=pe_commands.DropTipParams.model_construct( pipetteId=pipette_id, labwareId=labware_id, wellName=well_name, ), ) - create = pe_commands.DropTipCreate.construct( + create = pe_commands.DropTipCreate.model_construct( key=running.key, params=running.params, ) @@ -432,19 +432,19 @@ def _build_pick_up_tip( labware_id = self._labware_id_by_slot[slot] pipette_id = self._pipette_id_by_mount[mount] - running = pe_commands.PickUpTip.construct( + running = pe_commands.PickUpTip.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - params=pe_commands.PickUpTipParams.construct( + params=pe_commands.PickUpTipParams.model_construct( pipetteId=pipette_id, labwareId=labware_id, wellName=well_name, ), ) - create = pe_commands.PickUpTipCreate.construct( + create = pe_commands.PickUpTipCreate.model_construct( key=running.key, params=running.params ) return create, running @@ -484,31 +484,31 @@ def _build_liquid_handling( # TODO(mm, 2024-03-22): I don't think this has been true since # https://github.com/Opentrons/opentrons/pull/14211. Can we just use # aspirate and dispense commands now? - move_to_well_running = pe_commands.MoveToWell.construct( + move_to_well_running = pe_commands.MoveToWell.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - params=pe_commands.MoveToWellParams.construct( + params=pe_commands.MoveToWellParams.model_construct( pipetteId=pipette_id, labwareId=labware_id, wellName=well_name, ), ) - move_to_well_create = pe_commands.MoveToWellCreate.construct( + move_to_well_create = pe_commands.MoveToWellCreate.model_construct( key=move_to_well_running.key, params=move_to_well_running.params ) return move_to_well_create, move_to_well_running elif command["name"] == legacy_command_types.ASPIRATE: flow_rate = command["payload"]["rate"] * pipette.flow_rate.aspirate - aspirate_running = pe_commands.Aspirate.construct( + aspirate_running = pe_commands.Aspirate.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - # Don't .construct() params, because we want to validate + # Don't .model_construct() params, because we want to validate # volume and flowRate. params=pe_commands.AspirateParams( pipetteId=pipette_id, @@ -518,13 +518,13 @@ def _build_liquid_handling( flowRate=flow_rate, ), ) - aspirate_create = pe_commands.AspirateCreate.construct( + aspirate_create = pe_commands.AspirateCreate.model_construct( key=aspirate_running.key, params=aspirate_running.params ) return aspirate_create, aspirate_running else: flow_rate = command["payload"]["rate"] * pipette.flow_rate.dispense - dispense_running = pe_commands.Dispense.construct( + dispense_running = pe_commands.Dispense.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, @@ -540,24 +540,24 @@ def _build_liquid_handling( flowRate=flow_rate, ), ) - dispense_create = pe_commands.DispenseCreate.construct( + dispense_create = pe_commands.DispenseCreate.model_construct( key=dispense_running.key, params=dispense_running.params ) return dispense_create, dispense_running else: - running = pe_commands.Custom.construct( + running = pe_commands.Custom.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - params=LegacyCommandParams.construct( + params=LegacyCommandParams.model_construct( legacyCommandType=command["name"], legacyCommandText=command["payload"]["text"], ), ) - create = pe_commands.CustomCreate.construct( + create = pe_commands.CustomCreate.model_construct( key=running.key, params=running.params ) return create, running @@ -586,13 +586,13 @@ def _build_blow_out( well_name = well.well_name pipette_id = self._pipette_id_by_mount[mount] - blow_out_running = pe_commands.BlowOut.construct( + blow_out_running = pe_commands.BlowOut.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - # Don't .construct() params, because we want to validate flowRate. + # Don't .model_construct() params, because we want to validate flowRate. params=pe_commands.BlowOutParams( pipetteId=pipette_id, labwareId=labware_id, @@ -600,7 +600,7 @@ def _build_blow_out( flowRate=flow_rate, ), ) - blow_out_create = pe_commands.BlowOutCreate.construct( + blow_out_create = pe_commands.BlowOutCreate.model_construct( key=blow_out_running.key, params=blow_out_running.params ) return blow_out_create, blow_out_running @@ -608,18 +608,18 @@ def _build_blow_out( # TODO:(jr, 15.08.2022): blow_out commands with no specified labware get filtered # into custom. Refactor this in followup legacy command mapping else: - custom_running = pe_commands.Custom.construct( + custom_running = pe_commands.Custom.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.RUNNING, createdAt=now, startedAt=now, - params=LegacyCommandParams.construct( + params=LegacyCommandParams.model_construct( legacyCommandType=command["name"], legacyCommandText=command["payload"]["text"], ), ) - custom_create = pe_commands.CustomCreate.construct( + custom_create = pe_commands.CustomCreate.model_construct( key=custom_running.key, params=custom_running.params ) return custom_create, custom_running @@ -633,23 +633,23 @@ def _map_labware_load( slot = labware_load_info.deck_slot location: pe_types.LabwareLocation if labware_load_info.on_module: - location = pe_types.ModuleLocation.construct( + location = pe_types.ModuleLocation.model_construct( moduleId=self._module_id_by_slot[slot] ) else: - location = pe_types.DeckSlotLocation.construct(slotName=slot) + location = pe_types.DeckSlotLocation.model_construct(slotName=slot) command_id = f"commands.LOAD_LABWARE-{count}" labware_id = f"labware-{count}" - succeeded_command = pe_commands.LoadLabware.construct( + succeeded_command = pe_commands.LoadLabware.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.SUCCEEDED, createdAt=now, startedAt=now, completedAt=now, - params=pe_commands.LoadLabwareParams.construct( + params=pe_commands.LoadLabwareParams.model_construct( location=location, loadName=labware_load_info.labware_load_name, namespace=labware_load_info.labware_namespace, @@ -657,9 +657,9 @@ def _map_labware_load( displayName=labware_load_info.labware_display_name, ), notes=[], - result=pe_commands.LoadLabwareResult.construct( + result=pe_commands.LoadLabwareResult.model_construct( labwareId=labware_id, - definition=LabwareDefinition.parse_obj( + definition=LabwareDefinition.model_validate( labware_load_info.labware_definition ), offsetId=labware_load_info.offset_id, @@ -668,7 +668,7 @@ def _map_labware_load( queue_action = pe_actions.QueueCommandAction( command_id=succeeded_command.id, created_at=succeeded_command.createdAt, - request=pe_commands.LoadLabwareCreate.construct( + request=pe_commands.LoadLabwareCreate.model_construct( key=succeeded_command.key, params=succeeded_command.params ), request_hash=None, @@ -716,19 +716,19 @@ def _map_instrument_load( pipette_id = f"pipette-{count}" mount = MountType(str(instrument_load_info.mount).lower()) - succeeded_command = pe_commands.LoadPipette.construct( + succeeded_command = pe_commands.LoadPipette.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.SUCCEEDED, createdAt=now, startedAt=now, completedAt=now, - params=pe_commands.LoadPipetteParams.construct( + params=pe_commands.LoadPipetteParams.model_construct( pipetteName=PipetteNameType(instrument_load_info.instrument_load_name), mount=mount, ), notes=[], - result=pe_commands.LoadPipetteResult.construct(pipetteId=pipette_id), + result=pe_commands.LoadPipetteResult.model_construct(pipetteId=pipette_id), ) serial = instrument_load_info.pipette_dict.get("pipette_id", None) or "" state_update = StateUpdate() @@ -751,7 +751,7 @@ def _map_instrument_load( queue_action = pe_actions.QueueCommandAction( command_id=succeeded_command.id, created_at=succeeded_command.createdAt, - request=pe_commands.LoadPipetteCreate.construct( + request=pe_commands.LoadPipetteCreate.model_construct( key=succeeded_command.key, params=succeeded_command.params ), request_hash=None, @@ -793,14 +793,14 @@ def _map_module_load( loaded_model ) or self._module_data_provider.get_definition(loaded_model) - succeeded_command = pe_commands.LoadModule.construct( + succeeded_command = pe_commands.LoadModule.model_construct( id=command_id, key=command_id, status=pe_commands.CommandStatus.SUCCEEDED, createdAt=now, startedAt=now, completedAt=now, - params=pe_commands.LoadModuleParams.construct( + params=pe_commands.LoadModuleParams.model_construct( model=requested_model, location=pe_types.DeckSlotLocation( slotName=module_load_info.deck_slot, @@ -808,7 +808,7 @@ def _map_module_load( moduleId=module_id, ), notes=[], - result=pe_commands.LoadModuleResult.construct( + result=pe_commands.LoadModuleResult.model_construct( moduleId=module_id, serialNumber=module_load_info.module_serial, definition=loaded_definition, @@ -818,7 +818,7 @@ def _map_module_load( queue_action = pe_actions.QueueCommandAction( command_id=succeeded_command.id, created_at=succeeded_command.createdAt, - request=pe_commands.LoadModuleCreate.construct( + request=pe_commands.LoadModuleCreate.model_construct( key=succeeded_command.key, params=succeeded_command.params ), request_hash=None, diff --git a/api/src/opentrons/protocol_runner/python_protocol_wrappers.py b/api/src/opentrons/protocol_runner/python_protocol_wrappers.py index f20012f1dfe..ce063013878 100644 --- a/api/src/opentrons/protocol_runner/python_protocol_wrappers.py +++ b/api/src/opentrons/protocol_runner/python_protocol_wrappers.py @@ -66,7 +66,7 @@ def read( namespace=lw.namespace, load_name=lw.parameters.loadName, version=lw.version, - ): cast(LabwareDefinitionTypedDict, lw.dict(exclude_none=True)) + ): cast(LabwareDefinitionTypedDict, lw.model_dump(exclude_none=True)) for lw in labware_definitions } data_file_paths = [ diff --git a/api/src/opentrons/simulate.py b/api/src/opentrons/simulate.py index e565bab83e0..bed24c68731 100644 --- a/api/src/opentrons/simulate.py +++ b/api/src/opentrons/simulate.py @@ -829,7 +829,9 @@ def _create_live_context_pe( # Non-async would use call_soon_threadsafe(), which makes the waiting harder. async def add_all_extra_labware() -> None: for labware_definition_dict in extra_labware.values(): - labware_definition = LabwareDefinition.parse_obj(labware_definition_dict) + labware_definition = LabwareDefinition.model_validate( + labware_definition_dict + ) pe.add_labware_definition(labware_definition) # Add extra_labware to ProtocolEngine, being careful not to modify ProtocolEngine from this diff --git a/api/tests/opentrons/calibration_storage/test_file_operators.py b/api/tests/opentrons/calibration_storage/test_file_operators.py index 5a95f225fe3..ec25a2279c1 100644 --- a/api/tests/opentrons/calibration_storage/test_file_operators.py +++ b/api/tests/opentrons/calibration_storage/test_file_operators.py @@ -84,7 +84,7 @@ def test_deserialize_pydantic_model_valid() -> None: serialized = b'{"integer_field": 123, "! aliased field !": "abc"}' assert io.deserialize_pydantic_model( serialized, DummyModel - ) == DummyModel.construct(integer_field=123, aliased_field="abc") + ) == DummyModel.model_construct(integer_field=123, aliased_field="abc") def test_deserialize_pydantic_model_invalid_as_json() -> None: diff --git a/api/tests/opentrons/calibration_storage/test_tip_length_ot2.py b/api/tests/opentrons/calibration_storage/test_tip_length_ot2.py index df503241d75..51096866b5d 100644 --- a/api/tests/opentrons/calibration_storage/test_tip_length_ot2.py +++ b/api/tests/opentrons/calibration_storage/test_tip_length_ot2.py @@ -46,7 +46,7 @@ def starting_calibration_data( "tipLength": 27, "lastModified": inside_data.lastModified.isoformat(), "source": inside_data.source, - "status": inside_data.status.dict(), + "status": inside_data.status.model_dump(), "uri": "dummy_namespace/minimal_labware_def/1", } } diff --git a/api/tests/opentrons/hardware_control/test_gripper.py b/api/tests/opentrons/hardware_control/test_gripper.py index 7fc54791e33..fdce4f27d3d 100644 --- a/api/tests/opentrons/hardware_control/test_gripper.py +++ b/api/tests/opentrons/hardware_control/test_gripper.py @@ -104,9 +104,9 @@ def test_reload_instrument_cal_ot3_conf_changed( "fakeid123", jaw_max_offset=15, ) - new_conf = fake_gripper_conf.copy( + new_conf = fake_gripper_conf.model_copy( update={ - "grip_force_profile": fake_gripper_conf.grip_force_profile.copy( + "grip_force_profile": fake_gripper_conf.grip_force_profile.model_copy( update={"default_grip_force": 1} ) }, diff --git a/api/tests/opentrons/protocol_engine/commands/test_air_gap_in_place.py b/api/tests/opentrons/protocol_engine/commands/test_air_gap_in_place.py index 5d66a845dcc..b9d110fd9c2 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_air_gap_in_place.py +++ b/api/tests/opentrons/protocol_engine/commands/test_air_gap_in_place.py @@ -265,7 +265,7 @@ async def test_overpressure_error( if isinstance(location, CurrentWell): assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], @@ -275,7 +275,7 @@ async def test_overpressure_error( ) else: assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/commands/test_aspirate.py b/api/tests/opentrons/protocol_engine/commands/test_aspirate.py index 8e50d1825ae..4a8adbcdc76 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_aspirate.py +++ b/api/tests/opentrons/protocol_engine/commands/test_aspirate.py @@ -411,7 +411,7 @@ async def test_overpressure_error( result = await subject.execute(params) assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], @@ -581,7 +581,7 @@ async def test_stall_during_final_movement( result = await subject.execute(params) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], @@ -639,7 +639,7 @@ async def test_stall_during_preparation( result = await subject.execute(params) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()] ), state_update=update_types.StateUpdate( @@ -715,7 +715,7 @@ async def test_overpressure_during_preparation( result = await subject.execute(params) assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/commands/test_aspirate_in_place.py b/api/tests/opentrons/protocol_engine/commands/test_aspirate_in_place.py index 48dba2e0c3e..5a7ca3ee940 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_aspirate_in_place.py +++ b/api/tests/opentrons/protocol_engine/commands/test_aspirate_in_place.py @@ -304,7 +304,7 @@ async def test_overpressure_error( if isinstance(location, CurrentWell): assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], @@ -323,7 +323,7 @@ async def test_overpressure_error( ) else: assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/commands/test_blow_out.py b/api/tests/opentrons/protocol_engine/commands/test_blow_out.py index c06b62ace97..7549141be5b 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_blow_out.py +++ b/api/tests/opentrons/protocol_engine/commands/test_blow_out.py @@ -158,7 +158,7 @@ async def test_overpressure_error( result = await subject.execute(data) assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], @@ -233,7 +233,7 @@ async def test_stall_error( result = await subject.execute(data) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/commands/test_blow_out_in_place.py b/api/tests/opentrons/protocol_engine/commands/test_blow_out_in_place.py index 97e8e8c0851..50bee696c5a 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_blow_out_in_place.py +++ b/api/tests/opentrons/protocol_engine/commands/test_blow_out_in_place.py @@ -106,7 +106,7 @@ async def test_overpressure_error( result = await subject.execute(data) assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/commands/test_dispense.py b/api/tests/opentrons/protocol_engine/commands/test_dispense.py index e0e18307b69..5b60b61d4df 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_dispense.py +++ b/api/tests/opentrons/protocol_engine/commands/test_dispense.py @@ -119,7 +119,7 @@ async def test_dispense_implementation( labware_id="labware-id-abc123", well_name="A3", ), - new_deck_point=DeckPoint.construct(x=1, y=2, z=3), + new_deck_point=DeckPoint.model_construct(x=1, y=2, z=3), ), liquid_operated=update_types.LiquidOperatedUpdate( labware_id="labware-id-abc123", @@ -203,7 +203,7 @@ async def test_overpressure_error( result = await subject.execute(data) assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], @@ -216,7 +216,7 @@ async def test_overpressure_error( labware_id="labware-id", well_name="well-name", ), - new_deck_point=DeckPoint.construct(x=1, y=2, z=3), + new_deck_point=DeckPoint.model_construct(x=1, y=2, z=3), ), liquid_operated=update_types.LiquidOperatedUpdate( labware_id="labware-id", @@ -234,7 +234,7 @@ async def test_overpressure_error( labware_id="labware-id", well_name="well-name", ), - new_deck_point=DeckPoint.construct(x=1, y=2, z=3), + new_deck_point=DeckPoint.model_construct(x=1, y=2, z=3), ), ), ) @@ -288,7 +288,7 @@ async def test_stall_error( result = await subject.execute(data) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/commands/test_dispense_in_place.py b/api/tests/opentrons/protocol_engine/commands/test_dispense_in_place.py index bc39fba4a00..e9c715223de 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_dispense_in_place.py +++ b/api/tests/opentrons/protocol_engine/commands/test_dispense_in_place.py @@ -207,7 +207,7 @@ async def test_overpressure_error( if isinstance(location, CurrentWell): assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], @@ -226,7 +226,7 @@ async def test_overpressure_error( ) else: assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/commands/test_drop_tip.py b/api/tests/opentrons/protocol_engine/commands/test_drop_tip.py index 038ea12255b..430fa8dff32 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_drop_tip.py +++ b/api/tests/opentrons/protocol_engine/commands/test_drop_tip.py @@ -60,7 +60,7 @@ def mock_model_utils(decoy: Decoy) -> ModelUtils: def test_drop_tip_params_defaults() -> None: """A drop tip should use a `WellOrigin.DROP_TIP` by default.""" - default_params = DropTipParams.parse_obj( + default_params = DropTipParams.model_validate( {"pipetteId": "abc", "labwareId": "def", "wellName": "ghj"} ) @@ -71,7 +71,7 @@ def test_drop_tip_params_defaults() -> None: def test_drop_tip_params_default_origin() -> None: """A drop tip should drop a `WellOrigin.DROP_TIP` by default even if an offset is given.""" - default_params = DropTipParams.parse_obj( + default_params = DropTipParams.model_validate( { "pipetteId": "abc", "labwareId": "def", @@ -303,7 +303,7 @@ async def test_tip_attached_error( result = await subject.execute(params) assert result == DefinedErrorData( - public=TipPhysicallyAttachedError.construct( + public=TipPhysicallyAttachedError.model_construct( id="error-id", createdAt=datetime(year=1, month=2, day=3), wrappedErrors=[matchers.Anything()], @@ -396,7 +396,7 @@ async def test_stall_error( result = await subject.execute(params) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id="error-id", createdAt=datetime(year=1, month=2, day=3), wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/commands/test_drop_tip_in_place.py b/api/tests/opentrons/protocol_engine/commands/test_drop_tip_in_place.py index 5565ffea88c..8c4716cf380 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_drop_tip_in_place.py +++ b/api/tests/opentrons/protocol_engine/commands/test_drop_tip_in_place.py @@ -104,7 +104,7 @@ async def test_tip_attached_error( result = await subject.execute(params) assert result == DefinedErrorData( - public=TipPhysicallyAttachedError.construct( + public=TipPhysicallyAttachedError.model_construct( id="error-id", createdAt=datetime(year=1, month=2, day=3), wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/commands/test_liquid_probe.py b/api/tests/opentrons/protocol_engine/commands/test_liquid_probe.py index 34b979901aa..c9661512aaa 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_liquid_probe.py +++ b/api/tests/opentrons/protocol_engine/commands/test_liquid_probe.py @@ -350,7 +350,7 @@ async def test_liquid_not_found_error( ) if isinstance(subject, LiquidProbeImplementation): assert result == DefinedErrorData( - public=LiquidNotFoundError.construct( + public=LiquidNotFoundError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], @@ -726,7 +726,7 @@ async def test_liquid_probe_stall( result = await subject.execute(data) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=error_id, createdAt=timestamp, wrappedErrors=[matchers.Anything()] ), state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), diff --git a/api/tests/opentrons/protocol_engine/commands/test_load_liquid_class.py b/api/tests/opentrons/protocol_engine/commands/test_load_liquid_class.py index 041a7b2f8ca..54de10f3bc2 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_load_liquid_class.py +++ b/api/tests/opentrons/protocol_engine/commands/test_load_liquid_class.py @@ -152,7 +152,7 @@ async def test_load_liquid_class_conflicting_definition_for_id( liquid_class_record ) - new_liquid_class_record = liquid_class_record.copy(deep=True) + new_liquid_class_record = liquid_class_record.model_copy(deep=True) new_liquid_class_record.aspirate.offset.x += 123 # make it different params = LoadLiquidClassParams( liquidClassId="liquid-class-1", liquidClassRecord=new_liquid_class_record diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_relative.py b/api/tests/opentrons/protocol_engine/commands/test_move_relative.py index 1e2d98ebf21..7a993c16d35 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_relative.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_relative.py @@ -85,7 +85,7 @@ async def test_move_relative_stalls( result = await subject.execute(data) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=test_id, createdAt=timestamp, wrappedErrors=[matchers.Anything()] ), state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area.py b/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area.py index 9142f792252..0570d91c8bc 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area.py @@ -209,7 +209,7 @@ async def test_move_to_addressable_area_implementation_handles_stalls( result = await subject.execute(data) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=test_id, createdAt=timestamp, wrappedErrors=[matchers.Anything()] ), state_update=update_types.StateUpdate( diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area_for_drop_tip.py b/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area_for_drop_tip.py index b6ee2097458..e90bb7271f7 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area_for_drop_tip.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area_for_drop_tip.py @@ -133,7 +133,7 @@ async def test_move_to_addressable_area_for_drop_tip_handles_stalls( result = await subject.execute(data) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=test_id, createdAt=timestamp, wrappedErrors=[matchers.Anything()] ), state_update=update_types.StateUpdate( diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_to_coordinates.py b/api/tests/opentrons/protocol_engine/commands/test_move_to_coordinates.py index 85afb189988..3c9fc10bb1c 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_to_coordinates.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_to_coordinates.py @@ -97,7 +97,7 @@ async def test_move_to_coordinates_stall( result = await subject.execute(params=params) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=test_id, createdAt=timestamp, wrappedErrors=[matchers.Anything()] ), state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_to_well.py b/api/tests/opentrons/protocol_engine/commands/test_move_to_well.py index db91abd5a41..56a2691bbee 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_to_well.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_to_well.py @@ -158,7 +158,7 @@ async def test_move_to_well_stall_defined_error( result = await subject.execute(data) assert isinstance(result, DefinedErrorData) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()] ), state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), diff --git a/api/tests/opentrons/protocol_engine/commands/test_pick_up_tip.py b/api/tests/opentrons/protocol_engine/commands/test_pick_up_tip.py index 07170e08288..d4c53ea5992 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_pick_up_tip.py +++ b/api/tests/opentrons/protocol_engine/commands/test_pick_up_tip.py @@ -167,7 +167,7 @@ async def test_tip_physically_missing_error( ) assert result == DefinedErrorData( - public=TipPhysicallyMissingError.construct( + public=TipPhysicallyMissingError.model_construct( id=error_id, createdAt=error_created_at, wrappedErrors=[matchers.Anything()] ), state_update=update_types.StateUpdate( @@ -255,7 +255,7 @@ async def test_stall_error( ) assert result == DefinedErrorData( - public=StallOrCollisionError.construct( + public=StallOrCollisionError.model_construct( id=error_id, createdAt=error_created_at, wrappedErrors=[matchers.Anything()] ), state_update=update_types.StateUpdate( diff --git a/api/tests/opentrons/protocol_engine/commands/test_prepare_to_aspirate.py b/api/tests/opentrons/protocol_engine/commands/test_prepare_to_aspirate.py index f9eded1ffa0..5e77529f646 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_prepare_to_aspirate.py +++ b/api/tests/opentrons/protocol_engine/commands/test_prepare_to_aspirate.py @@ -91,7 +91,7 @@ async def test_overpressure_error( result = await subject.execute(data) assert result == DefinedErrorData( - public=OverpressureError.construct( + public=OverpressureError.model_construct( id=error_id, createdAt=error_timestamp, wrappedErrors=[matchers.Anything()], diff --git a/api/tests/opentrons/protocol_engine/conftest.py b/api/tests/opentrons/protocol_engine/conftest.py index 88a166524ba..48ce28e7a98 100644 --- a/api/tests/opentrons/protocol_engine/conftest.py +++ b/api/tests/opentrons/protocol_engine/conftest.py @@ -78,7 +78,7 @@ def ot3_standard_deck_def() -> DeckDefinitionV5: @pytest.fixture(scope="session") def ot2_fixed_trash_def() -> LabwareDefinition: """Get the definition of the OT-2 standard fixed trash.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( load_definition("opentrons_1_trash_1100ml_fixed", 1) ) @@ -86,7 +86,7 @@ def ot2_fixed_trash_def() -> LabwareDefinition: @pytest.fixture(scope="session") def ot2_short_fixed_trash_def() -> LabwareDefinition: """Get the definition of the OT-2 short fixed trash.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( load_definition("opentrons_1_trash_850ml_fixed", 1) ) @@ -94,7 +94,7 @@ def ot2_short_fixed_trash_def() -> LabwareDefinition: @pytest.fixture(scope="session") def ot3_fixed_trash_def() -> LabwareDefinition: """Get the definition of the OT-3 fixed trash.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( load_definition("opentrons_1_trash_3200ml_fixed", 1) ) @@ -102,7 +102,7 @@ def ot3_fixed_trash_def() -> LabwareDefinition: @pytest.fixture(scope="session") def ot3_absorbance_reader_lid() -> LabwareDefinition: """Get the definition of the OT-3 plate reader lid.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( load_definition("opentrons_flex_lid_absorbance_plate_reader_module", 1) ) @@ -110,7 +110,7 @@ def ot3_absorbance_reader_lid() -> LabwareDefinition: @pytest.fixture(scope="session") def well_plate_def() -> LabwareDefinition: """Get the definition of a 96 well plate.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( load_definition("corning_96_wellplate_360ul_flat", 2) ) @@ -118,7 +118,7 @@ def well_plate_def() -> LabwareDefinition: @pytest.fixture(scope="session") def flex_50uL_tiprack() -> LabwareDefinition: """Get the definition of a Flex 50uL tiprack.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( load_definition("opentrons_flex_96_filtertiprack_50ul", 1) ) @@ -126,7 +126,7 @@ def flex_50uL_tiprack() -> LabwareDefinition: @pytest.fixture(scope="session") def adapter_plate_def() -> LabwareDefinition: """Get the definition of a h/s adapter plate.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( load_definition("opentrons_universal_flat_adapter", 1) ) @@ -134,25 +134,31 @@ def adapter_plate_def() -> LabwareDefinition: @pytest.fixture(scope="session") def reservoir_def() -> LabwareDefinition: """Get the definition of single-row reservoir.""" - return LabwareDefinition.parse_obj(load_definition("nest_12_reservoir_15ml", 1)) + return LabwareDefinition.model_validate( + load_definition("nest_12_reservoir_15ml", 1) + ) @pytest.fixture(scope="session") def tip_rack_def() -> LabwareDefinition: """Get the definition of Opentrons 300 uL tip rack.""" - return LabwareDefinition.parse_obj(load_definition("opentrons_96_tiprack_300ul", 1)) + return LabwareDefinition.model_validate( + load_definition("opentrons_96_tiprack_300ul", 1) + ) @pytest.fixture(scope="session") def adapter_def() -> LabwareDefinition: """Get the definition of Opentrons 96 PCR adapter.""" - return LabwareDefinition.parse_obj(load_definition("opentrons_96_pcr_adapter", 1)) + return LabwareDefinition.model_validate( + load_definition("opentrons_96_pcr_adapter", 1) + ) @pytest.fixture(scope="session") def falcon_tuberack_def() -> LabwareDefinition: """Get the definition of the 6-well Falcon tuberack.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( load_definition("opentrons_6_tuberack_falcon_50ml_conical", 1) ) @@ -160,7 +166,7 @@ def falcon_tuberack_def() -> LabwareDefinition: @pytest.fixture(scope="session") def magdeck_well_plate_def() -> LabwareDefinition: """Get the definition of a well place compatible with magdeck.""" - return LabwareDefinition.parse_obj( + return LabwareDefinition.model_validate( load_definition("nest_96_wellplate_100ul_pcr_full_skirt", 1) ) diff --git a/api/tests/opentrons/protocol_engine/resources/test_labware_data_provider.py b/api/tests/opentrons/protocol_engine/resources/test_labware_data_provider.py index 92718c70d89..a666e7a697d 100644 --- a/api/tests/opentrons/protocol_engine/resources/test_labware_data_provider.py +++ b/api/tests/opentrons/protocol_engine/resources/test_labware_data_provider.py @@ -22,7 +22,7 @@ async def test_labware_data_gets_standard_definition() -> None: version=1, ) - assert result == LabwareDefinition.parse_obj(expected) + assert result == LabwareDefinition.model_validate(expected) async def test_labware_hash_match() -> None: @@ -38,9 +38,9 @@ async def test_labware_hash_match() -> None: version=1, ) - labware_model = LabwareDefinition.parse_obj(labware_dict) + labware_model = LabwareDefinition.model_validate(labware_dict) labware_model_dict = cast( - LabwareDefDict, labware_model.dict(exclude_none=True, exclude_unset=True) + LabwareDefDict, labware_model.model_dump(exclude_none=True, exclude_unset=True) ) assert hash_labware_def(labware_dict) == hash_labware_def(labware_model_dict) diff --git a/api/tests/opentrons/protocol_engine/state/test_command_history.py b/api/tests/opentrons/protocol_engine/state/test_command_history.py index 14eaa2a42f3..fabf17e26d1 100644 --- a/api/tests/opentrons/protocol_engine/state/test_command_history.py +++ b/api/tests/opentrons/protocol_engine/state/test_command_history.py @@ -202,13 +202,13 @@ def test_set_fixit_running_command_id(command_history: CommandHistory) -> None: """It should set the ID of the currently running fixit command.""" command_entry = create_queued_command() command_history.append_queued_command(command_entry) - running_command = command_entry.copy( + running_command = command_entry.model_copy( update={ "status": CommandStatus.RUNNING, } ) command_history.set_command_running(running_command) - finished_command = command_entry.copy( + finished_command = command_entry.model_copy( update={ "status": CommandStatus.SUCCEEDED, } @@ -218,7 +218,7 @@ def test_set_fixit_running_command_id(command_history: CommandHistory) -> None: command_id="fixit-id", intent=CommandIntent.FIXIT ) command_history.append_queued_command(fixit_command_entry) - fixit_running_command = fixit_command_entry.copy( + fixit_running_command = fixit_command_entry.model_copy( update={ "status": CommandStatus.RUNNING, } diff --git a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py index d4b59513be7..0cc542c4971 100644 --- a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py +++ b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py @@ -159,7 +159,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: assert len(commands_result) == 32 - assert commands_result[0] == commands.Home.construct( + assert commands_result[0] == commands.Home.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -170,7 +170,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.HomeResult(), ) - assert commands_result[1] == commands.LoadLabware.construct( + assert commands_result[1] == commands.LoadLabware.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -186,7 +186,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=tiprack_1_result_captor, ) - assert commands_result[2] == commands.LoadLabware.construct( + assert commands_result[2] == commands.LoadLabware.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -202,7 +202,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=tiprack_2_result_captor, ) - assert commands_result[3] == commands.LoadModule.construct( + assert commands_result[3] == commands.LoadModule.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -217,7 +217,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=module_1_result_captor, ) - assert commands_result[4] == commands.LoadLabware.construct( + assert commands_result[4] == commands.LoadLabware.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -233,7 +233,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=well_plate_1_result_captor, ) - assert commands_result[5] == commands.LoadLabware.construct( + assert commands_result[5] == commands.LoadLabware.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -250,7 +250,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: result=module_plate_1_result_captor, ) - assert commands_result[6] == commands.LoadPipette.construct( + assert commands_result[6] == commands.LoadPipette.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -264,7 +264,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: result=pipette_left_result_captor, ) - assert commands_result[7] == commands.LoadPipette.construct( + assert commands_result[7] == commands.LoadPipette.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -285,7 +285,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: pipette_left_id = pipette_left_result_captor.value.pipetteId pipette_right_id = pipette_right_result_captor.value.pipetteId - assert commands_result[8] == commands.PickUpTip.construct( + assert commands_result[8] == commands.PickUpTip.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -302,7 +302,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: tipVolume=300.0, tipLength=51.83, position=DeckPoint(x=0, y=0, z=0) ), ) - assert commands_result[9] == commands.PickUpTip.construct( + assert commands_result[9] == commands.PickUpTip.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -320,7 +320,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: ), ) - assert commands_result[10] == commands.DropTip.construct( + assert commands_result[10] == commands.DropTip.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -336,7 +336,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: result=commands.DropTipResult(position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[11] == commands.PickUpTip.construct( + assert commands_result[11] == commands.PickUpTip.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -353,7 +353,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: tipVolume=300.0, tipLength=51.83, position=DeckPoint(x=0, y=0, z=0) ), ) - assert commands_result[12] == commands.Aspirate.construct( + assert commands_result[12] == commands.Aspirate.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -370,7 +370,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.AspirateResult(volume=40, position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[13] == commands.Dispense.construct( + assert commands_result[13] == commands.Dispense.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -387,7 +387,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.DispenseResult(volume=35, position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[14] == commands.Aspirate.construct( + assert commands_result[14] == commands.Aspirate.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -404,7 +404,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.AspirateResult(volume=40, position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[15] == commands.Dispense.construct( + assert commands_result[15] == commands.Dispense.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -421,7 +421,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.DispenseResult(volume=35, position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[16] == commands.BlowOut.construct( + assert commands_result[16] == commands.BlowOut.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -437,7 +437,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.BlowOutResult(position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[17] == commands.Aspirate.construct( + assert commands_result[17] == commands.Aspirate.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -454,7 +454,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.AspirateResult(volume=50, position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[18] == commands.Dispense.construct( + assert commands_result[18] == commands.Dispense.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -471,7 +471,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.DispenseResult(volume=50, position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[19] == commands.BlowOut.construct( + assert commands_result[19] == commands.BlowOut.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -487,7 +487,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.BlowOutResult(position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[20] == commands.Aspirate.construct( + assert commands_result[20] == commands.Aspirate.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -504,7 +504,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.AspirateResult(volume=300, position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[21] == commands.Dispense.construct( + assert commands_result[21] == commands.Dispense.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -521,7 +521,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.DispenseResult(volume=300, position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[22] == commands.BlowOut.construct( + assert commands_result[22] == commands.BlowOut.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -538,7 +538,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: result=commands.BlowOutResult(position=DeckPoint(x=0, y=0, z=0)), ) # TODO:(jr, 15.08.2022): this should map to move_to when move_to is mapped in a followup ticket RSS-62 - assert commands_result[23] == commands.Custom.construct( + assert commands_result[23] == commands.Custom.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -554,7 +554,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: ) # TODO:(jr, 15.08.2022): aspirate commands with no labware get filtered # into custom. Refactor this in followup legacy command mapping - assert commands_result[24] == commands.Custom.construct( + assert commands_result[24] == commands.Custom.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -570,7 +570,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: ) # TODO:(jr, 15.08.2022): dispense commands with no labware get filtered # into custom. Refactor this in followup legacy command mapping - assert commands_result[25] == commands.Custom.construct( + assert commands_result[25] == commands.Custom.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -586,7 +586,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: ) # TODO:(jr, 15.08.2022): blow_out commands with no labware get filtered # into custom. Refactor this in followup legacy command mapping - assert commands_result[26] == commands.Custom.construct( + assert commands_result[26] == commands.Custom.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -600,7 +600,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.CustomResult(), ) - assert commands_result[27] == commands.Aspirate.construct( + assert commands_result[27] == commands.Aspirate.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -617,7 +617,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.AspirateResult(volume=50, position=DeckPoint(x=0, y=0, z=0)), ) - assert commands_result[28] == commands.Dispense.construct( + assert commands_result[28] == commands.Dispense.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -636,7 +636,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: ) # TODO:(jr, 15.08.2022): aspirate commands with no labware get filtered # into custom. Refactor this in followup legacy command mapping - assert commands_result[29] == commands.Custom.construct( + assert commands_result[29] == commands.Custom.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -652,7 +652,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: ) # TODO:(jr, 15.08.2022): dispense commands with no labware get filtered # into custom. Refactor this in followup legacy command mapping - assert commands_result[30] == commands.Custom.construct( + assert commands_result[30] == commands.Custom.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -666,7 +666,7 @@ async def test_big_protocol_commands(big_protocol_file: Path) -> None: notes=[], result=commands.CustomResult(), ) - assert commands_result[31] == commands.DropTip.construct( + assert commands_result[31] == commands.DropTip.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -812,7 +812,7 @@ def run(protocol): ) result_commands = await simulate_and_get_commands(path) [initial_home, comment] = result_commands - assert comment == commands.Comment.construct( + assert comment == commands.Comment.model_construct( status=commands.CommandStatus.SUCCEEDED, params=commands.CommentParams(message="oy."), notes=[], diff --git a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_custom_labware.py b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_custom_labware.py index 7ed54b17ebe..dcc95593c38 100644 --- a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_custom_labware.py +++ b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_custom_labware.py @@ -58,7 +58,7 @@ async def test_legacy_custom_labware(custom_labware_protocol_files: List[Path]) ) result = await subject.run(deck_configuration=[], protocol_source=protocol_source) - expected_labware = LoadedLabware.construct( + expected_labware = LoadedLabware.model_construct( id=matchers.Anything(), location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), loadName="fixture_96_plate", diff --git a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_module_commands.py b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_module_commands.py index e27c23faa27..5650312b5f6 100644 --- a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_module_commands.py +++ b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_module_commands.py @@ -75,7 +75,7 @@ async def test_runner_with_modules_in_legacy_python( thermocycler_result_captor = matchers.Captor() heater_shaker_result_captor = matchers.Captor() - assert commands_result[0] == commands.Home.construct( + assert commands_result[0] == commands.Home.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -86,7 +86,7 @@ async def test_runner_with_modules_in_legacy_python( notes=[], result=commands.HomeResult(), ) - assert commands_result[1] == commands.LoadLabware.construct( + assert commands_result[1] == commands.LoadLabware.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -98,7 +98,7 @@ async def test_runner_with_modules_in_legacy_python( result=matchers.Anything(), ) - assert commands_result[2] == commands.LoadModule.construct( + assert commands_result[2] == commands.LoadModule.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -110,7 +110,7 @@ async def test_runner_with_modules_in_legacy_python( result=temp_module_result_captor, ) - assert commands_result[3] == commands.LoadModule.construct( + assert commands_result[3] == commands.LoadModule.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -122,7 +122,7 @@ async def test_runner_with_modules_in_legacy_python( result=mag_module_result_captor, ) - assert commands_result[4] == commands.LoadModule.construct( + assert commands_result[4] == commands.LoadModule.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -134,7 +134,7 @@ async def test_runner_with_modules_in_legacy_python( result=thermocycler_result_captor, ) - assert commands_result[5] == commands.LoadModule.construct( + assert commands_result[5] == commands.LoadModule.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, diff --git a/api/tests/opentrons/protocol_runner/smoke_tests/test_protocol_runner.py b/api/tests/opentrons/protocol_runner/smoke_tests/test_protocol_runner.py index 1a8da30bd76..5db66e55eb2 100644 --- a/api/tests/opentrons/protocol_runner/smoke_tests/test_protocol_runner.py +++ b/api/tests/opentrons/protocol_runner/smoke_tests/test_protocol_runner.py @@ -58,13 +58,13 @@ async def test_runner_with_python( pipette_id_captor = matchers.Captor() labware_id_captor = matchers.Captor() - expected_pipette = LoadedPipette.construct( + expected_pipette = LoadedPipette.model_construct( id=pipette_id_captor, pipetteName=PipetteNameType.P300_SINGLE, mount=MountType.LEFT, ) - expected_labware = LoadedLabware.construct( + expected_labware = LoadedLabware.model_construct( id=labware_id_captor, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), loadName="opentrons_96_tiprack_300ul", @@ -75,7 +75,7 @@ async def test_runner_with_python( offsetId=None, ) - expected_module = LoadedModule.construct( + expected_module = LoadedModule.model_construct( id=matchers.IsA(str), model=ModuleModel.TEMPERATURE_MODULE_V1, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_3), @@ -86,7 +86,7 @@ async def test_runner_with_python( assert expected_labware in labware_result assert expected_module in modules_result - expected_command = commands.PickUpTip.construct( + expected_command = commands.PickUpTip.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -148,7 +148,7 @@ async def test_runner_with_json(json_protocol_file: Path) -> None: assert expected_pipette in pipettes_result assert expected_labware in labware_result - expected_command = commands.PickUpTip.construct( + expected_command = commands.PickUpTip.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -196,13 +196,13 @@ async def test_runner_with_legacy_python(legacy_python_protocol_file: Path) -> N pipette_id_captor = matchers.Captor() labware_id_captor = matchers.Captor() - expected_pipette = LoadedPipette.construct( + expected_pipette = LoadedPipette.model_construct( id=pipette_id_captor, pipetteName=PipetteNameType.P300_SINGLE, mount=MountType.LEFT, ) - expected_labware = LoadedLabware.construct( + expected_labware = LoadedLabware.model_construct( id=labware_id_captor, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), loadName="opentrons_96_tiprack_300ul", @@ -215,7 +215,7 @@ async def test_runner_with_legacy_python(legacy_python_protocol_file: Path) -> N assert expected_pipette in pipettes_result assert expected_labware in labware_result - expected_command = commands.PickUpTip.construct( + expected_command = commands.PickUpTip.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -260,13 +260,13 @@ async def test_runner_with_legacy_json(legacy_json_protocol_file: Path) -> None: pipette_id_captor = matchers.Captor() labware_id_captor = matchers.Captor() - expected_pipette = LoadedPipette.construct( + expected_pipette = LoadedPipette.model_construct( id=pipette_id_captor, pipetteName=PipetteNameType.P300_SINGLE, mount=MountType.LEFT, ) - expected_labware = LoadedLabware.construct( + expected_labware = LoadedLabware.model_construct( id=labware_id_captor, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), loadName="opentrons_96_tiprack_300ul", @@ -280,7 +280,7 @@ async def test_runner_with_legacy_json(legacy_json_protocol_file: Path) -> None: assert expected_pipette in pipettes_result assert expected_labware in labware_result - expected_command = commands.PickUpTip.construct( + expected_command = commands.PickUpTip.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, @@ -327,13 +327,13 @@ async def test_runner_with_python_and_run_time_parameters( tiprack_id_captor = matchers.Captor() reservoir_id_captor = matchers.Captor() - expected_pipette = LoadedPipette.construct( + expected_pipette = LoadedPipette.model_construct( id=pipette_id_captor, pipetteName=PipetteNameType.P300_SINGLE, mount=MountType.LEFT, ) - expected_tiprack = LoadedLabware.construct( + expected_tiprack = LoadedLabware.model_construct( id=tiprack_id_captor, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), loadName="opentrons_96_tiprack_300ul", @@ -344,7 +344,7 @@ async def test_runner_with_python_and_run_time_parameters( offsetId=None, ) - expected_reservoir = LoadedLabware.construct( + expected_reservoir = LoadedLabware.model_construct( id=reservoir_id_captor, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_2), loadName="nest_1_reservoir_195ml", @@ -361,14 +361,14 @@ async def test_runner_with_python_and_run_time_parameters( assert result.state_summary.status == EngineStatus.SUCCEEDED - expected_command = commands.Aspirate.construct( + expected_command = commands.Aspirate.model_construct( id=matchers.IsA(str), key=matchers.IsA(str), status=commands.CommandStatus.SUCCEEDED, createdAt=matchers.IsA(datetime), startedAt=matchers.IsA(datetime), completedAt=matchers.IsA(datetime), - params=commands.AspirateParams.construct( + params=commands.AspirateParams.model_construct( labwareId=reservoir_id_captor.value, wellName=matchers.IsA(str), wellLocation=matchers.Anything(), diff --git a/api/tests/opentrons/protocol_runner/test_json_translator.py b/api/tests/opentrons/protocol_runner/test_json_translator.py index b9abbf4e655..b48c18f95c9 100644 --- a/api/tests/opentrons/protocol_runner/test_json_translator.py +++ b/api/tests/opentrons/protocol_runner/test_json_translator.py @@ -194,7 +194,7 @@ wellName="A1", ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="dropTip", params={ "pipetteId": "pipette-id-1", @@ -231,7 +231,7 @@ wellName="A1", ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="pickUpTip", params={ "pipetteId": "pipette-id-1", @@ -273,7 +273,7 @@ ), ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="touchTip", params={ "pipetteId": "pipette-id-1", @@ -308,7 +308,7 @@ pipetteId="pipette-id-1", mount="left", pipetteName="p10_single" ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="loadPipette", params={ "pipetteId": "pipette-id-1", @@ -340,7 +340,7 @@ location=Location(slotName="3"), ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="loadModule", params={ "moduleId": "module-id-1", @@ -375,7 +375,7 @@ displayName="Trash", ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="loadLabware", params={ "labwareId": "labware-id-2", @@ -424,7 +424,7 @@ flowRate=1.23, ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="blowout", params={ "pipetteId": "pipette-id-1", @@ -459,7 +459,7 @@ commandType="delay", params=protocol_schema_v7.Params(waitForResume=True, message="hello world"), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="delay", params={"waitForResume": True, "message": "hello world"}, ), @@ -476,7 +476,7 @@ commandType="delay", params=protocol_schema_v7.Params(seconds=12.34, message="hello world"), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="delay", params={"seconds": 12.34, "message": "hello world"}, ), @@ -496,7 +496,7 @@ commandType="waitForResume", params=protocol_schema_v7.Params(message="hello world"), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="waitForResume", params={"message": "hello world"}, ), @@ -513,7 +513,7 @@ commandType="waitForDuration", params=protocol_schema_v7.Params(seconds=12.34, message="hello world"), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="waitForDuration", params={"seconds": 12.34, "message": "hello world"}, ), @@ -543,7 +543,7 @@ forceDirect=True, ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="moveToCoordinates", params={ "pipetteId": "pipette-id-1", @@ -596,7 +596,7 @@ ], ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="thermocycler/runProfile", params={ "moduleId": "module-id-2", @@ -647,7 +647,7 @@ volumeByWell={"A1": 32, "B2": 50}, ), ), - protocol_schema_v8.Command.construct( + protocol_schema_v8.Command.model_construct( commandType="loadLiquid", key=None, params={ diff --git a/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py b/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py index 42c589ba7d3..a91066c01f8 100644 --- a/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py +++ b/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py @@ -117,7 +117,7 @@ def test_map_after_command() -> None: assert result == [ pe_actions.SucceedCommandAction( - command=pe_commands.Comment.construct( + command=pe_commands.Comment.model_construct( id="command.COMMENT-0", key="command.COMMENT-0", status=pe_commands.CommandStatus.SUCCEEDED, @@ -240,7 +240,7 @@ def test_command_stack() -> None: command_id="command.COMMENT-1", started_at=matchers.IsA(datetime) ), pe_actions.SucceedCommandAction( - command=pe_commands.Comment.construct( + command=pe_commands.Comment.model_construct( id="command.COMMENT-0", key="command.COMMENT-0", status=pe_commands.CommandStatus.SUCCEEDED, @@ -302,7 +302,7 @@ def test_map_labware_load(minimal_labware_def: LabwareDefinition) -> None: started_at=matchers.IsA(datetime), ) expected_succeed = pe_actions.SucceedCommandAction( - command=pe_commands.LoadLabware.construct( + command=pe_commands.LoadLabware.model_construct( id=expected_id_and_key, key=expected_id_and_key, params=expected_params, @@ -310,7 +310,7 @@ def test_map_labware_load(minimal_labware_def: LabwareDefinition) -> None: createdAt=matchers.IsA(datetime), startedAt=matchers.IsA(datetime), completedAt=matchers.IsA(datetime), - result=pe_commands.LoadLabwareResult.construct( + result=pe_commands.LoadLabwareResult.model_construct( labwareId=matchers.IsA(str), # Trusting that the exact fields within in the labware definition # get passed through correctly. @@ -352,7 +352,7 @@ def test_map_instrument_load(decoy: Decoy) -> None: ).then_return(pipette_config) expected_id_and_key = "commands.LOAD_PIPETTE-0" - expected_params = pe_commands.LoadPipetteParams.construct( + expected_params = pe_commands.LoadPipetteParams.model_construct( pipetteName=PipetteNameType.P1000_SINGLE_GEN2, mount=MountType.LEFT ) expected_queue = pe_actions.QueueCommandAction( @@ -367,7 +367,7 @@ def test_map_instrument_load(decoy: Decoy) -> None: command_id=expected_id_and_key, started_at=matchers.IsA(datetime) ) expected_succeed = pe_actions.SucceedCommandAction( - command=pe_commands.LoadPipette.construct( + command=pe_commands.LoadPipette.model_construct( id=expected_id_and_key, key=expected_id_and_key, status=pe_commands.CommandStatus.SUCCEEDED, @@ -410,7 +410,7 @@ def test_map_module_load( module_data_provider: ModuleDataProvider, ) -> None: """It should correctly map a module load.""" - test_definition = ModuleDefinition.parse_obj(minimal_module_def) + test_definition = ModuleDefinition.model_validate(minimal_module_def) input = LegacyModuleLoadInfo( requested_model=TemperatureModuleModel.TEMPERATURE_V1, loaded_model=TemperatureModuleModel.TEMPERATURE_V2, @@ -423,7 +423,7 @@ def test_map_module_load( ).then_return(test_definition) expected_id_and_key = "commands.LOAD_MODULE-0" - expected_params = pe_commands.LoadModuleParams.construct( + expected_params = pe_commands.LoadModuleParams.model_construct( model=ModuleModel.TEMPERATURE_MODULE_V1, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), moduleId=matchers.IsA(str), @@ -440,7 +440,7 @@ def test_map_module_load( command_id=expected_id_and_key, started_at=matchers.IsA(datetime) ) expected_succeed = pe_actions.SucceedCommandAction( - command=pe_commands.LoadModule.construct( + command=pe_commands.LoadModule.model_construct( id=expected_id_and_key, key=expected_id_and_key, status=pe_commands.CommandStatus.SUCCEEDED, @@ -448,7 +448,7 @@ def test_map_module_load( startedAt=matchers.IsA(datetime), completedAt=matchers.IsA(datetime), params=expected_params, - result=pe_commands.LoadModuleResult.construct( + result=pe_commands.LoadModuleResult.model_construct( moduleId=matchers.IsA(str), serialNumber="module-serial", definition=test_definition, @@ -481,7 +481,7 @@ def test_map_module_labware_load(minimal_labware_def: LabwareDefinition) -> None ) expected_id_and_key = "commands.LOAD_LABWARE-0" - expected_params = pe_commands.LoadLabwareParams.construct( + expected_params = pe_commands.LoadLabwareParams.model_construct( location=ModuleLocation(moduleId="module-123"), namespace="some_namespace", loadName="some_load_name", @@ -503,7 +503,7 @@ def test_map_module_labware_load(minimal_labware_def: LabwareDefinition) -> None started_at=matchers.IsA(datetime), ) expected_succeed = pe_actions.SucceedCommandAction( - command=pe_commands.LoadLabware.construct( + command=pe_commands.LoadLabware.model_construct( id=expected_id_and_key, key=expected_id_and_key, params=expected_params, @@ -511,7 +511,7 @@ def test_map_module_labware_load(minimal_labware_def: LabwareDefinition) -> None createdAt=matchers.IsA(datetime), startedAt=matchers.IsA(datetime), completedAt=matchers.IsA(datetime), - result=pe_commands.LoadLabwareResult.construct( + result=pe_commands.LoadLabwareResult.model_construct( labwareId=matchers.IsA(str), # Trusting that the exact fields within in the labware definition # get passed through correctly. @@ -578,7 +578,7 @@ def test_map_pause() -> None: started_at=matchers.IsA(datetime), ), pe_actions.SucceedCommandAction( - command=pe_commands.WaitForResume.construct( + command=pe_commands.WaitForResume.model_construct( id="command.PAUSE-0", key="command.PAUSE-0", status=pe_commands.CommandStatus.SUCCEEDED, diff --git a/api/tests/opentrons/protocol_runner/test_run_orchestrator.py b/api/tests/opentrons/protocol_runner/test_run_orchestrator.py index c2cea3e0e7e..b7281953f22 100644 --- a/api/tests/opentrons/protocol_runner/test_run_orchestrator.py +++ b/api/tests/opentrons/protocol_runner/test_run_orchestrator.py @@ -256,11 +256,11 @@ async def test_add_command_and_wait_for_interval( verify_calls: int, ) -> None: """Should add a command a wait for it to complete.""" - load_command = pe_commands.HomeCreate.construct( - params=pe_commands.HomeParams.construct() + load_command = pe_commands.HomeCreate.model_construct( + params=pe_commands.HomeParams.model_construct() ) added_command = pe_commands.Home( - params=pe_commands.HomeParams.construct(), + params=pe_commands.HomeParams.model_construct(), id="test-123", createdAt=datetime(year=2024, month=1, day=1), key="123", diff --git a/api/tests/opentrons/protocols/models/test_json_protocol.py b/api/tests/opentrons/protocols/models/test_json_protocol.py index 696524ac84a..afb2770f21a 100644 --- a/api/tests/opentrons/protocols/models/test_json_protocol.py +++ b/api/tests/opentrons/protocols/models/test_json_protocol.py @@ -25,7 +25,7 @@ def test_json_protocol_model( ) # Create the model - d = json_protocol.Model.parse_obj(fx) + d = json_protocol.Model.model_validate(fx) # Compare the dict created by pydantic to the loaded json - assert d.dict(exclude_unset=True, by_alias=True) == fx + assert d.model_dump(exclude_unset=True, by_alias=True) == fx diff --git a/hardware/pytest.ini b/hardware/pytest.ini index 9337cd62ee1..2c36b03cf37 100644 --- a/hardware/pytest.ini +++ b/hardware/pytest.ini @@ -5,3 +5,9 @@ markers = requires_emulator: mark test as requiring emulator can_filter_func: can message filtering function asyncio_mode = auto + +filterwarnings = + # Pydantic's shims for its legacy v1 methods (e.g. `BaseModel.construct()`) + # are not type-checked properly. Forbid them, so we're forced to use their newer + # v2 replacements which are type-checked (e.g. ``BaseModel.model_construct()`) + error::pydantic.PydanticDeprecatedSince20 diff --git a/robot-server/pytest.ini b/robot-server/pytest.ini index 51ed89fd0d2..210861cb6ca 100644 --- a/robot-server/pytest.ini +++ b/robot-server/pytest.ini @@ -5,7 +5,11 @@ markers = addopts = --color=yes --strict-markers asyncio_mode = auto -# Don't allow any new code that uses features removed in SQLAlchemy 2.0. -# We should remove this when we upgrade to SQLAlchemy 2.0. filterwarnings = + # Don't allow any new code that uses features removed in SQLAlchemy 2.0. + # We should remove this when we upgrade to SQLAlchemy 2.0. error::sqlalchemy.exc.RemovedIn20Warning + # Pydantic's shims for its legacy v1 methods (e.g. `BaseModel.construct()`) + # are not type-checked properly. Forbid them, so we're forced to use their newer + # v2 replacements which are type-checked (e.g. ``BaseModel.model_construct()`) + error::pydantic.PydanticDeprecatedSince20 diff --git a/robot-server/robot_server/client_data/router.py b/robot-server/robot_server/client_data/router.py index 3a619c2111c..4a2850cb8c1 100644 --- a/robot-server/robot_server/client_data/router.py +++ b/robot-server/robot_server/client_data/router.py @@ -73,7 +73,7 @@ async def put_client_data( # noqa: D103 ) -> SimpleBody[ClientData]: store.put(key, request_body.data) client_data_publisher.publish_client_data(key) - return SimpleBody.construct(data=store.get(key)) + return SimpleBody.model_construct(data=store.get(key)) @router.get( @@ -92,7 +92,7 @@ async def get_client_data( # noqa: D103 store: Annotated[ClientDataStore, fastapi.Depends(get_client_data_store)], ) -> SimpleBody[ClientData]: try: - return SimpleBody.construct(data=store.get(key)) + return SimpleBody.model_construct(data=store.get(key)) except KeyError as e: raise ClientDataKeyDoesNotExist.from_exc(e).as_error( fastapi.status.HTTP_404_NOT_FOUND @@ -125,7 +125,7 @@ async def delete_client_data( # noqa: D103 ) from e else: client_data_publisher.publish_client_data(key) - return SimpleEmptyBody.construct() + return SimpleEmptyBody.model_construct() @router.delete( @@ -143,4 +143,4 @@ async def delete_all_client_data( # noqa: D103 store.delete_all() for deleted_key in keys_that_will_be_deleted: client_data_publisher.publish_client_data(deleted_key) - return SimpleEmptyBody.construct() + return SimpleEmptyBody.model_construct() diff --git a/robot-server/robot_server/commands/router.py b/robot-server/robot_server/commands/router.py index e4d2d4a9f13..ce4db3fd515 100644 --- a/robot-server/robot_server/commands/router.py +++ b/robot-server/robot_server/commands/router.py @@ -109,7 +109,9 @@ async def create_command( Comes from a query parameter in the URL. orchestrator: The `RunOrchestrator` handling engine for command to be enqueued. """ - command_create = request_body.data.copy(update={"intent": CommandIntent.SETUP}) + command_create = request_body.data.model_copy( + update={"intent": CommandIntent.SETUP} + ) command = await orchestrator.add_command_and_wait_for_interval( command=command_create, wait_until_complete=waitUntilComplete, timeout=timeout ) @@ -117,7 +119,7 @@ async def create_command( response_data = cast(StatelessCommand, orchestrator.get_command(command.id)) return await PydanticResponse.create( - content=SimpleBody.construct(data=response_data), + content=SimpleBody.model_construct(data=response_data), status_code=status.HTTP_201_CREATED, ) @@ -168,7 +170,7 @@ async def get_commands_list( meta = MultiBodyMeta(cursor=cmd_slice.cursor, totalLength=cmd_slice.total_length) return await PydanticResponse.create( - content=SimpleMultiBody.construct(data=commands, meta=meta), + content=SimpleMultiBody.model_construct(data=commands, meta=meta), status_code=status.HTTP_200_OK, ) @@ -204,6 +206,6 @@ async def get_command( raise CommandNotFound.from_exc(e).as_error(status.HTTP_404_NOT_FOUND) from e return await PydanticResponse.create( - content=SimpleBody.construct(data=cast(StatelessCommand, command)), + content=SimpleBody.model_construct(data=cast(StatelessCommand, command)), status_code=status.HTTP_200_OK, ) diff --git a/robot-server/robot_server/data_files/router.py b/robot-server/robot_server/data_files/router.py index cf4ba9fa649..f9c61afb77a 100644 --- a/robot-server/robot_server/data_files/router.py +++ b/robot-server/robot_server/data_files/router.py @@ -138,8 +138,8 @@ async def upload_data_file( existing_file_info = data_files_store.get_file_info_by_hash(file_hash) if existing_file_info: return await PydanticResponse.create( - content=SimpleBody.construct( - data=DataFile.construct( + content=SimpleBody.model_construct( + data=DataFile.model_construct( id=existing_file_info.id, name=existing_file_info.name, createdAt=existing_file_info.created_at, @@ -162,8 +162,8 @@ async def upload_data_file( ) await data_files_store.insert(file_info) return await PydanticResponse.create( - content=SimpleBody.construct( - data=DataFile.construct( + content=SimpleBody.model_construct( + data=DataFile.model_construct( id=file_info.id, name=file_info.name, createdAt=created_at, @@ -199,8 +199,8 @@ async def get_data_file_info_by_id( raise FileIdNotFound(detail=str(e)).as_error(status.HTTP_404_NOT_FOUND) return await PydanticResponse.create( - content=SimpleBody.construct( - data=DataFile.construct( + content=SimpleBody.model_construct( + data=DataFile.model_construct( id=resource.id, name=resource.name, createdAt=resource.created_at, @@ -264,9 +264,9 @@ async def get_all_data_files( meta = MultiBodyMeta(cursor=0, totalLength=len(data_files)) return await PydanticResponse.create( - content=SimpleMultiBody.construct( + content=SimpleMultiBody.model_construct( data=[ - DataFile.construct( + DataFile.model_construct( id=data_file_info.id, name=data_file_info.name, createdAt=data_file_info.created_at, @@ -307,6 +307,6 @@ async def delete_file_by_id( raise DataFileInUse(detail=str(e)).as_error(status.HTTP_409_CONFLICT) from e return await PydanticResponse.create( - content=SimpleEmptyBody.construct(), + content=SimpleEmptyBody.model_construct(), status_code=status.HTTP_200_OK, ) diff --git a/robot-server/robot_server/deck_configuration/defaults.py b/robot-server/robot_server/deck_configuration/defaults.py index 3ed9a5ed395..fce59673771 100644 --- a/robot-server/robot_server/deck_configuration/defaults.py +++ b/robot-server/robot_server/deck_configuration/defaults.py @@ -4,64 +4,64 @@ from . import models -_for_flex = models.DeckConfigurationRequest.construct( +_for_flex = models.DeckConfigurationRequest.model_construct( cutoutFixtures=[ - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutA1", cutoutFixtureId="singleLeftSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutB1", cutoutFixtureId="singleLeftSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutC1", cutoutFixtureId="singleLeftSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutD1", cutoutFixtureId="singleLeftSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutA2", cutoutFixtureId="singleCenterSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutB2", cutoutFixtureId="singleCenterSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutC2", cutoutFixtureId="singleCenterSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutD2", cutoutFixtureId="singleCenterSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutA3", cutoutFixtureId="trashBinAdapter", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutB3", cutoutFixtureId="singleRightSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutC3", cutoutFixtureId="singleRightSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutoutD3", cutoutFixtureId="singleRightSlot", opentronsModuleSerialNumber=None, @@ -70,64 +70,64 @@ ) -_for_ot2 = models.DeckConfigurationRequest.construct( +_for_ot2 = models.DeckConfigurationRequest.model_construct( cutoutFixtures=[ - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout1", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout2", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout3", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout4", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout5", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout6", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout7", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout8", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout9", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout10", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout11", cutoutFixtureId="singleStandardSlot", opentronsModuleSerialNumber=None, ), - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutId="cutout12", cutoutFixtureId="fixedTrashSlot", opentronsModuleSerialNumber=None, diff --git a/robot-server/robot_server/deck_configuration/router.py b/robot-server/robot_server/deck_configuration/router.py index cfb31c9f030..77ad38a3975 100644 --- a/robot-server/robot_server/deck_configuration/router.py +++ b/robot-server/robot_server/deck_configuration/router.py @@ -78,12 +78,12 @@ async def put_deck_configuration( # noqa: D103 if len(validation_errors) == 0: success_data = await store.set(request=request_body.data, last_modified_at=now) return await PydanticResponse.create( - content=SimpleBody.construct(data=success_data) + content=SimpleBody.model_construct(data=success_data) ) else: error_data = validation_mapping.map_out(validation_errors) return await PydanticResponse.create( - content=ErrorBody.construct(errors=error_data), + content=ErrorBody.model_construct(errors=error_data), status_code=HTTP_422_UNPROCESSABLE_ENTITY, ) @@ -111,5 +111,5 @@ async def get_deck_configuration( # noqa: D103 ], ) -> PydanticResponse[SimpleBody[models.DeckConfigurationResponse]]: return await PydanticResponse.create( - content=SimpleBody.construct(data=await store.get()) + content=SimpleBody.model_construct(data=await store.get()) ) diff --git a/robot-server/robot_server/deck_configuration/store.py b/robot-server/robot_server/deck_configuration/store.py index 159013e3504..4a383dd0a3d 100644 --- a/robot-server/robot_server/deck_configuration/store.py +++ b/robot-server/robot_server/deck_configuration/store.py @@ -132,7 +132,7 @@ async def get_for_cli(deck_type: DeckType, path: Path) -> bytes: return serialize_deck_configuration(from_storage[0], from_storage[1]) else: default_as_http_response = _get_default(deck_type) - default_as_http_request = models.DeckConfigurationRequest.construct( + default_as_http_request = models.DeckConfigurationRequest.model_construct( cutoutFixtures=default_as_http_response.cutoutFixtures ) storable_default = _http_types_to_storage_types( @@ -162,21 +162,21 @@ def _storage_types_to_http_types( ) -> models.DeckConfigurationResponse: storage_cutout_fixtures, last_modified_at = storage_val http_cutout_fixtures = [ - models.CutoutFixture.construct( + models.CutoutFixture.model_construct( cutoutFixtureId=storage_element.cutout_fixture_id, cutoutId=storage_element.cutout_id, opentronsModuleSerialNumber=storage_element.opentrons_module_serial_number, ) for storage_element in storage_cutout_fixtures ] - return models.DeckConfigurationResponse.construct( + return models.DeckConfigurationResponse.model_construct( cutoutFixtures=http_cutout_fixtures, lastModifiedAt=last_modified_at, ) def _get_default(deck_type: DeckType) -> models.DeckConfigurationResponse: - return models.DeckConfigurationResponse.construct( + return models.DeckConfigurationResponse.model_construct( cutoutFixtures=defaults.for_deck_definition(deck_type.value).cutoutFixtures, lastModifiedAt=None, ) diff --git a/robot-server/robot_server/error_recovery/settings/router.py b/robot-server/robot_server/error_recovery/settings/router.py index 4fdfeee5498..27dde185f0b 100644 --- a/robot-server/robot_server/error_recovery/settings/router.py +++ b/robot-server/robot_server/error_recovery/settings/router.py @@ -62,5 +62,7 @@ async def _get_current_response( ) -> PydanticResponse[SimpleBody[ResponseData]]: is_enabled = store.get_is_enabled() return await PydanticResponse.create( - SimpleBody.construct(data=ResponseData.construct(enabled=is_enabled)) + SimpleBody.model_construct( + data=ResponseData.model_construct(enabled=is_enabled) + ) ) diff --git a/robot-server/robot_server/errors/error_responses.py b/robot-server/robot_server/errors/error_responses.py index 73f8a97f445..82752660692 100644 --- a/robot-server/robot_server/errors/error_responses.py +++ b/robot-server/robot_server/errors/error_responses.py @@ -25,7 +25,7 @@ class BaseErrorBody(BaseResponseBody): def as_error(self, status_code: int) -> ApiError: """Serialize the response as an API error to raise in a handler.""" - return ApiError(status_code=status_code, content=self.dict()) + return ApiError(status_code=status_code, content=self.model_dump()) class ErrorSource(BaseModel): diff --git a/robot-server/robot_server/errors/global_errors.py b/robot-server/robot_server/errors/global_errors.py index 73e460854ba..5f7d73eb234 100644 --- a/robot-server/robot_server/errors/global_errors.py +++ b/robot-server/robot_server/errors/global_errors.py @@ -53,7 +53,7 @@ def from_exc( ) -> "FirmwareUpdateRequired": """Build a FirmwareUpdateRequired from a specific exception. Preserves metadata.""" parent_inst = ErrorDetails.from_exc(exc, **supplemental_kwargs) - inst = FirmwareUpdateRequired(**parent_inst.dict()) + inst = FirmwareUpdateRequired(**parent_inst.model_dump()) if not inst.meta: inst.meta = {"update_url": "/subsystems/update"} else: diff --git a/robot-server/robot_server/instruments/router.py b/robot-server/robot_server/instruments/router.py index a9a3e3bbed3..e059876eb37 100644 --- a/robot-server/robot_server/instruments/router.py +++ b/robot-server/robot_server/instruments/router.py @@ -63,7 +63,7 @@ def _pipette_dict_to_pipette_res( """Convert PipetteDict to Pipette response model.""" if pipette_dict: calibration_data = pipette_offset - return Pipette.construct( + return Pipette.model_construct( firmwareVersion=str(fw_version) if fw_version else None, ok=True, mount=MountType.from_hw_mount(mount).value, @@ -75,7 +75,7 @@ def _pipette_dict_to_pipette_res( channels=pipette_dict["channels"], min_volume=pipette_dict["min_volume"], max_volume=pipette_dict["max_volume"], - calibratedOffset=InstrumentCalibrationData.construct( + calibratedOffset=InstrumentCalibrationData.model_construct( offset=Vec3f( x=calibration_data.offset.x, y=calibration_data.offset.y, @@ -84,9 +84,9 @@ def _pipette_dict_to_pipette_res( source=calibration_data.source, last_modified=calibration_data.last_modified, reasonability_check_failures=[ - InconsistentCalibrationFailure.construct( + InconsistentCalibrationFailure.model_construct( offsets={ - k.name: Vec3f.construct(x=v.x, y=v.y, z=v.z) + k.name: Vec3f.model_construct(x=v.x, y=v.y, z=v.z) for k, v in failure.offsets.items() }, limit=failure.limit, @@ -97,7 +97,7 @@ def _pipette_dict_to_pipette_res( if calibration_data else None, ), - state=PipetteState.parse_obj(pipette_state) if pipette_state else None, + state=PipetteState.model_validate(pipette_state) if pipette_state else None, ) @@ -106,7 +106,7 @@ def _gripper_dict_to_gripper_res( ) -> Gripper: """Convert GripperDict to Gripper response model.""" calibration_data = gripper_dict["calibration_offset"] - return Gripper.construct( + return Gripper.model_construct( firmwareVersion=str(fw_version) if fw_version else None, ok=True, mount=MountType.EXTENSION.value, @@ -115,7 +115,7 @@ def _gripper_dict_to_gripper_res( subsystem=SubSystem.from_hw(HWSubSystem.of_mount(OT3Mount.GRIPPER)), data=GripperData( jawState=gripper_dict["state"].name.lower(), - calibratedOffset=InstrumentCalibrationData.construct( + calibratedOffset=InstrumentCalibrationData.model_construct( offset=Vec3f( x=calibration_data.offset.x, y=calibration_data.offset.y, @@ -219,7 +219,7 @@ async def _get_attached_instruments_ot3( await hardware.cache_instruments(skip_if_would_block=True) response_data = await _get_instrument_data(hardware) return await PydanticResponse.create( - content=SimpleMultiBody.construct( + content=SimpleMultiBody.model_construct( data=response_data, meta=MultiBodyMeta(cursor=0, totalLength=len(response_data)), ), @@ -243,7 +243,7 @@ async def _get_attached_instruments_ot2( if pipette_dict ] return await PydanticResponse.create( - content=SimpleMultiBody.construct( + content=SimpleMultiBody.model_construct( data=response_data, meta=MultiBodyMeta(cursor=0, totalLength=len(response_data)), ), diff --git a/robot-server/robot_server/labware_offsets/models.py b/robot-server/robot_server/labware_offsets/models.py index 8c6dd5760f6..fcc3d2f2200 100644 --- a/robot-server/robot_server/labware_offsets/models.py +++ b/robot-server/robot_server/labware_offsets/models.py @@ -1,8 +1,7 @@ """Request/response models for the `/labwareOffsets` endpoints.""" -from typing import Literal, Type -from typing_extensions import Self +from typing import Literal from robot_server.errors.error_responses import ErrorDetails @@ -14,6 +13,6 @@ class LabwareOffsetNotFound(ErrorDetails): title: str = "Labware Offset Not Found" @classmethod - def build(cls: Type[Self], bad_offset_id: str) -> Self: + def build(cls, bad_offset_id: str) -> "LabwareOffsetNotFound": """Return an error with a standard message.""" - return cls.construct(detail=f'No offset found with ID "{bad_offset_id}".') + return cls.model_construct(detail=f'No offset found with ID "{bad_offset_id}".') diff --git a/robot-server/robot_server/labware_offsets/router.py b/robot-server/robot_server/labware_offsets/router.py index fb017fc1457..241f5b31505 100644 --- a/robot-server/robot_server/labware_offsets/router.py +++ b/robot-server/robot_server/labware_offsets/router.py @@ -47,7 +47,7 @@ async def post_labware_offset( # noqa: D103 new_offset_created_at: Annotated[datetime, fastapi.Depends(get_current_time)], request_body: Annotated[RequestModel[LabwareOffsetCreate], fastapi.Body()], ) -> PydanticResponse[SimpleBody[LabwareOffset]]: - new_offset = LabwareOffset.construct( + new_offset = LabwareOffset.model_construct( id=new_offset_id, createdAt=new_offset_created_at, definitionUri=request_body.data.definitionUri, @@ -56,7 +56,7 @@ async def post_labware_offset( # noqa: D103 ) store.add(new_offset) return await PydanticResponse.create( - content=SimpleBody.construct(data=new_offset), + content=SimpleBody.model_construct(data=new_offset), status_code=201, ) @@ -142,14 +142,14 @@ async def get_labware_offsets( # noqa: D103 location_module_model_filter=location_module_model, ) - meta = MultiBodyMeta.construct( + meta = MultiBodyMeta.model_construct( # todo(mm, 2024-12-06): Update this when pagination is supported. cursor=0, totalLength=len(result_data), ) return await PydanticResponse.create( - SimpleMultiBody[LabwareOffset].construct( + SimpleMultiBody[LabwareOffset].model_construct( data=result_data, meta=meta, ) @@ -174,7 +174,9 @@ async def delete_labware_offset( # noqa: D103 except LabwareOffsetNotFoundError as e: raise LabwareOffsetNotFound.build(bad_offset_id=e.bad_offset_id).as_error(404) else: - return await PydanticResponse.create(SimpleBody.construct(data=deleted_offset)) + return await PydanticResponse.create( + SimpleBody.model_construct(data=deleted_offset) + ) @PydanticResponse.wrap_route( @@ -186,4 +188,4 @@ async def delete_all_labware_offsets( # noqa: D103 store: Annotated[LabwareOffsetStore, fastapi.Depends(get_labware_offset_store)] ) -> PydanticResponse[SimpleEmptyBody]: store.delete_all() - return await PydanticResponse.create(SimpleEmptyBody.construct()) + return await PydanticResponse.create(SimpleEmptyBody.model_construct()) diff --git a/robot-server/robot_server/maintenance_runs/maintenance_run_data_manager.py b/robot-server/robot_server/maintenance_runs/maintenance_run_data_manager.py index c3346e33351..dfc76945f81 100644 --- a/robot-server/robot_server/maintenance_runs/maintenance_run_data_manager.py +++ b/robot-server/robot_server/maintenance_runs/maintenance_run_data_manager.py @@ -24,7 +24,7 @@ def _build_run( created_at: datetime, state_summary: Optional[StateSummary], ) -> MaintenanceRun: - state_summary = state_summary or StateSummary.construct( + state_summary = state_summary or StateSummary.model_construct( status=EngineStatus.IDLE, errors=[], labware=[], @@ -37,7 +37,7 @@ def _build_run( liquidClasses=[], hasEverEnteredErrorRecovery=False, ) - return MaintenanceRun.construct( + return MaintenanceRun.model_construct( id=run_id, createdAt=created_at, status=state_summary.status, diff --git a/robot-server/robot_server/maintenance_runs/router/base_router.py b/robot-server/robot_server/maintenance_runs/router/base_router.py index 0e9abc62553..6f6abaf89b5 100644 --- a/robot-server/robot_server/maintenance_runs/router/base_router.py +++ b/robot-server/robot_server/maintenance_runs/router/base_router.py @@ -188,7 +188,7 @@ async def create_run( log.info(f'Created an empty run "{run_id}"".') return await PydanticResponse.create( - content=SimpleBody.construct(data=run_data), + content=SimpleBody.model_construct(data=run_data), status_code=status.HTTP_201_CREATED, ) @@ -221,11 +221,11 @@ async def get_current_run( data = run_data_manager.get(current_run_id) links = AllRunsLinks( - current=ResourceLink.construct(href=f"/maintenance_runs/{current_run_id}") + current=ResourceLink.model_construct(href=f"/maintenance_runs/{current_run_id}") ) return await PydanticResponse.create( - content=Body.construct(data=data, links=links), + content=Body.model_construct(data=data, links=links), status_code=status.HTTP_200_OK, ) @@ -249,7 +249,7 @@ async def get_run( run_data: Data of the run specified in the runId url parameter. """ return await PydanticResponse.create( - content=SimpleBody.construct(data=run_data), + content=SimpleBody.model_construct(data=run_data), status_code=status.HTTP_200_OK, ) @@ -285,6 +285,6 @@ async def remove_run( raise RunNotFound(detail=str(e)).as_error(status.HTTP_404_NOT_FOUND) from e return await PydanticResponse.create( - content=SimpleEmptyBody.construct(), + content=SimpleEmptyBody.model_construct(), status_code=status.HTTP_200_OK, ) diff --git a/robot-server/robot_server/maintenance_runs/router/commands_router.py b/robot-server/robot_server/maintenance_runs/router/commands_router.py index afc5e03779b..40c9b5d782a 100644 --- a/robot-server/robot_server/maintenance_runs/router/commands_router.py +++ b/robot-server/robot_server/maintenance_runs/router/commands_router.py @@ -155,7 +155,7 @@ async def create_run_command( # TODO(mc, 2022-05-26): increment the HTTP API version so that default # behavior is to pass through `command_intent` without overriding it command_intent = pe_commands.CommandIntent.SETUP - command_create = request_body.data.copy(update={"intent": command_intent}) + command_create = request_body.data.model_copy(update={"intent": command_intent}) command = await run_orchestrator_store.add_command_and_wait_for_interval( request=command_create, wait_until_complete=waitUntilComplete, timeout=timeout ) @@ -163,7 +163,7 @@ async def create_run_command( response_data = run_orchestrator_store.get_command(command.id) return await PydanticResponse.create( - content=SimpleBody.construct(data=response_data), + content=SimpleBody.model_construct(data=response_data), status_code=status.HTTP_201_CREATED, ) @@ -228,7 +228,7 @@ async def get_run_commands( recovery_target_command = run_data_manager.get_recovery_target_command(run_id=runId) data = [ - RunCommandSummary.construct( + RunCommandSummary.model_construct( id=c.id, key=c.key, commandType=c.commandType, @@ -249,13 +249,13 @@ async def get_run_commands( totalLength=command_slice.total_length, ) - links = CommandCollectionLinks.construct( + links = CommandCollectionLinks.model_construct( current=_make_command_link(runId, current_command), currentlyRecoveringFrom=_make_command_link(runId, recovery_target_command), ) return await PydanticResponse.create( - content=MultiBody.construct(data=data, meta=meta, links=links), + content=MultiBody.model_construct(data=data, meta=meta, links=links), status_code=status.HTTP_200_OK, ) @@ -297,7 +297,7 @@ async def get_run_command( raise CommandNotFound(detail=str(e)).as_error(status.HTTP_404_NOT_FOUND) from e return await PydanticResponse.create( - content=SimpleBody.construct(data=command), + content=SimpleBody.model_construct(data=command), status_code=status.HTTP_200_OK, ) @@ -306,7 +306,7 @@ def _make_command_link( run_id: str, command_pointer: Optional[CommandPointer] ) -> Optional[CommandLink]: return ( - CommandLink.construct( + CommandLink.model_construct( href=f"/maintenance_runs/{run_id}/commands/{command_pointer.command_id}", meta=CommandLinkMeta( runId=run_id, diff --git a/robot-server/robot_server/maintenance_runs/router/labware_router.py b/robot-server/robot_server/maintenance_runs/router/labware_router.py index 72fc09d911a..938cee77af7 100644 --- a/robot-server/robot_server/maintenance_runs/router/labware_router.py +++ b/robot-server/robot_server/maintenance_runs/router/labware_router.py @@ -54,7 +54,7 @@ async def add_labware_offset( log.info(f'Added labware offset "{added_offset.id}"' f' to run "{run.id}".') return await PydanticResponse.create( - content=SimpleBody.construct(data=added_offset), + content=SimpleBody.model_construct(data=added_offset), status_code=status.HTTP_201_CREATED, ) @@ -93,8 +93,8 @@ async def add_labware_definition( log.info(f'Added labware definition "{uri}"' f' to run "{run.id}".') return PydanticResponse( - content=SimpleBody.construct( - data=LabwareDefinitionSummary.construct(definitionUri=uri) + content=SimpleBody.model_construct( + data=LabwareDefinitionSummary.model_construct(definitionUri=uri) ), status_code=status.HTTP_201_CREATED, ) diff --git a/robot-server/robot_server/modules/router.py b/robot-server/robot_server/modules/router.py index 1f630d9bdb6..2f566eb7207 100644 --- a/robot-server/robot_server/modules/router.py +++ b/robot-server/robot_server/modules/router.py @@ -67,7 +67,7 @@ async def get_attached_modules( module_identity=module_identity, live_data=mod.live_data, usb_port=mod.usb_port, - module_offset=ModuleCalibrationData.construct( + module_offset=ModuleCalibrationData.model_construct( offset=Vec3f( x=calibrated.offset.x, y=calibrated.offset.y, @@ -83,7 +83,7 @@ async def get_attached_modules( ) return await PydanticResponse.create( - content=SimpleMultiBody.construct( + content=SimpleMultiBody.model_construct( data=response_data, meta=MultiBodyMeta(cursor=0, totalLength=len(response_data)), ), diff --git a/robot-server/robot_server/persistence/_migrations/up_to_2.py b/robot-server/robot_server/persistence/_migrations/up_to_2.py index 69e9cc57875..2e6ba069b36 100644 --- a/robot-server/robot_server/persistence/_migrations/up_to_2.py +++ b/robot-server/robot_server/persistence/_migrations/up_to_2.py @@ -215,11 +215,11 @@ def _migrate_data_1_to_2(transaction: sqlalchemy.engine.Connection) -> None: f"Migrating analysis {index+1}/{len(rows_needing_migration)}, {row.id}..." ) - v1_completed_analysis = CompletedAnalysis.parse_obj( + v1_completed_analysis = CompletedAnalysis.model_validate( _legacy_pickle.loads(row.completed_analysis) ) - v2_completed_analysis_as_document = v1_completed_analysis.json( + v2_completed_analysis_as_document = v1_completed_analysis.model_dump_json( # by_alias and exclude_none should match how # FastAPI + Pydantic + our customizations serialize these objects # over the `GET /protocols/:id/analyses/:id` endpoint. diff --git a/robot-server/robot_server/persistence/_migrations/up_to_3.py b/robot-server/robot_server/persistence/_migrations/up_to_3.py index 73053d10391..b4382545dbf 100644 --- a/robot-server/robot_server/persistence/_migrations/up_to_3.py +++ b/robot-server/robot_server/persistence/_migrations/up_to_3.py @@ -23,7 +23,6 @@ from typing import List from opentrons.protocol_engine import StateSummary -import pydantic import sqlalchemy from ..pydantic import pydantic_to_json @@ -138,9 +137,7 @@ def _migrate_run_table_excluding_commands( new_state_summary = ( None if old_row.state_summary is None - else pydantic_to_json( - pydantic.parse_obj_as(StateSummary, old_state_summary) - ) + else pydantic_to_json(StateSummary.model_validate(old_state_summary)) ) dest_transaction.execute( insert_new_run, diff --git a/robot-server/robot_server/persistence/pydantic.py b/robot-server/robot_server/persistence/pydantic.py index 8c6383f0ae1..a8eb14b0916 100644 --- a/robot-server/robot_server/persistence/pydantic.py +++ b/robot-server/robot_server/persistence/pydantic.py @@ -11,7 +11,7 @@ def pydantic_to_json(obj: BaseModel) -> str: """Serialize a Pydantic object for storing in the SQL database.""" - return obj.json( + return obj.model_dump_json( # by_alias and exclude_none should match how # FastAPI + Pydantic + our customizations serialize these objects by_alias=True, @@ -21,7 +21,9 @@ def pydantic_to_json(obj: BaseModel) -> str: def pydantic_list_to_json(obj_list: Sequence[BaseModel]) -> str: """Serialize a list of Pydantic objects for storing in the SQL database.""" - return json.dumps([obj.dict(by_alias=True, exclude_none=True) for obj in obj_list]) + return json.dumps( + [obj.model_dump(by_alias=True, exclude_none=True) for obj in obj_list] + ) @overload diff --git a/robot-server/robot_server/protocols/analysis_store.py b/robot-server/robot_server/protocols/analysis_store.py index be69601466f..d03c8cabb31 100644 --- a/robot-server/robot_server/protocols/analysis_store.py +++ b/robot-server/robot_server/protocols/analysis_store.py @@ -195,7 +195,7 @@ async def update( else: result = AnalysisResult.OK - completed_analysis = CompletedAnalysis.construct( + completed_analysis = CompletedAnalysis.model_construct( id=analysis_id, result=result, robotType=robot_type, @@ -237,7 +237,7 @@ async def save_initialization_failed_analysis( errors: List[ErrorOccurrence], ) -> None: """Commit the failed analysis to store.""" - completed_analysis = CompletedAnalysis.construct( + completed_analysis = CompletedAnalysis.model_construct( id=analysis_id, result=AnalysisResult.NOT_OK, robotType=robot_type, @@ -305,7 +305,9 @@ def get_summaries_by_protocol(self, protocol_id: str) -> List[AnalysisSummary]: protocol_id=protocol_id ) completed_analysis_summaries = [ - AnalysisSummary.construct(id=analysis_id, status=AnalysisStatus.COMPLETED) + AnalysisSummary.model_construct( + id=analysis_id, status=AnalysisStatus.COMPLETED + ) for analysis_id in completed_analysis_ids ] @@ -455,7 +457,7 @@ def add( protocol_id not in self._analysis_ids_by_protocol_id ), "Protocol must not already have a pending analysis." - new_pending_analysis = PendingAnalysis.construct( + new_pending_analysis = PendingAnalysis.model_construct( id=analysis_id, runTimeParameters=run_time_parameters, ) diff --git a/robot-server/robot_server/protocols/router.py b/robot-server/robot_server/protocols/router.py index ff6521b70d6..28294f99c7d 100644 --- a/robot-server/robot_server/protocols/router.py +++ b/robot-server/robot_server/protocols/router.py @@ -364,13 +364,13 @@ async def _get_cached_protocol_analysis() -> PydanticResponse[ status.HTTP_503_SERVICE_UNAVAILABLE ) from error - data = Protocol.construct( + data = Protocol.model_construct( id=cached_protocol_id, createdAt=resource.created_at, protocolKind=resource.protocol_kind, protocolType=resource.source.config.protocol_type, robotType=resource.source.robot_type, - metadata=Metadata.parse_obj(resource.source.metadata), + metadata=Metadata.model_validate(resource.source.metadata), analysisSummaries=analysis_summaries, key=resource.protocol_key, files=[ @@ -385,7 +385,7 @@ async def _get_cached_protocol_analysis() -> PydanticResponse[ ) return await PydanticResponse.create( - content=SimpleBody.construct(data=data), + content=SimpleBody.model_construct(data=data), # not returning a 201 because we're not actually creating a new resource status_code=status.HTTP_200_OK, ) @@ -443,7 +443,7 @@ async def _get_cached_protocol_analysis() -> PydanticResponse[ protocolKind=protocol_kind, protocolType=source.config.protocol_type, robotType=source.robot_type, - metadata=Metadata.parse_obj(source.metadata), + metadata=Metadata.model_validate(source.metadata), analysisSummaries=analysis_summaries, key=key, files=[ProtocolFile(name=f.path.name, role=f.role) for f in source.files], @@ -452,7 +452,7 @@ async def _get_cached_protocol_analysis() -> PydanticResponse[ log.info(f'Created protocol "{protocol_id}" and started analysis "{analysis_id}".') return await PydanticResponse.create( - content=SimpleBody.construct(data=data), + content=SimpleBody.model_construct(data=data), status_code=status.HTTP_201_CREATED, ) @@ -549,13 +549,13 @@ async def get_protocols( """ protocol_resources = protocol_store.get_all() data = [ - Protocol.construct( + Protocol.model_construct( id=r.protocol_id, createdAt=r.created_at, protocolKind=r.protocol_kind, protocolType=r.source.config.protocol_type, robotType=r.source.robot_type, - metadata=Metadata.parse_obj(r.source.metadata), + metadata=Metadata.model_validate(r.source.metadata), analysisSummaries=analysis_store.get_summaries_by_protocol(r.protocol_id), key=r.protocol_key, files=[ProtocolFile(name=f.path.name, role=f.role) for f in r.source.files], @@ -566,7 +566,7 @@ async def get_protocols( meta = MultiBodyMeta(cursor=0, totalLength=len(data)) return await PydanticResponse.create( - content=SimpleMultiBody.construct(data=data, meta=meta), + content=SimpleMultiBody.model_construct(data=data, meta=meta), status_code=status.HTTP_200_OK, ) @@ -597,7 +597,7 @@ async def get_protocol_ids( meta = MultiBodyMeta(cursor=0, totalLength=len(protocol_ids)) return await PydanticResponse.create( - content=SimpleMultiBody.construct(data=protocol_ids, meta=meta) + content=SimpleMultiBody.model_construct(data=protocol_ids, meta=meta) ) @@ -630,13 +630,13 @@ async def get_protocol_by_id( analyses = analysis_store.get_summaries_by_protocol(protocol_id=protocolId) referencing_run_ids = protocol_store.get_referencing_run_ids(protocolId) - data = Protocol.construct( + data = Protocol.model_construct( id=protocolId, createdAt=resource.created_at, protocolKind=resource.protocol_kind, protocolType=resource.source.config.protocol_type, robotType=resource.source.robot_type, - metadata=Metadata.parse_obj(resource.source.metadata), + metadata=Metadata.model_validate(resource.source.metadata), analysisSummaries=analyses, key=resource.protocol_key, files=[ @@ -644,15 +644,15 @@ async def get_protocol_by_id( ], ) - links = ProtocolLinks.construct( + links = ProtocolLinks.model_construct( referencingRuns=[ - RunLink.construct(id=run_id, href=f"/runs/{run_id}") + RunLink.model_construct(id=run_id, href=f"/runs/{run_id}") for run_id in referencing_run_ids ] ) return await PydanticResponse.create( - content=Body.construct( + content=Body.model_construct( data=data, links=links, ), @@ -690,7 +690,7 @@ async def delete_protocol_by_id( raise ProtocolUsedByRun(detail=str(e)).as_error(status.HTTP_409_CONFLICT) from e return await PydanticResponse.create( - content=SimpleEmptyBody.construct(), + content=SimpleEmptyBody.model_construct(), status_code=status.HTTP_200_OK, ) @@ -772,7 +772,7 @@ async def create_protocol_analysis( status.HTTP_503_SERVICE_UNAVAILABLE ) from error return await PydanticResponse.create( - content=SimpleMultiBody.construct( + content=SimpleMultiBody.model_construct( data=analysis_summaries, meta=MultiBodyMeta(cursor=0, totalLength=len(analysis_summaries)), ), @@ -813,7 +813,7 @@ async def get_protocol_analyses( analyses = await analysis_store.get_by_protocol(protocolId) return await PydanticResponse.create( - content=SimpleMultiBody.construct( + content=SimpleMultiBody.model_construct( data=analyses, meta=MultiBodyMeta(cursor=0, totalLength=len(analyses)), ) @@ -859,7 +859,9 @@ async def get_protocol_analysis_by_id( status.HTTP_404_NOT_FOUND ) from error - return await PydanticResponse.create(content=SimpleBody.construct(data=analysis)) + return await PydanticResponse.create( + content=SimpleBody.model_construct(data=analysis) + ) @protocols_router.get( @@ -951,7 +953,7 @@ async def get_protocol_data_files( data_files = await protocol_store.get_referenced_data_files(protocolId) return await PydanticResponse.create( - content=SimpleMultiBody.construct( + content=SimpleMultiBody.model_construct( data=data_files, meta=MultiBodyMeta(cursor=0, totalLength=len(data_files)) ) ) diff --git a/robot-server/robot_server/robot/control/router.py b/robot-server/robot_server/robot/control/router.py index 35910748115..a39e7fcab7e 100644 --- a/robot-server/robot_server/robot/control/router.py +++ b/robot-server/robot_server/robot/control/router.py @@ -29,12 +29,12 @@ async def _get_estop_status_response( estop_handler: EstopHandler, ) -> PydanticResponse[SimpleBody[EstopStatusModel]]: """Helper to generate the current Estop Status as a response model.""" - data = EstopStatusModel.construct( + data = EstopStatusModel.model_construct( status=estop_handler.get_state(), leftEstopPhysicalStatus=estop_handler.get_left_physical_status(), rightEstopPhysicalStatus=estop_handler.get_right_physical_status(), ) - return await PydanticResponse.create(content=SimpleBody.construct(data=data)) + return await PydanticResponse.create(content=SimpleBody.model_construct(data=data)) @PydanticResponse.wrap_route( @@ -91,8 +91,8 @@ async def get_door_status( door_required: Annotated[bool, Depends(get_door_switch_required)], ) -> PydanticResponse[SimpleBody[DoorStatusModel]]: return await PydanticResponse.create( - content=SimpleBody.construct( - data=DoorStatusModel.construct( + content=SimpleBody.model_construct( + data=DoorStatusModel.model_construct( status=DoorState.from_hw_physical_status(hardware.door_state), doorRequiredClosedForProtocol=door_required, ) diff --git a/robot-server/robot_server/runs/router/actions_router.py b/robot-server/robot_server/runs/router/actions_router.py index c7c24162cfb..80a461f3b59 100644 --- a/robot-server/robot_server/runs/router/actions_router.py +++ b/robot-server/robot_server/runs/router/actions_router.py @@ -155,6 +155,6 @@ async def create_run_action( raise RunNotFound.from_exc(e).as_error(status.HTTP_404_NOT_FOUND) from e return await PydanticResponse.create( - content=SimpleBody.construct(data=action), + content=SimpleBody.model_construct(data=action), status_code=status.HTTP_201_CREATED, ) diff --git a/robot-server/robot_server/runs/router/base_router.py b/robot-server/robot_server/runs/router/base_router.py index 4fb4be2b401..c51c02de1e4 100644 --- a/robot-server/robot_server/runs/router/base_router.py +++ b/robot-server/robot_server/runs/router/base_router.py @@ -288,7 +288,7 @@ async def create_run( # noqa: C901 log.info(f'Created protocol run "{run_id}" from protocol "{protocol_id}".') return await PydanticResponse.create( - content=SimpleBody.construct(data=run_data), + content=SimpleBody.model_construct(data=run_data), status_code=status.HTTP_201_CREATED, ) @@ -328,13 +328,13 @@ async def get_runs( current_run_id = run_data_manager.current_run_id meta = MultiBodyMeta(cursor=0, totalLength=len(data)) links = AllRunsLinks( - current=ResourceLink.construct(href=f"/runs/{current_run_id}") + current=ResourceLink.model_construct(href=f"/runs/{current_run_id}") if current_run_id is not None else None ) return await PydanticResponse.create( - content=MultiBody.construct(data=data, links=links, meta=meta), + content=MultiBody.model_construct(data=data, links=links, meta=meta), status_code=status.HTTP_200_OK, ) @@ -358,7 +358,7 @@ async def get_run( run_data: Data of the run specified in the runId url parameter. """ return await PydanticResponse.create( - content=SimpleBody.construct(data=run_data), + content=SimpleBody.model_construct(data=run_data), status_code=status.HTTP_200_OK, ) @@ -393,7 +393,7 @@ async def remove_run( raise RunNotFound(detail=str(e)).as_error(status.HTTP_404_NOT_FOUND) from e return await PydanticResponse.create( - content=SimpleEmptyBody.construct(), + content=SimpleEmptyBody.model_construct(), status_code=status.HTTP_200_OK, ) @@ -433,7 +433,7 @@ async def update_run( raise RunNotFound(detail=str(e)).as_error(status.HTTP_404_NOT_FOUND) from e return await PydanticResponse.create( - content=SimpleBody.construct(data=run_data), + content=SimpleBody.model_construct(data=run_data), status_code=status.HTTP_200_OK, ) @@ -509,7 +509,7 @@ async def get_run_commands_error( ) return await PydanticResponse.create( - content=SimpleMultiBody.construct( + content=SimpleMultiBody.model_construct( data=command_error_slice.commands_errors, meta=meta, ), @@ -554,7 +554,7 @@ async def get_current_state( # noqa: C901 active_nozzle_maps = run_data_manager.get_nozzle_maps(run_id=runId) nozzle_layouts = { - pipetteId: ActiveNozzleLayout.construct( + pipetteId: ActiveNozzleLayout.model_construct( startingNozzle=nozzle_map.starting_nozzle, activeNozzles=nozzle_map.active_nozzles, config=NozzleLayoutConfig(nozzle_map.configuration.value.lower()), @@ -563,7 +563,7 @@ async def get_current_state( # noqa: C901 } tip_states = { - pipette_id: TipState.construct(hasTip=has_tip) + pipette_id: TipState.model_construct(hasTip=has_tip) for pipette_id, has_tip in run_data_manager.get_tip_attached( run_id=runId ).items() @@ -625,8 +625,8 @@ async def get_current_state( # noqa: C901 break last_completed_command = run_data_manager.get_last_completed_command(run_id=runId) - links = CurrentStateLinks.construct( - lastCompleted=CommandLinkNoMeta.construct( + links = CurrentStateLinks.model_construct( + lastCompleted=CommandLinkNoMeta.model_construct( id=last_completed_command.command_id, href=f"/runs/{runId}/commands/{last_completed_command.command_id}", ) @@ -635,8 +635,8 @@ async def get_current_state( # noqa: C901 ) return await PydanticResponse.create( - content=Body.construct( - data=RunCurrentState.construct( + content=Body.model_construct( + data=RunCurrentState.model_construct( estopEngaged=estop_engaged, activeNozzleLayouts=nozzle_layouts, tipStates=tip_states, diff --git a/robot-server/robot_server/runs/router/commands_router.py b/robot-server/robot_server/runs/router/commands_router.py index 577606a1446..99828010750 100644 --- a/robot-server/robot_server/runs/router/commands_router.py +++ b/robot-server/robot_server/runs/router/commands_router.py @@ -221,7 +221,7 @@ async def create_run_command( # TODO(mc, 2022-05-26): increment the HTTP API version so that default # behavior is to pass through `command_intent` without overriding it command_intent = request_body.data.intent or pe_commands.CommandIntent.SETUP - command_create = request_body.data.copy(update={"intent": command_intent}) + command_create = request_body.data.model_copy(update={"intent": command_intent}) try: command = await run_orchestrator_store.add_command_and_wait_for_interval( @@ -241,7 +241,7 @@ async def create_run_command( response_data = run_orchestrator_store.get_command(command.id) return await PydanticResponse.create( - content=SimpleBody.construct(data=response_data), + content=SimpleBody.model_construct(data=response_data), status_code=status.HTTP_201_CREATED, ) @@ -315,7 +315,7 @@ async def get_run_commands( recovery_target_command = run_data_manager.get_recovery_target_command(run_id=runId) data = [ - RunCommandSummary.construct( + RunCommandSummary.model_construct( id=c.id, key=c.key, commandType=c.commandType, @@ -337,13 +337,13 @@ async def get_run_commands( totalLength=command_slice.total_length, ) - links = CommandCollectionLinks.construct( + links = CommandCollectionLinks.model_construct( current=_make_command_link(runId, current_command), currentlyRecoveringFrom=_make_command_link(runId, recovery_target_command), ) return await PydanticResponse.create( - content=MultiBody.construct(data=data, meta=meta, links=links), + content=MultiBody.model_construct(data=data, meta=meta, links=links), status_code=status.HTTP_200_OK, ) @@ -401,7 +401,7 @@ async def get_run_commands_as_pre_serialized_list( status.HTTP_503_SERVICE_UNAVAILABLE ) from e return await PydanticResponse.create( - content=SimpleMultiBody.construct( + content=SimpleMultiBody.model_construct( data=commands, meta=MultiBodyMeta(cursor=0, totalLength=len(commands)) ) ) @@ -442,7 +442,7 @@ async def get_run_command( raise CommandNotFound.from_exc(e).as_error(status.HTTP_404_NOT_FOUND) from e return await PydanticResponse.create( - content=SimpleBody.construct(data=command), + content=SimpleBody.model_construct(data=command), status_code=status.HTTP_200_OK, ) @@ -451,7 +451,7 @@ def _make_command_link( run_id: str, command_pointer: Optional[CommandPointer] ) -> Optional[CommandLink]: return ( - CommandLink.construct( + CommandLink.model_construct( href=f"/runs/{run_id}/commands/{command_pointer.command_id}", meta=CommandLinkMeta( runId=run_id, diff --git a/robot-server/robot_server/runs/router/error_recovery_policy_router.py b/robot-server/robot_server/runs/router/error_recovery_policy_router.py index 4653d564244..a5c3ae0543d 100644 --- a/robot-server/robot_server/runs/router/error_recovery_policy_router.py +++ b/robot-server/robot_server/runs/router/error_recovery_policy_router.py @@ -59,7 +59,7 @@ async def put_error_recovery_policy( raise RunStopped(detail=str(e)).as_error(status.HTTP_409_CONFLICT) from e return await PydanticResponse.create( - content=SimpleEmptyBody.construct(), + content=SimpleEmptyBody.model_construct(), status_code=status.HTTP_200_OK, ) @@ -90,8 +90,8 @@ async def get_error_recovery_policy( raise RunStopped(detail=str(e)).as_error(status.HTTP_409_CONFLICT) from e return await PydanticResponse.create( - content=SimpleBody.construct( - data=ErrorRecoveryPolicy.construct(policyRules=rules) + content=SimpleBody.model_construct( + data=ErrorRecoveryPolicy.model_construct(policyRules=rules) ), status_code=status.HTTP_200_OK, ) diff --git a/robot-server/robot_server/runs/router/labware_router.py b/robot-server/robot_server/runs/router/labware_router.py index 5d244e5438b..2a0396b3b86 100644 --- a/robot-server/robot_server/runs/router/labware_router.py +++ b/robot-server/robot_server/runs/router/labware_router.py @@ -70,7 +70,7 @@ async def add_labware_offset( log.info(f'Added labware offset "{added_offset.id}"' f' to run "{run.id}".') return await PydanticResponse.create( - content=SimpleBody.construct(data=added_offset), + content=SimpleBody.model_construct(data=added_offset), status_code=status.HTTP_201_CREATED, ) @@ -114,8 +114,8 @@ async def add_labware_definition( log.info(f'Added labware definition "{uri}"' f' to run "{run.id}".') return PydanticResponse( - content=SimpleBody.construct( - data=LabwareDefinitionSummary.construct(definitionUri=uri) + content=SimpleBody.model_construct( + data=LabwareDefinitionSummary.model_construct(definitionUri=uri) ), status_code=status.HTTP_201_CREATED, ) @@ -156,6 +156,6 @@ async def get_run_loaded_labware_definitions( raise RunStopped(detail=str(e)).as_error(status.HTTP_409_CONFLICT) from e return await PydanticResponse.create( - content=SimpleBody.construct(data=labware_definitions), + content=SimpleBody.model_construct(data=labware_definitions), status_code=status.HTTP_200_OK, ) diff --git a/robot-server/robot_server/runs/run_data_manager.py b/robot-server/robot_server/runs/run_data_manager.py index 9999e040523..fa937f7cb68 100644 --- a/robot-server/robot_server/runs/run_data_manager.py +++ b/robot-server/robot_server/runs/run_data_manager.py @@ -49,7 +49,7 @@ def _build_run( # such that this default summary object is not needed if run_resource.ok and isinstance(state_summary, StateSummary): - return Run.construct( + return Run.model_construct( id=run_resource.run_id, protocolId=run_resource.protocol_id, createdAt=run_resource.created_at, @@ -72,7 +72,7 @@ def _build_run( errors: List[EnumeratedError] = [] if isinstance(state_summary, BadStateSummary): - state = StateSummary.construct( + state = StateSummary.model_construct( status=EngineStatus.STOPPED, errors=[], labware=[], @@ -109,7 +109,7 @@ def _build_run( AssertionError("Logic error in parsing invalid run.") ) - return BadRun.construct( + return BadRun.model_construct( dataError=run_loading_error, id=run_resource.run_id, protocolId=run_resource.protocol_id, diff --git a/robot-server/robot_server/service/errors.py b/robot-server/robot_server/service/errors.py index 94a8d758563..8503b767258 100644 --- a/robot-server/robot_server/service/errors.py +++ b/robot-server/robot_server/service/errors.py @@ -79,7 +79,7 @@ def __init__( *wrapped_details, ), links=links, - ).dict(exclude_none=True) + ).model_dump(exclude_none=True) super().__init__( status_code=definition.status_code, diff --git a/robot-server/robot_server/service/json_api/response.py b/robot-server/robot_server/service/json_api/response.py index 0d2500b5297..9b815e75fbf 100644 --- a/robot-server/robot_server/service/json_api/response.py +++ b/robot-server/robot_server/service/json_api/response.py @@ -41,7 +41,7 @@ class BaseResponseBody(BaseModel): """ @override - def dict(self, *args: Any, **kwargs: Any) -> Dict[str, Any]: + def model_dump(self, *args: Any, **kwargs: Any) -> Dict[str, Any]: """Always exclude `None` when serializing to an object. With Pydantic v1, the OpenAPI spec described `Optional`(i.e., possibly @@ -56,13 +56,25 @@ def dict(self, *args: Any, **kwargs: Any) -> Dict[str, Any]: serialization behavior at this point would risk breaking things on the client. """ kwargs["exclude_none"] = True + return super().model_dump(*args, **kwargs) + + @override + def dict(self, *args: Any, **kwargs: Any) -> Dict[str, Any]: + """See notes in `model_dump()`.""" + kwargs["exclude_none"] = True return super().dict(*args, **kwargs) + @override + def model_dump_json(self, *args: Any, **kwargs: Any) -> str: + """See notes in `.model_dump()`.""" + kwargs["exclude_none"] = True + return super().model_dump_json(*args, **kwargs) + @override def json(self, *args: Any, **kwargs: Any) -> str: - """See notes in `.dict()`.""" + """See notes in `.model_dump()`.""" kwargs["exclude_none"] = True - return super().json(*args, **kwargs) + return super().model_dump_json(*args, **kwargs) class SimpleBody(BaseResponseBody, Generic[ResponseDataT]): @@ -112,8 +124,8 @@ class SimpleMultiBody(BaseResponseBody, Generic[ResponseDataT]): # non-validating classmethod is taken from the type of this member, and there we really # want the arguments to be Sequence so they can accept narrower subtypes. For instance, # if you define a function as returning SimpleMultiBody[Union[A, B]], you should really - # be able to do return SimpleMultiBody.construct([A(), A(), A()]) or even - # SimpleMultiBody[Union[A, B]].construct([A(), A(), A()]). However, because construct's + # be able to do return SimpleMultiBody.model_construct([A(), A(), A()]) or even + # SimpleMultiBody[Union[A, B]].model_construct([A(), A(), A()]). However, because construct's # params are defined based on the dataclass fields, the only way to get the arguments # to be covariant is to make data the covariant Sequence protocol. meta: MultiBodyMeta = Field( @@ -229,7 +241,7 @@ async def create( def render(self, content: ResponseBodyT) -> bytes: """Render the response body to JSON bytes.""" - return content.json().encode(self.charset) + return content.model_dump_json().encode(self.charset) # TODO(mc, 2021-12-09): remove this model diff --git a/robot-server/robot_server/service/legacy/routers/networking.py b/robot-server/robot_server/service/legacy/routers/networking.py index 3c9ea08be2c..ea3c4543ea8 100644 --- a/robot-server/robot_server/service/legacy/routers/networking.py +++ b/robot-server/robot_server/service/legacy/routers/networking.py @@ -190,7 +190,7 @@ async def post_wifi_key(key: UploadFile = File(...)): else: # We return a JSONResponse because we want the 200 status code. response.message = "Key file already present" - return JSONResponse(content=response.dict()) + return JSONResponse(content=response.model_dump()) @router.delete( @@ -274,4 +274,4 @@ async def post_wifi_disconnect(wifi_ssid: WifiNetwork): ) else: stat = status.HTTP_500_INTERNAL_SERVER_ERROR - return JSONResponse(status_code=stat, content=result.dict()) + return JSONResponse(status_code=stat, content=result.model_dump()) diff --git a/robot-server/robot_server/service/notifications/notification_client.py b/robot-server/robot_server/service/notifications/notification_client.py index 052bb272cf9..1727ee0c880 100644 --- a/robot-server/robot_server/service/notifications/notification_client.py +++ b/robot-server/robot_server/service/notifications/notification_client.py @@ -91,8 +91,8 @@ def publish_advise_refetch( Args: topic: The topic to publish the message on. """ - message = NotifyRefetchBody.construct() - payload = message.json() + message = NotifyRefetchBody.model_construct() + payload = message.model_dump_json() self._client.publish( topic=topic, payload=payload, @@ -109,8 +109,8 @@ def publish_advise_unsubscribe( Args: topic: The topic to publish the message on. """ - message = NotifyUnsubscribeBody.construct() - payload = message.json() + message = NotifyUnsubscribeBody.model_construct() + payload = message.model_dump_json() self._client.publish( topic=topic, payload=payload, diff --git a/robot-server/robot_server/service/session/command_execution/callable_executor.py b/robot-server/robot_server/service/session/command_execution/callable_executor.py index 39a62cbe3ae..2503ff952e3 100644 --- a/robot-server/robot_server/service/session/command_execution/callable_executor.py +++ b/robot-server/robot_server/service/session/command_execution/callable_executor.py @@ -26,7 +26,7 @@ async def execute(self, command: Command) -> CompletedCommand: with duration() as time_it: name_arg = command.request.command data = command.request.data - data_arg = data.dict() if data else {} + data_arg = data.model_dump() if data else {} await self._callable(name_arg, data_arg) diff --git a/robot-server/robot_server/service/session/router.py b/robot-server/robot_server/service/session/router.py index d950572ce8a..83f5a5578ab 100644 --- a/robot-server/robot_server/service/session/router.py +++ b/robot-server/robot_server/service/session/router.py @@ -169,7 +169,7 @@ async def session_command_execute_handler( log.debug(f"Command result: {command_result}") - return CommandResponse.construct( + return CommandResponse.model_construct( data=command_result, links=get_valid_session_links(sessionId, router) ) diff --git a/robot-server/robot_server/subsystems/router.py b/robot-server/robot_server/subsystems/router.py index e64e7390063..0ce265cc7e6 100644 --- a/robot-server/robot_server/subsystems/router.py +++ b/robot-server/robot_server/subsystems/router.py @@ -122,7 +122,7 @@ async def get_attached_subsystems( """Return all subsystems currently present on the machine.""" hardware = get_ot3_hardware(thread_manager) data = [ - PresentSubsystem.construct( + PresentSubsystem.model_construct( name=SubSystem.from_hw(subsystem_id), ok=subsystem_details.ok, current_fw_version=str(subsystem_details.current_fw_version), @@ -134,7 +134,7 @@ async def get_attached_subsystems( ] meta = MultiBodyMeta(cursor=0, totalLength=len(data)) return await PydanticResponse.create( - content=SimpleMultiBody.construct(data=data, meta=meta) + content=SimpleMultiBody.model_construct(data=data, meta=meta) ) @@ -164,8 +164,8 @@ async def get_attached_subsystem( status.HTTP_404_NOT_FOUND ) return await PydanticResponse.create( - content=SimpleBody.construct( - data=PresentSubsystem.construct( + content=SimpleBody.model_construct( + data=PresentSubsystem.model_construct( name=subsystem, ok=subsystem_status.ok, current_fw_version=str(subsystem_status.current_fw_version), @@ -197,7 +197,7 @@ async def get_subsystem_updates( """Return all currently-running firmware update process summaries.""" handles = await update_manager.all_ongoing_processes() data = [ - UpdateProgressSummary.construct( + UpdateProgressSummary.model_construct( id=handle.process_details.update_id, subsystem=handle.process_details.subsystem, updateStatus=handle.cached_state, @@ -207,7 +207,7 @@ async def get_subsystem_updates( ] meta = MultiBodyMeta(cursor=0, totalLength=len(data)) return await PydanticResponse.create( - content=SimpleMultiBody.construct(data=data, meta=meta) + content=SimpleMultiBody.model_construct(data=data, meta=meta) ) @@ -238,8 +238,8 @@ async def get_subsystem_update( ) from e progress = await handle.get_progress() return await PydanticResponse.create( - content=SimpleBody.construct( - data=UpdateProgressData.construct( + content=SimpleBody.model_construct( + data=UpdateProgressData.model_construct( id=handle.process_details.update_id, createdAt=handle.process_details.created_at, subsystem=handle.process_details.subsystem, @@ -282,7 +282,7 @@ async def get_update_processes( ] meta = MultiBodyMeta(cursor=0, totalLength=len(data)) return await PydanticResponse.create( - content=SimpleMultiBody.construct(data=data, meta=meta) + content=SimpleMultiBody.model_construct(data=data, meta=meta) ) @@ -306,8 +306,8 @@ async def get_update_process( raise IDNotFound(detail=id).as_error(status.HTTP_404_NOT_FOUND) from e progress = await handle.get_progress() return await PydanticResponse.create( - content=SimpleBody.construct( - data=UpdateProgressData.construct( + content=SimpleBody.model_construct( + data=UpdateProgressData.model_construct( id=handle.process_details.update_id, subsystem=handle.process_details.subsystem, createdAt=handle.process_details.created_at, @@ -375,8 +375,8 @@ async def begin_subsystem_update( ) progress = await summary.get_progress() return await PydanticResponse.create( - content=SimpleBody.construct( - data=UpdateProgressData.construct( + content=SimpleBody.model_construct( + data=UpdateProgressData.model_construct( id=summary.process_details.update_id, createdAt=summary.process_details.created_at, subsystem=subsystem, diff --git a/robot-server/tests/instruments/test_router.py b/robot-server/tests/instruments/test_router.py index fe401828284..9989d6b0409 100644 --- a/robot-server/tests/instruments/test_router.py +++ b/robot-server/tests/instruments/test_router.py @@ -212,7 +212,7 @@ async def rehearse_instrument_retrievals(skip_if_would_block: bool = False) -> N result = await get_attached_instruments(hardware=ot3_hardware_api) assert result.content.data == [ - Pipette.construct( + Pipette.model_construct( ok=True, mount="left", instrumentType="pipette", @@ -234,7 +234,7 @@ async def rehearse_instrument_retrievals(skip_if_would_block: bool = False) -> N ), state=PipetteState(tip_detected=True), ), - Pipette.construct( + Pipette.model_construct( ok=True, mount="right", firmwareVersion="11", @@ -256,7 +256,7 @@ async def rehearse_instrument_retrievals(skip_if_would_block: bool = False) -> N ), state=PipetteState(tip_detected=False), ), - Gripper.construct( + Gripper.model_construct( ok=True, mount="extension", firmwareVersion="11", @@ -305,7 +305,7 @@ async def test_get_ot2_instruments( decoy.verify(await ot2_hardware_api.cache_instruments(), times=0) assert result2.status_code == 200 assert result2.content.data == [ - Pipette.construct( + Pipette.model_construct( ok=True, mount="right", instrumentType="pipette", @@ -351,7 +351,7 @@ async def test_get_96_channel_instruments( decoy.when(ot3_hardware_api.get_instrument_offset(OT3Mount.RIGHT)).then_return(None) assert result2.status_code == 200 assert result2.content.data == [ - Pipette.construct( + Pipette.model_construct( ok=True, mount="left", instrumentType="pipette", diff --git a/robot-server/tests/maintenance_runs/router/test_labware_router.py b/robot-server/tests/maintenance_runs/router/test_labware_router.py index 4e5ae1152f2..d23204aa2d2 100644 --- a/robot-server/tests/maintenance_runs/router/test_labware_router.py +++ b/robot-server/tests/maintenance_runs/router/test_labware_router.py @@ -46,7 +46,7 @@ def run() -> MaintenanceRun: @pytest.fixture() def labware_definition(minimal_labware_def: LabwareDefDict) -> LabwareDefinition: """Create a labware definition fixture.""" - return LabwareDefinition.parse_obj(minimal_labware_def) + return LabwareDefinition.model_validate(minimal_labware_def) async def test_add_labware_offset( diff --git a/robot-server/tests/maintenance_runs/test_engine_store.py b/robot-server/tests/maintenance_runs/test_engine_store.py index bf01c653df1..ed9987f5e77 100644 --- a/robot-server/tests/maintenance_runs/test_engine_store.py +++ b/robot-server/tests/maintenance_runs/test_engine_store.py @@ -109,7 +109,7 @@ async def test_create_engine_with_labware_offsets( ) assert result.labwareOffsets == [ - pe_types.LabwareOffset.construct( + pe_types.LabwareOffset.model_construct( id=matchers.IsA(str), createdAt=matchers.IsA(datetime), definitionUri="namespace/load_name/version", diff --git a/robot-server/tests/modules/test_module_data_mapper.py b/robot-server/tests/modules/test_module_data_mapper.py index 62fa54e9a49..9fef6e607f4 100644 --- a/robot-server/tests/modules/test_module_data_mapper.py +++ b/robot-server/tests/modules/test_module_data_mapper.py @@ -138,7 +138,7 @@ def test_maps_magnetic_module_data( has_available_update=True, live_data=input_data, usb_port=hardware_usb_port, - module_offset=ModuleCalibrationData.construct( + module_offset=ModuleCalibrationData.model_construct( offset=Vec3f(x=0, y=0, z=0), ), ) @@ -213,7 +213,7 @@ def test_maps_temperature_module_data( has_available_update=True, live_data=input_data, usb_port=hardware_usb_port, - module_offset=ModuleCalibrationData.construct( + module_offset=ModuleCalibrationData.model_construct( offset=Vec3f(x=0, y=0, z=0), ), ) @@ -321,7 +321,7 @@ def test_maps_thermocycler_module_data( has_available_update=True, live_data=input_data, usb_port=hardware_usb_port, - module_offset=ModuleCalibrationData.construct( + module_offset=ModuleCalibrationData.model_construct( offset=Vec3f(x=0, y=0, z=0), ), ) @@ -426,7 +426,7 @@ def test_maps_heater_shaker_module_data( has_available_update=True, live_data=input_data, usb_port=hardware_usb_port, - module_offset=ModuleCalibrationData.construct( + module_offset=ModuleCalibrationData.model_construct( offset=Vec3f(x=0, y=0, z=0), ), ) diff --git a/robot-server/tests/modules/test_router.py b/robot-server/tests/modules/test_router.py index 287041f17cf..f63f46f7c27 100644 --- a/robot-server/tests/modules/test_router.py +++ b/robot-server/tests/modules/test_router.py @@ -99,7 +99,7 @@ async def test_get_modules_maps_data_and_id( hubPort=None, path="/dev/null", ), - moduleOffset=ModuleCalibrationData.construct( + moduleOffset=ModuleCalibrationData.model_construct( offset=Vec3f(x=0, y=0, z=0), ), data=MagneticModuleData( @@ -171,7 +171,7 @@ async def test_get_modules_maps_data_and_id( port_group=PortGroup.UNKNOWN, hub_port=None, ), - module_offset=ModuleCalibrationData.construct( + module_offset=ModuleCalibrationData.model_construct( offset=Vec3f( x=calibration_offset.offset.x, y=calibration_offset.offset.y, diff --git a/robot-server/tests/persistence/test_pydantic.py b/robot-server/tests/persistence/test_pydantic.py index 4e25b8c0fca..ea4ea1887a8 100644 --- a/robot-server/tests/persistence/test_pydantic.py +++ b/robot-server/tests/persistence/test_pydantic.py @@ -13,7 +13,7 @@ class _DummyModel(BaseModel): def test_round_trip() -> None: """Test Python->JSON->Python round trips.""" - original = _DummyModel.construct(field="hello", aliasedField="world") + original = _DummyModel.model_construct(field="hello", aliasedField="world") after_round_trip = subject.json_to_pydantic( _DummyModel, subject.pydantic_to_json(original) ) @@ -28,7 +28,7 @@ def test_round_trip() -> None: def test_field_aliases() -> None: """The JSON should contain field aliases, not the Python attribute names.""" - original = _DummyModel.construct(field="hello", aliasedField="world") + original = _DummyModel.model_construct(field="hello", aliasedField="world") json = subject.pydantic_to_json(original) json_list = subject.pydantic_list_to_json([original]) assert '"aliasedFieldAlias"' in json diff --git a/robot-server/tests/protocols/test_protocol_analyzer.py b/robot-server/tests/protocols/test_protocol_analyzer.py index 5f581afebb4..39f0feda73b 100644 --- a/robot-server/tests/protocols/test_protocol_analyzer.py +++ b/robot-server/tests/protocols/test_protocol_analyzer.py @@ -246,7 +246,7 @@ async def test_analyze_updates_pending_on_error( raised_exception = Exception("You got me!!") - error_occurrence = pe_errors.ErrorOccurrence.construct( + error_occurrence = pe_errors.ErrorOccurrence.model_construct( id="internal-error", createdAt=datetime(year=2023, month=3, day=3), errorType="EnumeratedError", diff --git a/robot-server/tests/protocols/test_protocols_router.py b/robot-server/tests/protocols/test_protocols_router.py index 0ae2c591ebd..56005162e93 100644 --- a/robot-server/tests/protocols/test_protocols_router.py +++ b/robot-server/tests/protocols/test_protocols_router.py @@ -392,7 +392,7 @@ async def test_get_protocol_by_id( key="dummy-key-111", ) - assert result.content.links == ProtocolLinks.construct(referencingRuns=[]) + assert result.content.links == ProtocolLinks.model_construct(referencingRuns=[]) assert result.status_code == 200 diff --git a/robot-server/tests/runs/router/test_base_router.py b/robot-server/tests/runs/router/test_base_router.py index 9cf42061faa..0350bb4d0b0 100644 --- a/robot-server/tests/runs/router/test_base_router.py +++ b/robot-server/tests/runs/router/test_base_router.py @@ -777,7 +777,7 @@ async def test_get_run_commands_errors_raises_no_run( @pytest.mark.parametrize( "error_list, expected_cursor_result", - [([], 0), ([pe_errors.ErrorOccurrence.construct(id="error-id")], 1)], + [([], 0), ([pe_errors.ErrorOccurrence.model_construct(id="error-id")], 1)], ) async def test_get_run_commands_errors_defualt_cursor( decoy: Decoy, @@ -865,7 +865,7 @@ async def test_get_current_state_success( ) assert result.status_code == 200 - assert result.content.data == RunCurrentState.construct( + assert result.content.data == RunCurrentState.model_construct( estopEngaged=False, activeNozzleLayouts={ "mock-pipette-id": ActiveNozzleLayout( diff --git a/robot-server/tests/runs/router/test_labware_router.py b/robot-server/tests/runs/router/test_labware_router.py index a81c6726e6d..25f80048df6 100644 --- a/robot-server/tests/runs/router/test_labware_router.py +++ b/robot-server/tests/runs/router/test_labware_router.py @@ -93,7 +93,7 @@ async def test_add_labware_offset_not_current( run: Run, ) -> None: """It should 409 if the run is not current.""" - not_current_run = run.copy(update={"current": False}) + not_current_run = run.model_copy(update={"current": False}) labware_offset_request = pe_types.LabwareOffsetCreate( definitionUri="namespace_1/load_name_1/123", @@ -142,7 +142,7 @@ async def test_add_labware_definition_not_current( labware_definition: LabwareDefinition, ) -> None: """It should 409 if the run is not current.""" - not_current_run = run.copy(update={"current": False}) + not_current_run = run.model_copy(update={"current": False}) with pytest.raises(ApiError) as exc_info: await add_labware_definition( diff --git a/robot-server/tests/runs/test_error_recovery_mapping.py b/robot-server/tests/runs/test_error_recovery_mapping.py index 0212fd0b6ed..6cab88243e3 100644 --- a/robot-server/tests/runs/test_error_recovery_mapping.py +++ b/robot-server/tests/runs/test_error_recovery_mapping.py @@ -116,9 +116,9 @@ def test_create_error_recovery_policy_defined_error( @pytest.mark.parametrize("enabled", [True, False]) def test_enabled_boolean(enabled: bool) -> None: """enabled=False should override any rules and always fail the run.""" - command = LiquidProbe.construct() + command = LiquidProbe.model_construct() # type: ignore[call-arg] error_data = DefinedErrorData[LiquidNotFoundError]( - public=LiquidNotFoundError.construct() + public=LiquidNotFoundError.model_construct() # type: ignore[call-arg] ) rules = [ @@ -160,9 +160,9 @@ def test_enabled_on_flex_disabled_on_ot2( robot_type: RobotType, expect_error_recovery_to_be_enabled: bool ) -> None: """On OT-2s, the run should always fail regardless of any input rules.""" - command = LiquidProbe.construct() + command = LiquidProbe.model_construct() # type: ignore[call-arg] error_data = DefinedErrorData[LiquidNotFoundError]( - public=LiquidNotFoundError.construct() + public=LiquidNotFoundError.model_construct() # type: ignore[call-arg] ) rules = [ diff --git a/robot-server/tests/runs/test_run_data_manager.py b/robot-server/tests/runs/test_run_data_manager.py index 31b58f9950a..8d139b4edff 100644 --- a/robot-server/tests/runs/test_run_data_manager.py +++ b/robot-server/tests/runs/test_run_data_manager.py @@ -967,7 +967,7 @@ def test_get_commands_errors_slice_historical_run( mock_run_store: RunStore, ) -> None: """Should get a sliced command error list from engine store.""" - expected_commands_errors_result = [ErrorOccurrence.construct(id="error-id")] + expected_commands_errors_result = [ErrorOccurrence.model_construct(id="error-id")] # type: ignore[call-arg] command_error_slice = CommandErrorSlice( cursor=1, total_length=3, commands_errors=expected_commands_errors_result diff --git a/robot-server/tests/runs/test_run_orchestrator_store.py b/robot-server/tests/runs/test_run_orchestrator_store.py index 1774215acfd..b0f8354e494 100644 --- a/robot-server/tests/runs/test_run_orchestrator_store.py +++ b/robot-server/tests/runs/test_run_orchestrator_store.py @@ -120,7 +120,7 @@ async def test_create_engine_with_labware_offsets( ) assert result.labwareOffsets == [ - pe_types.LabwareOffset.construct( + pe_types.LabwareOffset.model_construct( id=matchers.IsA(str), createdAt=matchers.IsA(datetime), definitionUri="namespace/load_name/version", diff --git a/robot-server/tests/runs/test_run_store.py b/robot-server/tests/runs/test_run_store.py index cfbe89a44e4..400e5ef6a06 100644 --- a/robot-server/tests/runs/test_run_store.py +++ b/robot-server/tests/runs/test_run_store.py @@ -122,7 +122,7 @@ def protocol_commands_errors() -> List[pe_commands.Command]: params=pe_commands.WaitForResumeParams(message="hello world"), result=pe_commands.WaitForResumeResult(), intent=pe_commands.CommandIntent.PROTOCOL, - error=ErrorOccurrence.construct( + error=ErrorOccurrence.model_construct( id="error-id", createdAt=datetime(2024, 1, 1), errorType="blah-blah", @@ -137,7 +137,7 @@ def protocol_commands_errors() -> List[pe_commands.Command]: params=pe_commands.WaitForResumeParams(message="hey world"), result=pe_commands.WaitForResumeResult(), intent=pe_commands.CommandIntent.PROTOCOL, - error=ErrorOccurrence.construct( + error=ErrorOccurrence.model_construct( id="error-id-2", createdAt=datetime(2024, 1, 1), errorType="blah-blah", @@ -738,7 +738,7 @@ def test_get_run_time_parameters_invalid( state_summary: StateSummary, ) -> None: """It should return an empty list if there invalid parameters.""" - bad_parameters = [pe_types.BooleanParameter.construct(foo="bar")] + bad_parameters = [pe_types.BooleanParameter.model_construct(foo="bar")] # type: ignore[call-arg] subject.insert( run_id="run-id", protocol_id=None, diff --git a/robot-server/tests/service/json_api/test_request.py b/robot-server/tests/service/json_api/test_request.py index 71cd3d0cbcc..8c2012b158b 100644 --- a/robot-server/tests/service/json_api/test_request.py +++ b/robot-server/tests/service/json_api/test_request.py @@ -9,22 +9,22 @@ def test_attributes_as_dict(): DictRequest = RequestModel[dict] obj_to_validate = {"data": {"some_data": 1}} - my_request_obj = DictRequest.parse_obj(obj_to_validate) - assert my_request_obj.dict() == {"data": {"some_data": 1}} + my_request_obj = DictRequest.model_validate(obj_to_validate) + assert my_request_obj.model_dump() == {"data": {"some_data": 1}} def test_attributes_as_item_model(): ItemRequest = RequestModel[ItemModel] obj_to_validate = {"data": {"name": "apple", "quantity": 10, "price": 1.20}} - my_request_obj = ItemRequest.parse_obj(obj_to_validate) - assert my_request_obj.dict() == obj_to_validate + my_request_obj = ItemRequest.model_validate(obj_to_validate) + assert my_request_obj.model_dump() == obj_to_validate def test_attributes_as_item_model_empty_dict(): ItemRequest = RequestModel[ItemModel] obj_to_validate: Dict[str, Any] = {"data": {}} with raises(ValidationError) as e: - ItemRequest.parse_obj(obj_to_validate) + ItemRequest.model_validate(obj_to_validate) assert e.value.errors() == [ { @@ -55,7 +55,7 @@ def test_attributes_required(): MyRequest = RequestModel[dict] obj_to_validate = {"data": None} with raises(ValidationError) as e: - MyRequest.parse_obj(obj_to_validate) + MyRequest.model_validate(obj_to_validate) assert e.value.errors() == [ { @@ -72,7 +72,7 @@ def test_data_required(): MyRequest = RequestModel[dict] obj_to_validate = {"data": None} with raises(ValidationError) as e: - MyRequest.parse_obj(obj_to_validate) + MyRequest.model_validate(obj_to_validate) assert e.value.errors() == [ { @@ -90,7 +90,7 @@ def test_request_with_id(): obj_to_validate = { "data": {"type": "item", "attributes": {}, "id": "abc123"}, } - my_request_obj = MyRequest.parse_obj(obj_to_validate) - assert my_request_obj.dict() == { + my_request_obj = MyRequest.model_validate(obj_to_validate) + assert my_request_obj.model_dump() == { "data": {"type": "item", "attributes": {}, "id": "abc123"}, } diff --git a/robot-server/tests/service/json_api/test_resource_links.py b/robot-server/tests/service/json_api/test_resource_links.py index 804fa77b837..581c018892a 100644 --- a/robot-server/tests/service/json_api/test_resource_links.py +++ b/robot-server/tests/service/json_api/test_resource_links.py @@ -14,8 +14,8 @@ def test_follows_structure(): "self": {"href": "/items/1", "meta": None}, } } - validated = ThingWithLink.parse_obj(structure_to_validate) - assert validated.dict() == structure_to_validate + validated = ThingWithLink.model_validate(structure_to_validate) + assert validated.model_dump() == structure_to_validate def test_must_be_self_key_with_string_value(): @@ -25,7 +25,7 @@ def test_must_be_self_key_with_string_value(): } } with raises(ValidationError) as e: - ThingWithLink.parse_obj(invalid_structure_to_validate) + ThingWithLink.model_validate(invalid_structure_to_validate) assert e.value.errors() == [ { "loc": ("links",), diff --git a/robot-server/tests/service/json_api/test_response.py b/robot-server/tests/service/json_api/test_response.py index 6952468229b..05e01f45b6c 100644 --- a/robot-server/tests/service/json_api/test_response.py +++ b/robot-server/tests/service/json_api/test_response.py @@ -126,4 +126,4 @@ class ResponseSpec(NamedTuple): @pytest.mark.parametrize(ResponseSpec._fields, RESPONSE_SPECS) def test_response_to_dict(subject: BaseModel, expected: Dict[str, Any]) -> None: - assert subject.dict() == expected + assert subject.model_dump() == expected diff --git a/robot-server/tests/service/session/models/test_command.py b/robot-server/tests/service/session/models/test_command.py index 67d99f409ac..695638262a4 100644 --- a/robot-server/tests/service/session/models/test_command.py +++ b/robot-server/tests/service/session/models/test_command.py @@ -15,7 +15,7 @@ ) def test_empty(command_def: command_definitions.CommandDefinition): """Test creation of empty command request and response.""" - request = command.CommandRequest.parse_obj( + request = command.CommandRequest.model_validate( {"data": {"command": command_def.value, "data": {}}} ) assert request.data.command == command_def @@ -57,6 +57,6 @@ def test_empty(command_def: command_definitions.CommandDefinition): def test_requires_data(command_def: command_definitions.CommandDefinition): """Test creation of command requiring data will fail with empty body.""" with pytest.raises(ValidationError): - command.CommandRequest.parse_obj( + command.CommandRequest.model_validate( {"data": {"command": command_def.value, "data": {}}} ) diff --git a/robot-server/tests/subsystems/test_router.py b/robot-server/tests/subsystems/test_router.py index a5fb9f86ca6..8b6357a0c1e 100644 --- a/robot-server/tests/subsystems/test_router.py +++ b/robot-server/tests/subsystems/test_router.py @@ -104,7 +104,7 @@ def _build_attached_subsystems( def _build_subsystem_data( subsystem: SubSystem, state: SubSystemState ) -> PresentSubsystem: - return PresentSubsystem.construct( + return PresentSubsystem.model_construct( name=subsystem, ok=state.ok, current_fw_version=str(state.current_fw_version), @@ -230,25 +230,25 @@ async def test_get_subsystem_updates_with_some( response = await get_subsystem_updates(update_manager) assert response.content.data == [ - UpdateProgressSummary.construct( + UpdateProgressSummary.model_construct( id=x_process_details.update_id, createdAt=x_process_details.created_at, subsystem=x_process_details.subsystem, updateStatus=x_state, ), - UpdateProgressSummary.construct( + UpdateProgressSummary.model_construct( id=y_process_details.update_id, createdAt=y_process_details.created_at, subsystem=y_process_details.subsystem, updateStatus=y_state, ), - UpdateProgressSummary.construct( + UpdateProgressSummary.model_construct( id=head_process_details.update_id, createdAt=head_process_details.created_at, subsystem=head_process_details.subsystem, updateStatus=head_state, ), - UpdateProgressSummary.construct( + UpdateProgressSummary.model_construct( id=pipette_process_details.update_id, createdAt=pipette_process_details.created_at, subsystem=pipette_process_details.subsystem, @@ -284,7 +284,7 @@ async def test_get_subsystem_update_succeeds( await update_manager.get_ongoing_update_process_handle_by_subsystem(subsystem) ).then_return(handle) response = await get_subsystem_update(subsystem, update_manager) - assert response.content.data == UpdateProgressData.construct( + assert response.content.data == UpdateProgressData.model_construct( id=details.update_id, createdAt=details.created_at, subsystem=details.subsystem, @@ -329,7 +329,7 @@ async def test_get_subsystem_update_error( await update_manager.get_ongoing_update_process_handle_by_subsystem(subsystem) ).then_return(handle) response = await get_subsystem_update(subsystem, update_manager) - assert response.content.data == UpdateProgressData.construct( + assert response.content.data == UpdateProgressData.model_construct( id=details.update_id, createdAt=details.created_at, subsystem=details.subsystem, @@ -386,25 +386,25 @@ async def test_get_all_updates_some( ) response = await get_update_processes(update_manager) assert response.content.data == [ - UpdateProgressSummary.construct( + UpdateProgressSummary.model_construct( id=x_process_details.update_id, createdAt=x_process_details.created_at, subsystem=x_process_details.subsystem, updateStatus=x_state, ), - UpdateProgressSummary.construct( + UpdateProgressSummary.model_construct( id=y_process_details.update_id, createdAt=y_process_details.created_at, subsystem=y_process_details.subsystem, updateStatus=y_state, ), - UpdateProgressSummary.construct( + UpdateProgressSummary.model_construct( id=head_process_details.update_id, createdAt=head_process_details.created_at, subsystem=head_process_details.subsystem, updateStatus=head_state, ), - UpdateProgressSummary.construct( + UpdateProgressSummary.model_construct( id=pipette_process_details.update_id, createdAt=pipette_process_details.created_at, subsystem=pipette_process_details.subsystem, @@ -526,7 +526,7 @@ async def test_begin_update( headers["Location"] == f"http://127.0.0.1:31950/subsystems/updates/current/{subsystem.value}" ) - assert response_data.content.data == UpdateProgressData.construct( + assert response_data.content.data == UpdateProgressData.model_construct( id=update_id, createdAt=created_at, subsystem=subsystem, diff --git a/server-utils/pytest.ini b/server-utils/pytest.ini index 49f04412746..a2cc2091144 100644 --- a/server-utils/pytest.ini +++ b/server-utils/pytest.ini @@ -1,3 +1,9 @@ [pytest] addopts = --color=yes --strict-markers asyncio_mode = auto + +filterwarnings = + # Pydantic's shims for its legacy v1 methods (e.g. `BaseModel.construct()`) + # are not type-checked properly. Forbid them, so we're forced to use their newer + # v2 replacements which are type-checked (e.g. ``BaseModel.model_construct()`) + error::pydantic.PydanticDeprecatedSince20 diff --git a/shared-data/python/opentrons_shared_data/gripper/__init__.py b/shared-data/python/opentrons_shared_data/gripper/__init__.py index c9ee59543b6..ab5ab38af72 100644 --- a/shared-data/python/opentrons_shared_data/gripper/__init__.py +++ b/shared-data/python/opentrons_shared_data/gripper/__init__.py @@ -45,7 +45,7 @@ def load_definition( """Load gripper definition based on schema version and gripper model.""" try: path = Path("gripper") / "definitions" / f"{version}" / f"{model.value}.json" - return GripperDefinition.parse_obj(json.loads(load_shared_data(path))) + return GripperDefinition.model_validate(json.loads(load_shared_data(path))) except FileNotFoundError: raise InvalidGripperDefinition( f"Gripper model {model} definition in schema version {version} does not exist." diff --git a/shared-data/python/opentrons_shared_data/liquid_classes/__init__.py b/shared-data/python/opentrons_shared_data/liquid_classes/__init__.py index b5da3d7ba52..1b8458adf25 100644 --- a/shared-data/python/opentrons_shared_data/liquid_classes/__init__.py +++ b/shared-data/python/opentrons_shared_data/liquid_classes/__init__.py @@ -1,5 +1,4 @@ """Types and functions for accessing liquid class definitions.""" -import json from .. import load_shared_data from .liquid_class_definition import LiquidClassSchemaV1 @@ -18,10 +17,8 @@ def load_definition(name: str, version: int = DEFAULT_VERSION) -> LiquidClassSch Note: this is an expensive operation and should be called sparingly. """ try: - return LiquidClassSchemaV1.parse_obj( - json.loads( - load_shared_data(f"liquid-class/definitions/{version}/{name}.json") - ) + return LiquidClassSchemaV1.model_validate_json( + load_shared_data(f"liquid-class/definitions/{version}/{name}.json") ) except FileNotFoundError: raise LiquidClassDefinitionDoesNotExist( diff --git a/shared-data/python/opentrons_shared_data/pipette/load_data.py b/shared-data/python/opentrons_shared_data/pipette/load_data.py index 40027d54394..66ba690356a 100644 --- a/shared-data/python/opentrons_shared_data/pipette/load_data.py +++ b/shared-data/python/opentrons_shared_data/pipette/load_data.py @@ -155,7 +155,7 @@ def load_liquid_model( ) -> Dict[str, PipetteLiquidPropertiesDefinition]: liquid_dict = _liquid(channels, model, version) return { - k: PipetteLiquidPropertiesDefinition.parse_obj(v) + k: PipetteLiquidPropertiesDefinition.model_validate(v) for k, v in liquid_dict.items() } @@ -213,7 +213,7 @@ def update_pipette_configuration( Given an input of v1 mutable configs, look up the equivalent keyed value of that configuration.""" quirks_list = [] - dict_of_base_model = base_configurations.dict(by_alias=True) + dict_of_base_model = base_configurations.model_dump(by_alias=True) for c, v in v1_configuration_changes.items(): lookup_key = _change_to_camel_case(c) @@ -245,7 +245,7 @@ def update_pipette_configuration( k.name: v for k, v in dict_of_base_model["plungerPositionsConfigurations"].items() } - return PipetteConfigurations.parse_obj(dict_of_base_model) + return PipetteConfigurations.model_validate(dict_of_base_model) def load_definition( @@ -266,7 +266,7 @@ def load_definition( generation = PipetteGenerationType(physical_dict["displayCategory"]) mount_configs = MOUNT_CONFIG_LOOKUP_TABLE[generation][channels] - return PipetteConfigurations.parse_obj( + return PipetteConfigurations.model_validate( { **geometry_dict, **physical_dict, @@ -289,4 +289,4 @@ def load_valid_nozzle_maps( raise KeyError("Pipette version not found.") physical_dict = _physical(channels, model, version) - return ValidNozzleMaps.parse_obj(physical_dict["validNozzleMaps"]) + return ValidNozzleMaps.model_validate(physical_dict["validNozzleMaps"]) diff --git a/shared-data/python/opentrons_shared_data/pipette/mutable_configurations.py b/shared-data/python/opentrons_shared_data/pipette/mutable_configurations.py index 7e1beb5dd35..23943ef9082 100644 --- a/shared-data/python/opentrons_shared_data/pipette/mutable_configurations.py +++ b/shared-data/python/opentrons_shared_data/pipette/mutable_configurations.py @@ -80,7 +80,7 @@ def _migrate_to_v2_configurations( Given an input of v1 mutable configs, look up the equivalent keyed value of that configuration.""" quirks_list = [] - dict_of_base_model = base_configurations.dict(by_alias=True) + dict_of_base_model = base_configurations.model_dump(by_alias=True) for c, v in v1_mutable_configs.items(): if isinstance(v, str): # ignore the saved model @@ -112,7 +112,7 @@ def _migrate_to_v2_configurations( k.name: v for k, v in dict_of_base_model["plungerPositionsConfigurations"].items() } - return PipetteConfigurations.parse_obj(dict_of_base_model) + return PipetteConfigurations.model_validate(dict_of_base_model) def _load_available_overrides( @@ -239,7 +239,7 @@ def _load_full_mutable_configs( pipette_model.pipette_channels, pipette_model.pipette_version, ) - base_configs_dict = base_configs.dict(by_alias=True) + base_configs_dict = base_configs.model_dump(by_alias=True) full_mutable_configs = _list_all_mutable_configs(overrides, base_configs_dict) if not full_mutable_configs.get("name"): @@ -432,7 +432,7 @@ def save_overrides( pipette_model.pipette_channels, pipette_model.pipette_version, ) - base_configs_dict = base_configs.dict(by_alias=True) + base_configs_dict = base_configs.model_dump(by_alias=True) try: existing_overrides = _load_available_overrides( pipette_serial_number, pipette_override_path diff --git a/shared-data/python/opentrons_shared_data/pipette/scripts/build_json_script.py b/shared-data/python/opentrons_shared_data/pipette/scripts/build_json_script.py index 510d0ae5251..e3631d04669 100644 --- a/shared-data/python/opentrons_shared_data/pipette/scripts/build_json_script.py +++ b/shared-data/python/opentrons_shared_data/pipette/scripts/build_json_script.py @@ -138,7 +138,7 @@ def _build_partial_tip_configurations(channels: int) -> PartialTipDefinition: def build_geometry_model_v2( input_dictionary: Dict[str, Any] ) -> PipetteGeometryDefinition: - return PipetteGeometryDefinition.parse_obj(input_dictionary) + return PipetteGeometryDefinition.model_validate(input_dictionary) def build_liquid_model_v2( @@ -147,11 +147,11 @@ def build_liquid_model_v2( ) -> PipetteLiquidPropertiesDefinition: if input_dictionary: if input_dictionary.get("partialTipConfigurations"): - return PipetteLiquidPropertiesDefinition.parse_obj( + return PipetteLiquidPropertiesDefinition.model_validate( {**input_dictionary, "supportedTips": supported_tip_configurations} ) else: - return PipetteLiquidPropertiesDefinition.parse_obj( + return PipetteLiquidPropertiesDefinition.model_validate( { **input_dictionary, "supportedTips": supported_tip_configurations, @@ -163,7 +163,7 @@ def build_liquid_model_v2( "please input the load names of default tipracks separated by commas\n" ) list_default_tipracks = default_tipracks.split(",") - return PipetteLiquidPropertiesDefinition.parse_obj( + return PipetteLiquidPropertiesDefinition.model_validate( { "supportedTips": supported_tip_configurations, "maxVolume": max_volume, @@ -181,7 +181,7 @@ def build_physical_model_v2( sensors=input_dictionary.pop("availableSensors", []) ) back_compat_names = input_dictionary.pop("backCompatNames", []) - return PipettePhysicalPropertiesDefinition.parse_obj( + return PipettePhysicalPropertiesDefinition.model_validate( { **input_dictionary, "availableSensors": available_sensors, @@ -213,7 +213,7 @@ def build_physical_model_v2( back_compat_names = [i.strip() for i in back_compat_names_str.split(",")] else: back_compat_names = [] - return PipettePhysicalPropertiesDefinition.parse_obj( + return PipettePhysicalPropertiesDefinition.model_validate( { "displayName": display_name, "model": pipette_type, @@ -235,7 +235,7 @@ def build_physical_model_v2( def build_supported_tips(input_dictionary: Dict[str, Any]) -> SupportedTipsDefinition: - return SupportedTipsDefinition.parse_obj(input_dictionary) + return SupportedTipsDefinition.model_validate(input_dictionary) def save_to_file( @@ -332,7 +332,7 @@ def build_new_pipette_model_v2( top_level_pipette_model["liquid"], pipette_functions_dict, ) - liquid_model_dict = liquid_model.dict(by_alias=True) + liquid_model_dict = liquid_model.model_dump(by_alias=True) liquid_model_dict["supportedTips"] = { k.name: v for k, v in liquid_model_dict["supportedTips"].items() } diff --git a/shared-data/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py b/shared-data/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py index 740504501b0..2c8a13a3e17 100644 --- a/shared-data/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py +++ b/shared-data/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py @@ -218,7 +218,7 @@ def load_and_update_file_from_config( geometry["nozzleOffset"] = value_to_update else: geometry = update(geometry, camel_list_to_update, value_to_update) - PipetteGeometryDefinition.parse_obj(geometry) + PipetteGeometryDefinition.model_validate(geometry) filepath = ( ROOT @@ -240,7 +240,7 @@ def load_and_update_file_from_config( physical = update(physical, camel_list_to_update, value_to_update) - PipettePhysicalPropertiesDefinition.parse_obj(physical) + PipettePhysicalPropertiesDefinition.model_validate(physical) filepath = ( ROOT / "general" @@ -274,7 +274,7 @@ def load_and_update_file_from_config( liquid[c.name.lower()], camel_list_to_update, value_to_update ) - PipetteLiquidPropertiesDefinition.parse_obj(liquid) + PipetteLiquidPropertiesDefinition.model_validate(liquid) filepath = ( ROOT / "liquid" @@ -292,7 +292,7 @@ def load_and_update_file_from_config( liquid = update( liquid[lc.name.lower()], camel_list_to_update, value_to_update ) - PipetteLiquidPropertiesDefinition.parse_obj(liquid) + PipetteLiquidPropertiesDefinition.model_validate(liquid) filepath = ( ROOT diff --git a/shared-data/python/pytest.ini b/shared-data/python/pytest.ini index e552559af25..588979766ed 100644 --- a/shared-data/python/pytest.ini +++ b/shared-data/python/pytest.ini @@ -1,2 +1,8 @@ [pytest] addopts = --color=yes --strict-markers + +filterwarnings = + # Pydantic's shims for its legacy v1 methods (e.g. `BaseModel.construct()`) + # are not type-checked properly. Forbid them, so we're forced to use their newer + # v2 replacements which are type-checked (e.g. ``BaseModel.model_construct()`) + error::pydantic.PydanticDeprecatedSince20 diff --git a/shared-data/python/tests/gripper/test_definition.py b/shared-data/python/tests/gripper/test_definition.py index 6cbfbc77fd5..3128531b95f 100644 --- a/shared-data/python/tests/gripper/test_definition.py +++ b/shared-data/python/tests/gripper/test_definition.py @@ -17,14 +17,14 @@ def test_gripper_definition() -> None: def test_gripper_definition_type() -> None: - assert GripperDefinition.parse_obj(GRIPPER_DEF) + assert GripperDefinition.model_validate(GRIPPER_DEF) # missing key del GRIPPER_DEF["gripForceProfile"] with pytest.raises(ValidationError): - assert GripperDefinition.parse_obj(GRIPPER_DEF) + assert GripperDefinition.model_validate(GRIPPER_DEF) # no missing key but with incorrect value GRIPPER_DEF["geometry"]["gripForceProfile"] = {"min": 1.0, "max": "0.0"} with pytest.raises(ValidationError): - assert GripperDefinition.parse_obj(GRIPPER_DEF) + assert GripperDefinition.model_validate(GRIPPER_DEF) diff --git a/shared-data/python/tests/labware/test_validations.py b/shared-data/python/tests/labware/test_validations.py index 39052e5d150..b4d06a40e1d 100644 --- a/shared-data/python/tests/labware/test_validations.py +++ b/shared-data/python/tests/labware/test_validations.py @@ -11,11 +11,11 @@ def test_loadname_regex_applied() -> None: defdict = load_definition(*get_ot_defs()[0]) defdict["parameters"]["loadName"] = "ALSJHDAKJLA" with pytest.raises(ValidationError): - LabwareDefinition.parse_obj(defdict) + LabwareDefinition.model_validate(defdict) def test_namespace_regex_applied() -> None: defdict = load_definition(*get_ot_defs()[0]) defdict["namespace"] = "ALSJHDAKJLA" with pytest.raises(ValidationError): - LabwareDefinition.parse_obj(defdict) + LabwareDefinition.model_validate(defdict) diff --git a/shared-data/python/tests/liquid_classes/test_load.py b/shared-data/python/tests/liquid_classes/test_load.py index c8bf7b25244..d0d96fd00fe 100644 --- a/shared-data/python/tests/liquid_classes/test_load.py +++ b/shared-data/python/tests/liquid_classes/test_load.py @@ -14,9 +14,9 @@ def test_load_liquid_class_schema_v1() -> None: fixture_data = load_shared_data("liquid-class/definitions/1/water.json") - liquid_class_model = LiquidClassSchemaV1.parse_raw(fixture_data) + liquid_class_model = LiquidClassSchemaV1.model_validate_json(fixture_data) liquid_class_def_from_model = json.loads( - liquid_class_model.json(exclude_unset=True) + liquid_class_model.model_dump_json(exclude_unset=True) ) expected_liquid_class_def = json.loads(fixture_data) assert liquid_class_def_from_model == expected_liquid_class_def diff --git a/shared-data/python/tests/pipette/test_load_data.py b/shared-data/python/tests/pipette/test_load_data.py index 012aed7baca..386af05de5b 100644 --- a/shared-data/python/tests/pipette/test_load_data.py +++ b/shared-data/python/tests/pipette/test_load_data.py @@ -90,7 +90,7 @@ def test_update_pipette_configuration( base_configurations, v1_configuration_changes, liquid_class ) - updated_configurations_dict = updated_configurations.dict() + updated_configurations_dict = updated_configurations.model_dump() for k, v in v1_configuration_changes.items(): if k == "tip_length": for i in updated_configurations_dict["liquid_properties"][liquid_class][ diff --git a/shared-data/python/tests/pipette/test_mutable_configurations.py b/shared-data/python/tests/pipette/test_mutable_configurations.py index 38920c473e8..d7a6c8ed1db 100644 --- a/shared-data/python/tests/pipette/test_mutable_configurations.py +++ b/shared-data/python/tests/pipette/test_mutable_configurations.py @@ -272,7 +272,7 @@ def test_load_with_overrides( ) if serial_number == TEST_SERIAL_NUMBER: - dict_loaded_configs = loaded_base_configurations.dict(by_alias=True) + dict_loaded_configs = loaded_base_configurations.model_dump(by_alias=True) for map_key in dict_loaded_configs["pickUpTipConfigurations"]["pressFit"][ "configurationsByNozzleMap" ]: @@ -283,7 +283,7 @@ def test_load_with_overrides( "configurationsByNozzleMap" ][map_key][tip_key]["speed"] = 5.0 - updated_configurations_dict = updated_configurations.dict(by_alias=True) + updated_configurations_dict = updated_configurations.model_dump(by_alias=True) assert set(dict_loaded_configs.pop("quirks")) == set( updated_configurations_dict.pop("quirks") ) diff --git a/shared-data/python/tests/pipette/test_pipette_definition.py b/shared-data/python/tests/pipette/test_pipette_definition.py index 9fd134ec059..2d5e2aec87a 100644 --- a/shared-data/python/tests/pipette/test_pipette_definition.py +++ b/shared-data/python/tests/pipette/test_pipette_definition.py @@ -19,10 +19,10 @@ def get_liquid_definition_for( liquid_class: LiquidClasses, ) -> PipetteLiquidPropertiesDefinition: if liquid_class == LiquidClasses.lowVolumeDefault: - return PipetteLiquidPropertiesDefinition.parse_obj( + return PipetteLiquidPropertiesDefinition.model_validate( { "supportedTips": { - "t50": SupportedTipsDefinition.parse_obj( + "t50": SupportedTipsDefinition.model_validate( { "defaultAspirateFlowRate": { "default": 5, @@ -52,10 +52,10 @@ def get_liquid_definition_for( } ) else: - return PipetteLiquidPropertiesDefinition.parse_obj( + return PipetteLiquidPropertiesDefinition.model_validate( { "supportedTips": { - "t50": SupportedTipsDefinition.parse_obj( + "t50": SupportedTipsDefinition.model_validate( { "defaultAspirateFlowRate": { "default": 5, diff --git a/shared-data/python/tests/pipette/test_validate_schema.py b/shared-data/python/tests/pipette/test_validate_schema.py index a29d59f4eda..a002c38cfb2 100644 --- a/shared-data/python/tests/pipette/test_validate_schema.py +++ b/shared-data/python/tests/pipette/test_validate_schema.py @@ -163,7 +163,7 @@ def test_serializer() -> None: assert loaded_model.display_category == types.PipetteGenerationType.FLEX assert loaded_model.channels == types.PipetteChannelType.NINETY_SIX_CHANNEL - model_dict = loaded_model.dict() + model_dict = loaded_model.model_dump() # each field should be the value of the enum class assert ( isinstance(model_dict["pipette_type"], str) diff --git a/shared-data/python/tests/protocol/test_protocol_schema_v6.py b/shared-data/python/tests/protocol/test_protocol_schema_v6.py index 051219f5408..67ccfdc6a9f 100644 --- a/shared-data/python/tests/protocol/test_protocol_schema_v6.py +++ b/shared-data/python/tests/protocol/test_protocol_schema_v6.py @@ -20,7 +20,7 @@ def test_v6_types(defpath: Path) -> None: def_data = load_shared_data(defpath) def_model = protocol_schema_v6.ProtocolSchemaV6.model_validate_json(def_data) - def_dict_from_model = def_model.dict( + def_dict_from_model = def_model.model_dump( exclude_unset=True, # 'schemaVersion' in python is '$schemaVersion' in JSON by_alias=True, diff --git a/shared-data/python/tests/protocol/test_protocol_schema_v7.py b/shared-data/python/tests/protocol/test_protocol_schema_v7.py index 4045ccf35d7..0e5609148c3 100644 --- a/shared-data/python/tests/protocol/test_protocol_schema_v7.py +++ b/shared-data/python/tests/protocol/test_protocol_schema_v7.py @@ -13,7 +13,7 @@ def test_v7_types(defpath: Path) -> None: def_data = load_shared_data(defpath) def_model = protocol_schema_v7.ProtocolSchemaV7.model_validate_json(def_data) - def_dict_from_model = def_model.dict( + def_dict_from_model = def_model.model_dump( exclude_unset=True, # 'schemaVersion' in python is '$schemaVersion' in JSON by_alias=True, diff --git a/shared-data/python/tests/protocol/test_protocol_schema_v8.py b/shared-data/python/tests/protocol/test_protocol_schema_v8.py index 48c9b6d242c..d2488904235 100644 --- a/shared-data/python/tests/protocol/test_protocol_schema_v8.py +++ b/shared-data/python/tests/protocol/test_protocol_schema_v8.py @@ -12,6 +12,6 @@ def test_v8_types(defpath: Path) -> None: def_data = load_shared_data(defpath) def_model = protocol_schema_v8.ProtocolSchemaV8.model_validate_json(def_data) - def_dict_from_model = def_model.dict(by_alias=True, exclude_unset=True) + def_dict_from_model = def_model.model_dump(by_alias=True, exclude_unset=True) expected_def_dict = json.loads(def_data) assert def_dict_from_model == expected_def_dict diff --git a/system-server/pytest.ini b/system-server/pytest.ini index 3c283534412..61e37dad0cb 100644 --- a/system-server/pytest.ini +++ b/system-server/pytest.ini @@ -2,3 +2,9 @@ addopts = --cov=system_server --cov-report term-missing:skip-covered --cov-report xml:coverage.xml --color=yes --strict-markers asyncio_mode = auto tavern-global-cfg = tests/integration/common.yaml + +filterwarnings = + # Pydantic's shims for its legacy v1 methods (e.g. `BaseModel.construct()`) + # are not type-checked properly. Forbid them, so we're forced to use their newer + # v2 replacements which are type-checked (e.g. ``BaseModel.model_construct()`) + error::pydantic.PydanticDeprecatedSince20 diff --git a/system-server/system_server/settings/settings.py b/system-server/system_server/settings/settings.py index d7b90658e8f..5256a1e09e1 100644 --- a/system-server/system_server/settings/settings.py +++ b/system-server/system_server/settings/settings.py @@ -77,7 +77,7 @@ def save_settings(settings: SystemServerSettings) -> bool: env_path = env_path or f"{settings.persistence_directory}/system.env" prefix = settings.model_config.get("env_prefix") try: - for key, val in settings.dict().items(): + for key, val in settings.model_dump().items(): name = f"{prefix}{key}" value = str(val) if val is not None else "" set_key(env_path, name, value) From d2650530ee9a9d2ce912732e479a1f3285f8935f Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Thu, 19 Dec 2024 10:16:05 -0500 Subject: [PATCH 35/42] perf(robot-server): Reuse existing TypeAdapter for Command (#17144) --- robot-server/robot_server/runs/run_store.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/robot-server/robot_server/runs/run_store.py b/robot-server/robot_server/runs/run_store.py index 446a7a96482..3094b73b8ba 100644 --- a/robot-server/robot_server/runs/run_store.py +++ b/robot-server/robot_server/runs/run_store.py @@ -20,7 +20,7 @@ CommandErrorSlice, CommandStatus, ) -from opentrons.protocol_engine.commands import Command +from opentrons.protocol_engine.commands import Command, CommandAdapter from opentrons.protocol_engine.types import RunTimeParameter from opentrons_shared_data.errors.exceptions import ( @@ -51,6 +51,8 @@ _CACHE_ENTRIES = 32 +_rtp_list_adapter = TypeAdapter(list[RunTimeParameter]) + @dataclass(frozen=True) class RunResource: @@ -828,13 +830,9 @@ def _convert_state_to_sql_values( } -_command_type_adapter: TypeAdapter[Command] = TypeAdapter(Command) -_rtp_list_adapter = TypeAdapter(list[RunTimeParameter]) - - def _parse_command(json_str: str) -> Command: """Parse a JSON string from the database into a `Command`.""" - return json_to_pydantic(_command_type_adapter, json_str) + return json_to_pydantic(CommandAdapter, json_str) def _convert_commands_status_to_sql_command_status( From 74b126ec992541987b10f289e8f6ddb59a754af8 Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Thu, 19 Dec 2024 10:16:57 -0500 Subject: [PATCH 36/42] refactor(robot-server): Delete obsolete workarounds for discriminated unions in Pydantic v1 (#17145) --- robot-server/robot_server/commands/router.py | 13 +------------ .../maintenance_runs/router/commands_router.py | 4 ++-- robot-server/robot_server/runs/command_models.py | 15 --------------- .../robot_server/runs/router/commands_router.py | 4 ++-- robot-server/tests/commands/test_router.py | 7 +++---- .../router/test_commands_router.py | 7 +++---- .../tests/runs/router/test_commands_router.py | 13 ++++++------- 7 files changed, 17 insertions(+), 46 deletions(-) diff --git a/robot-server/robot_server/commands/router.py b/robot-server/robot_server/commands/router.py index ce4db3fd515..5d99f3e04f7 100644 --- a/robot-server/robot_server/commands/router.py +++ b/robot-server/robot_server/commands/router.py @@ -28,17 +28,6 @@ commands_router = APIRouter() -class RequestModelWithStatelessCommandCreate(RequestModel[StatelessCommandCreate]): - """Equivalent to RequestModel[StatelessCommandCreate]. - - This works around a Pydantic v<2 bug where RequestModel[StatelessCommandCreate] - doesn't parse using the StatelessCommandCreate union discriminator. - https://github.com/pydantic/pydantic/issues/3782 - """ - - data: StatelessCommandCreate - - class CommandNotFound(ErrorDetails): """An error returned if the given command cannot be found.""" @@ -63,7 +52,7 @@ class CommandNotFound(ErrorDetails): }, ) async def create_command( - request_body: RequestModelWithStatelessCommandCreate, + request_body: RequestModel[StatelessCommandCreate], orchestrator: Annotated[RunOrchestrator, Depends(get_default_orchestrator)], waitUntilComplete: Annotated[ bool, diff --git a/robot-server/robot_server/maintenance_runs/router/commands_router.py b/robot-server/robot_server/maintenance_runs/router/commands_router.py index 40c9b5d782a..6e043006ec3 100644 --- a/robot-server/robot_server/maintenance_runs/router/commands_router.py +++ b/robot-server/robot_server/maintenance_runs/router/commands_router.py @@ -17,10 +17,10 @@ MultiBody, MultiBodyMeta, PydanticResponse, + RequestModel, ) from robot_server.robot.control.dependencies import require_estop_in_good_state from robot_server.runs.command_models import ( - RequestModelWithCommandCreate, CommandCollectionLinks, CommandLink, CommandLinkMeta, @@ -99,7 +99,7 @@ async def get_current_run_from_url( }, ) async def create_run_command( - request_body: RequestModelWithCommandCreate, + request_body: RequestModel[pe_commands.CommandCreate], run_orchestrator_store: Annotated[ MaintenanceRunOrchestratorStore, Depends(get_maintenance_run_orchestrator_store) ], diff --git a/robot-server/robot_server/runs/command_models.py b/robot-server/robot_server/runs/command_models.py index 5da1038f470..dc19b4026c1 100644 --- a/robot-server/robot_server/runs/command_models.py +++ b/robot-server/robot_server/runs/command_models.py @@ -8,21 +8,6 @@ from pydantic import BaseModel, Field -from opentrons.protocol_engine import commands as pe_commands - -from robot_server.service.json_api.request import RequestModel - - -class RequestModelWithCommandCreate(RequestModel[pe_commands.CommandCreate]): - """Equivalent to RequestModel[CommandCreate]. - - This works around a Pydantic v<2 bug where RequestModel[CommandCreate] - doesn't parse using the CommandCreate union discriminator. - https://github.com/pydantic/pydantic/issues/3782 - """ - - data: pe_commands.CommandCreate - class CommandLinkMeta(BaseModel): """Metadata about a command resource referenced in `links`.""" diff --git a/robot-server/robot_server/runs/router/commands_router.py b/robot-server/robot_server/runs/router/commands_router.py index 99828010750..55e1826d5e8 100644 --- a/robot-server/robot_server/runs/router/commands_router.py +++ b/robot-server/robot_server/runs/router/commands_router.py @@ -17,11 +17,11 @@ MultiBodyMeta, PydanticResponse, SimpleMultiBody, + RequestModel, ) from robot_server.robot.control.dependencies import require_estop_in_good_state from ..command_models import ( - RequestModelWithCommandCreate, CommandCollectionLinks, CommandLink, CommandLinkMeta, @@ -155,7 +155,7 @@ async def get_current_run_from_url( }, ) async def create_run_command( - request_body: RequestModelWithCommandCreate, + request_body: RequestModel[pe_commands.CommandCreate], run_orchestrator_store: Annotated[ RunOrchestratorStore, Depends(get_run_orchestrator_store) ], diff --git a/robot-server/tests/commands/test_router.py b/robot-server/tests/commands/test_router.py index 4ccc1a1acc1..978594a6917 100644 --- a/robot-server/tests/commands/test_router.py +++ b/robot-server/tests/commands/test_router.py @@ -11,10 +11,9 @@ from opentrons.protocol_engine.errors import CommandDoesNotExistError from opentrons.protocol_runner import RunOrchestrator -from robot_server.service.json_api import MultiBodyMeta +from robot_server.service.json_api import MultiBodyMeta, RequestModel from robot_server.errors.error_responses import ApiError from robot_server.commands.router import ( - RequestModelWithStatelessCommandCreate, create_command, get_commands_list, get_command, @@ -58,7 +57,7 @@ def _stub_queued_command_state(*_a: object, **_k: object) -> pe_commands.Command ).then_do(_stub_queued_command_state) result = await create_command( - RequestModelWithStatelessCommandCreate(data=command_create), + RequestModel(data=command_create), waitUntilComplete=False, timeout=42, orchestrator=run_orchestrator, @@ -99,7 +98,7 @@ async def test_create_command_wait_for_complete( decoy.when(run_orchestrator.get_command("abc123")).then_return(completed_command) result = await create_command( - RequestModelWithStatelessCommandCreate(data=command_create), + RequestModel(data=command_create), waitUntilComplete=True, timeout=42, orchestrator=run_orchestrator, diff --git a/robot-server/tests/maintenance_runs/router/test_commands_router.py b/robot-server/tests/maintenance_runs/router/test_commands_router.py index 19415f080f9..84bf5a490c5 100644 --- a/robot-server/tests/maintenance_runs/router/test_commands_router.py +++ b/robot-server/tests/maintenance_runs/router/test_commands_router.py @@ -13,7 +13,7 @@ from opentrons.protocol_engine.errors import CommandDoesNotExistError from robot_server.errors.error_responses import ApiError -from robot_server.service.json_api import MultiBodyMeta +from robot_server.service.json_api import MultiBodyMeta, RequestModel from robot_server.maintenance_runs.maintenance_run_orchestrator_store import ( MaintenanceRunOrchestratorStore, @@ -31,7 +31,6 @@ get_current_run_from_url, ) from robot_server.runs.command_models import ( - RequestModelWithCommandCreate, CommandCollectionLinks, CommandLink, CommandLinkMeta, @@ -109,7 +108,7 @@ async def test_create_run_command( result = await create_run_command( run_id="run-id", - request_body=RequestModelWithCommandCreate(data=command_request), + request_body=RequestModel(data=command_request), waitUntilComplete=False, run_orchestrator_store=mock_maintenance_run_orchestrator_store, timeout=None, @@ -151,7 +150,7 @@ async def test_create_run_command_blocking_completion( result = await create_run_command( run_id="run-id", - request_body=RequestModelWithCommandCreate(data=command_request), + request_body=RequestModel(data=command_request), waitUntilComplete=True, timeout=999, run_orchestrator_store=mock_maintenance_run_orchestrator_store, diff --git a/robot-server/tests/runs/router/test_commands_router.py b/robot-server/tests/runs/router/test_commands_router.py index e7045fe6287..50d58993c6c 100644 --- a/robot-server/tests/runs/router/test_commands_router.py +++ b/robot-server/tests/runs/router/test_commands_router.py @@ -13,10 +13,9 @@ ) from robot_server.errors.error_responses import ApiError -from robot_server.service.json_api import MultiBodyMeta +from robot_server.service.json_api import MultiBodyMeta, RequestModel from robot_server.runs.command_models import ( - RequestModelWithCommandCreate, CommandCollectionLinks, CommandLink, CommandLinkMeta, @@ -129,7 +128,7 @@ def _stub_queued_command_state(*_a: object, **_k: object) -> pe_commands.Command result = await create_run_command( run_id="run-id", - request_body=RequestModelWithCommandCreate(data=command_request), + request_body=RequestModel(data=command_request), waitUntilComplete=False, run_orchestrator_store=mock_run_orchestrator_store, failedCommandId=None, @@ -163,7 +162,7 @@ async def test_create_command_with_failed_command_raises( with pytest.raises(ApiError): await create_run_command( run_id="run-id", - request_body=RequestModelWithCommandCreate(data=command_create), + request_body=RequestModel(data=command_create), run_orchestrator_store=mock_run_orchestrator_store, failedCommandId="123", check_estop=True, @@ -204,7 +203,7 @@ async def test_create_run_command_blocking_completion( result = await create_run_command( run_id="run-id", - request_body=RequestModelWithCommandCreate(data=command_request), + request_body=RequestModel(data=command_request), waitUntilComplete=True, timeout=999, run_orchestrator_store=mock_run_orchestrator_store, @@ -238,7 +237,7 @@ async def test_add_conflicting_setup_command( with pytest.raises(ApiError) as exc_info: await create_run_command( run_id="run-id", - request_body=RequestModelWithCommandCreate(data=command_request), + request_body=RequestModel(data=command_request), run_orchestrator_store=mock_run_orchestrator_store, failedCommandId=None, check_estop=True, @@ -273,7 +272,7 @@ async def test_add_command_to_stopped_engine( with pytest.raises(ApiError) as exc_info: await create_run_command( run_id="run-id", - request_body=RequestModelWithCommandCreate(data=command_request), + request_body=RequestModel(data=command_request), run_orchestrator_store=mock_run_orchestrator_store, failedCommandId=None, check_estop=True, From 481a1f0a55f63ef5fe3b31e4a674aa0192f86d6a Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:01:17 -0500 Subject: [PATCH 37/42] feat(shared-data,-protocol-designer): add foundation for plate reader support in PD (#17147) This PR introduces plate reader to PD, still hidden behind a feature flag. Namely, it adds the ability to add plate reader to the initial deck state and fixes logic for ModuleLabel rendering for all modules. Of note, in this dev work, I discovered a bug in the plate reader's shared-data definition, in which the top-level x and y dimensions were flipped, so those values are swapped here as well. --- components/src/molecules/Tabs/index.tsx | 47 +++++++++---- .../localization/en/starting_deck_state.json | 1 + .../Designer/DeckSetup/DeckSetupTools.tsx | 5 +- .../Designer/DeckSetup/HighlightItems.tsx | 1 + .../pages/Designer/DeckSetup/HoveredItems.tsx | 1 + .../pages/Designer/DeckSetup/LabwareTools.tsx | 11 +++- .../pages/Designer/DeckSetup/ModuleLabel.tsx | 66 ++++++++++--------- .../DeckSetup/SelectedHoveredItems.tsx | 1 + .../DeckSetup/__tests__/LabwareTools.test.tsx | 1 + .../DeckSetup/__tests__/utils.test.ts | 6 +- .../src/pages/Designer/DeckSetup/constants.ts | 6 +- .../src/pages/Designer/DeckSetup/utils.ts | 46 ++++++------- .../src/utils/labwareModuleCompatibility.ts | 15 +++++ .../definitions/3/absorbanceReaderV1.json | 4 +- 14 files changed, 135 insertions(+), 76 deletions(-) diff --git a/components/src/molecules/Tabs/index.tsx b/components/src/molecules/Tabs/index.tsx index d9e6a7b349a..70811a3dd2a 100644 --- a/components/src/molecules/Tabs/index.tsx +++ b/components/src/molecules/Tabs/index.tsx @@ -1,8 +1,10 @@ import { css } from 'styled-components' -import { TYPOGRAPHY, SPACING, RESPONSIVENESS } from '../../ui-style-constants' +import { Tooltip } from '../../atoms' import { COLORS, BORDERS } from '../../helix-design-system' -import { POSITION_RELATIVE, DIRECTION_ROW } from '../../styles' import { Btn, Flex } from '../../primitives' +import { POSITION_RELATIVE, DIRECTION_ROW } from '../../styles' +import { useHoverTooltip } from '../../tooltips' +import { TYPOGRAPHY, SPACING, RESPONSIVENESS } from '../../ui-style-constants' const DEFAULT_TAB_STYLE = css` ${TYPOGRAPHY.pSemiBold} @@ -65,6 +67,7 @@ export interface TabProps { onClick: () => void isActive?: boolean disabled?: boolean + disabledReasonForTooltip?: string } export interface TabsProps { @@ -77,18 +80,36 @@ export function Tabs(props: TabsProps): JSX.Element { return ( {tabs.map((tab, index) => ( - { - tab.onClick() - }} - css={tab.isActive === true ? CURRENT_TAB_STYLE : DEFAULT_TAB_STYLE} - disabled={tab.disabled} - > - {tab.text} - + ))} ) } + +function Tab(props: TabProps): JSX.Element { + const { + text, + onClick, + isActive, + disabled = false, + disabledReasonForTooltip, + } = props + const [targetProps, tooltipProps] = useHoverTooltip() + return ( + <> + + {text} + + {disabled && disabledReasonForTooltip != null ? ( + + {disabledReasonForTooltip} + + ) : null} + + ) +} diff --git a/protocol-designer/src/assets/localization/en/starting_deck_state.json b/protocol-designer/src/assets/localization/en/starting_deck_state.json index fd77cb95dd8..afa602358ca 100644 --- a/protocol-designer/src/assets/localization/en/starting_deck_state.json +++ b/protocol-designer/src/assets/localization/en/starting_deck_state.json @@ -48,6 +48,7 @@ "onDeck": "On deck", "one_item": "No more than 1 {{hardware}} allowed on the deck at one time", "only_display_rec": "Only display recommended labware", + "plate_reader_no_labware": "Labware cannot be loaded onto a plate reader. You can move labware onto the plate reader when building your protocol", "protocol_starting_deck": "Protocol starting deck", "read_more_gen1_gen2": "Read more about the differences between GEN1 and GEN2 Magnetic Modules", "rename_lab": "Rename labware", diff --git a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx index e93ec99d887..4c41a8f8464 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx @@ -18,6 +18,7 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { + ABSORBANCE_READER_V1, FLEX_ROBOT_TYPE, FLEX_STAGING_AREA_SLOT_ADDRESSABLE_AREAS, getModuleDisplayName, @@ -228,7 +229,9 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null { disabled: selectedFixture === 'wasteChute' || selectedFixture === 'wasteChuteAndStagingArea' || - selectedFixture === 'trashBin', + selectedFixture === 'trashBin' || + selectedModuleModel === ABSORBANCE_READER_V1, + disabledReasonForTooltip: t('plate_reader_no_labware'), isActive: tab === 'labware', onClick: () => { setTab('labware') diff --git a/protocol-designer/src/pages/Designer/DeckSetup/HighlightItems.tsx b/protocol-designer/src/pages/Designer/DeckSetup/HighlightItems.tsx index fd548de360b..c9e4726eae3 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/HighlightItems.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/HighlightItems.tsx @@ -191,6 +191,7 @@ export function HighlightItems(props: HighlightItemsProps): JSX.Element | null { ? hoveredItem.text ?? '' : selectedItemModule.text ?? '' } + slot={moduleOnDeck.slot} /> ) } diff --git a/protocol-designer/src/pages/Designer/DeckSetup/HoveredItems.tsx b/protocol-designer/src/pages/Designer/DeckSetup/HoveredItems.tsx index a96d2418607..7a478a37f98 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/HoveredItems.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/HoveredItems.tsx @@ -109,6 +109,7 @@ export const HoveredItems = ( orientation={orientation} isSelected={false} isLast={true} + slot={selectedSlot.slot} /> ) : null} diff --git a/protocol-designer/src/pages/Designer/DeckSetup/LabwareTools.tsx b/protocol-designer/src/pages/Designer/DeckSetup/LabwareTools.tsx index be4f457429e..ca8feac72d1 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/LabwareTools.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/LabwareTools.tsx @@ -38,6 +38,7 @@ import { getOnlyLatestDefs } from '../../../labware-defs' import { ADAPTER_96_CHANNEL, getLabwareIsCompatible as _getLabwareIsCompatible, + getLabwareCompatibleWithAbsorbanceReader, } from '../../../utils/labwareModuleCompatibility' import { getHas96Channel } from '../../../utils' import { createCustomLabwareDef } from '../../../labware-defs/actions' @@ -49,6 +50,7 @@ import { selectLabware, selectNestedLabware, } from '../../../labware-ingred/actions' +import { getEnableAbsorbanceReader } from '../../../feature-flags/selectors' import { ALL_ORDERED_CATEGORIES, CUSTOM_CATEGORY, @@ -132,13 +134,17 @@ export function LabwareTools(props: LabwareToolsProps): JSX.Element { robotType === OT2_ROBOT_TYPE ? isNextToHeaterShaker : false ) + const enablePlateReader = useSelector(getEnableAbsorbanceReader) + const getLabwareCompatible = useCallback( (def: LabwareDefinition2) => { // assume that custom (non-standard) labware is (potentially) compatible if (moduleType == null || !getLabwareDefIsStandard(def)) { return true } - return _getLabwareIsCompatible(def, moduleType) + return moduleType === ABSORBANCE_READER_TYPE + ? getLabwareCompatibleWithAbsorbanceReader(def) + : _getLabwareIsCompatible(def, moduleType) }, [moduleType] ) @@ -167,7 +173,8 @@ export function LabwareTools(props: LabwareToolsProps): JSX.Element { moduleType !== HEATERSHAKER_MODULE_TYPE) || (isAdapter96Channel && !has96Channel) || (slot === 'offDeck' && isAdapter) || - (PLATE_READER_LOADNAME === parameters.loadName && + (!enablePlateReader && + PLATE_READER_LOADNAME === parameters.loadName && moduleType !== ABSORBANCE_READER_TYPE) ) }, diff --git a/protocol-designer/src/pages/Designer/DeckSetup/ModuleLabel.tsx b/protocol-designer/src/pages/Designer/DeckSetup/ModuleLabel.tsx index 12849eba08a..568eeb5f0d9 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/ModuleLabel.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/ModuleLabel.tsx @@ -3,15 +3,19 @@ import { useSelector } from 'react-redux' import { DeckLabelSet } from '@opentrons/components' import { FLEX_ROBOT_TYPE, + FLEX_STANDARD_DECKID, HEATERSHAKER_MODULE_TYPE, - MAGNETIC_MODULE_TYPE, + OT2_STANDARD_DECKID, TEMPERATURE_MODULE_TYPE, - THERMOCYCLER_MODULE_TYPE, getModuleDef2, } from '@opentrons/shared-data' import { getRobotType } from '../../../file-data/selectors' import type { DeckLabelProps } from '@opentrons/components' -import type { CoordinateTuple, ModuleModel } from '@opentrons/shared-data' +import type { + CoordinateTuple, + DeckSlotId, + ModuleModel, +} from '@opentrons/shared-data' interface ModuleLabelProps { moduleModel: ModuleModel @@ -19,6 +23,7 @@ interface ModuleLabelProps { orientation: 'left' | 'right' isSelected: boolean isLast: boolean + slot: DeckSlotId | null isZoomed?: boolean labwareInfos?: DeckLabelProps[] labelName?: string @@ -33,6 +38,7 @@ export const ModuleLabel = (props: ModuleLabelProps): JSX.Element => { labwareInfos = [], isZoomed = true, labelName, + slot, } = props const robotType = useSelector(getRobotType) const labelContainerRef = useRef(null) @@ -45,30 +51,21 @@ export const ModuleLabel = (props: ModuleLabelProps): JSX.Element => { }, [labwareInfos]) const def = getModuleDef2(moduleModel) - const overhang = - def?.dimensions.labwareInterfaceXDimension != null - ? def.dimensions.xDimension - def?.dimensions.labwareInterfaceXDimension + const slotTransformKey = + robotType === FLEX_ROBOT_TYPE ? FLEX_STANDARD_DECKID : OT2_STANDARD_DECKID + const cornerOffsetsFromSlotFromTransform = + slot != null && !isZoomed + ? def?.slotTransforms?.[slotTransformKey]?.[slot]?.cornerOffsetFromSlot + : null + const tempAdjustmentX = + def?.moduleType === TEMPERATURE_MODULE_TYPE && orientation === 'right' + ? def?.dimensions.xDimension - (def?.dimensions.footprintXDimension ?? 0) // shift depending on side of deck + : 0 + const tempAdjustmentY = def?.moduleType === TEMPERATURE_MODULE_TYPE ? -1 : 0 + const heaterShakerAdjustmentX = + def?.moduleType === HEATERSHAKER_MODULE_TYPE && orientation === 'right' // shift depending on side of deck + ? 7 // TODO(ND: 12/18/2024): investigate further why the module definition does not contain sufficient info to find this offset : 0 - let leftOverhang = overhang - - switch (def?.moduleType) { - case TEMPERATURE_MODULE_TYPE: - leftOverhang = overhang * 2 - break - case HEATERSHAKER_MODULE_TYPE: - leftOverhang = overhang + 14 - break - case MAGNETIC_MODULE_TYPE: - leftOverhang = overhang + 8 - break - case THERMOCYCLER_MODULE_TYPE: - if (!isZoomed && robotType === FLEX_ROBOT_TYPE) { - leftOverhang = overhang + 20 - } - break - default: - break - } return ( { ...labwareInfos, ]} x={ - (orientation === 'right' - ? position[0] - overhang - : position[0] - leftOverhang) - def?.cornerOffsetFromSlot.x + position[0] + + def.cornerOffsetFromSlot.x + + (cornerOffsetsFromSlotFromTransform?.[0][3] ?? 0) + + tempAdjustmentX + + heaterShakerAdjustmentX - + 1 + } + y={ + position[1] + + def.cornerOffsetFromSlot.y + + (cornerOffsetsFromSlotFromTransform?.[1][3] ?? 0) - + labelContainerHeight + + tempAdjustmentY } - y={position[1] + def?.cornerOffsetFromSlot.y - labelContainerHeight} width={def?.dimensions.xDimension + 2} height={def?.dimensions.yDimension + 2} /> diff --git a/protocol-designer/src/pages/Designer/DeckSetup/SelectedHoveredItems.tsx b/protocol-designer/src/pages/Designer/DeckSetup/SelectedHoveredItems.tsx index 2400271ee22..b150cdb9274 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/SelectedHoveredItems.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/SelectedHoveredItems.tsx @@ -188,6 +188,7 @@ export const SelectedHoveredItems = ( orientation={orientation} isSelected={true} labwareInfos={labwareInfos} + slot={selectedSlot.slot} /> ) : null} diff --git a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/LabwareTools.test.tsx b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/LabwareTools.test.tsx index 479724f3527..d584faf4d27 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/LabwareTools.test.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/LabwareTools.test.tsx @@ -25,6 +25,7 @@ import type { LabwareDefinition2, PipetteV2Specs } from '@opentrons/shared-data' vi.mock('../../../../utils') vi.mock('../../../../step-forms/selectors') +vi.mock('../../../../feature-flags/selectors') vi.mock('../../../../file-data/selectors') vi.mock('../../../../labware-defs/selectors') vi.mock('../../../../labware-defs/actions') diff --git a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/utils.test.ts b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/utils.test.ts index 50325ad7197..7d48c7ea71d 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/utils.test.ts +++ b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/utils.test.ts @@ -1,5 +1,6 @@ import { describe, it, expect } from 'vitest' import { + ABSORBANCE_READER_V1, FLEX_ROBOT_TYPE, HEATERSHAKER_MODULE_TYPE, HEATERSHAKER_MODULE_V1, @@ -45,12 +46,13 @@ describe('getModuleModelsBySlot', () => { }) it('renders all flex modules for B1', () => { expect(getModuleModelsBySlot(true, FLEX_ROBOT_TYPE, 'B1')).toEqual( - FLEX_MODULE_MODELS + FLEX_MODULE_MODELS.filter(model => model !== ABSORBANCE_READER_V1) ) }) it('renders all flex modules for C1', () => { const noTC = FLEX_MODULE_MODELS.filter( - model => model !== THERMOCYCLER_MODULE_V2 + model => + model !== THERMOCYCLER_MODULE_V2 && model !== ABSORBANCE_READER_V1 ) expect(getModuleModelsBySlot(true, FLEX_ROBOT_TYPE, 'C1')).toEqual(noTC) }) diff --git a/protocol-designer/src/pages/Designer/DeckSetup/constants.ts b/protocol-designer/src/pages/Designer/DeckSetup/constants.ts index e1acb64424d..479b185a765 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/constants.ts +++ b/protocol-designer/src/pages/Designer/DeckSetup/constants.ts @@ -13,6 +13,7 @@ import { HEATERSHAKER_MODULE_TYPE, MAGNETIC_BLOCK_TYPE, ABSORBANCE_READER_TYPE, + ABSORBANCE_READER_V1, } from '@opentrons/shared-data' import type { ModuleModel, ModuleType } from '@opentrons/shared-data' @@ -92,9 +93,7 @@ export const RECOMMENDED_LABWARE_BY_MODULE: { [K in ModuleType]: string[] } = { 'nest_96_wellplate_2ml_deep', 'opentrons_96_wellplate_200ul_pcr_full_skirt', ], - [ABSORBANCE_READER_TYPE]: [ - 'opentrons_flex_lid_absorbance_plate_reader_module', - ], + [ABSORBANCE_READER_TYPE]: ['nest_96_wellplate_200ul_flat'], } export const MOAM_MODELS_WITH_FF: ModuleModel[] = [TEMPERATURE_MODULE_V2] @@ -102,6 +101,7 @@ export const MOAM_MODELS: ModuleModel[] = [ TEMPERATURE_MODULE_V2, HEATERSHAKER_MODULE_V1, MAGNETIC_BLOCK_V1, + ABSORBANCE_READER_V1, ] export const MAX_MOAM_MODULES = 7 diff --git a/protocol-designer/src/pages/Designer/DeckSetup/utils.ts b/protocol-designer/src/pages/Designer/DeckSetup/utils.ts index a288947365a..a891926d329 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/utils.ts +++ b/protocol-designer/src/pages/Designer/DeckSetup/utils.ts @@ -5,8 +5,9 @@ import { FLEX_ROBOT_TYPE, FLEX_STAGING_AREA_SLOT_ADDRESSABLE_AREAS, HEATERSHAKER_MODULE_TYPE, - MAGNETIC_BLOCK_V1, + HEATERSHAKER_MODULE_V1, OT2_ROBOT_TYPE, + TEMPERATURE_MODULE_V2, THERMOCYCLER_MODULE_TYPE, THERMOCYCLER_MODULE_V2, getAreSlotsAdjacent, @@ -61,33 +62,32 @@ export function getModuleModelsBySlot( robotType: RobotType, slot: DeckSlotId ): ModuleModel[] { - const FLEX_MIDDLE_SLOTS = ['B2', 'C2', 'A2', 'D2'] + const FLEX_MIDDLE_SLOTS = new Set(['B2', 'C2', 'A2', 'D2']) const OT2_MIDDLE_SLOTS = ['2', '5', '8', '11'] - const FILTERED_MODULES = enableAbsorbanceReader - ? FLEX_MODULE_MODELS - : FLEX_MODULE_MODELS.filter(model => model !== ABSORBANCE_READER_V1) - let moduleModels: ModuleModel[] = FILTERED_MODULES + const FLEX_RIGHT_SLOTS = new Set(['A3', 'B3', 'C3', 'D3']) + + let moduleModels: ModuleModel[] = FLEX_MODULE_MODELS switch (robotType) { case FLEX_ROBOT_TYPE: { - if (slot !== 'B1' && !FLEX_MIDDLE_SLOTS.includes(slot)) { - moduleModels = FILTERED_MODULES.filter( - model => model !== THERMOCYCLER_MODULE_V2 - ) - } - if (FLEX_MIDDLE_SLOTS.includes(slot)) { - moduleModels = FILTERED_MODULES.filter( - model => model === MAGNETIC_BLOCK_V1 - ) - } - if ( - FLEX_STAGING_AREA_SLOT_ADDRESSABLE_AREAS.includes( - slot as AddressableAreaName - ) - ) { - moduleModels = [] - } + moduleModels = FLEX_STAGING_AREA_SLOT_ADDRESSABLE_AREAS.includes( + slot as AddressableAreaName + ) + ? [] + : FLEX_MODULE_MODELS.filter(model => { + if (model === THERMOCYCLER_MODULE_V2) { + return slot === 'B1' + } else if (model === ABSORBANCE_READER_V1) { + return FLEX_RIGHT_SLOTS.has(slot) && enableAbsorbanceReader + } else if ( + model === TEMPERATURE_MODULE_V2 || + model === HEATERSHAKER_MODULE_V1 + ) { + return !FLEX_MIDDLE_SLOTS.has(slot) + } + return true + }) break } case OT2_ROBOT_TYPE: { diff --git a/protocol-designer/src/utils/labwareModuleCompatibility.ts b/protocol-designer/src/utils/labwareModuleCompatibility.ts index 52fd34ec9ed..1664e060f0a 100644 --- a/protocol-designer/src/utils/labwareModuleCompatibility.ts +++ b/protocol-designer/src/utils/labwareModuleCompatibility.ts @@ -11,6 +11,9 @@ import type { LabwareDefByDefURI } from '../labware-defs' import type { LabwareOnDeck } from '../step-forms' import type { LabwareDefinition2, ModuleType } from '@opentrons/shared-data' // NOTE: this does not distinguish btw versions. Standard labware only (assumes namespace is 'opentrons') + +const PLATE_READER_MAX_LABWARE_Z_MM = 16 + export const COMPATIBLE_LABWARE_ALLOWLIST_BY_MODULE_TYPE: Record< ModuleType, Readonly @@ -155,6 +158,18 @@ export const getLabwareIsCustom = ( return labwareOnDeck.labwareDefURI in customLabwares } +// This breaks pattern with other module compatibility checks, but it more exactly mirrors Protocol Engine's logic +// See api/src/opentrons/protocol_engine/state/labware.py for details +export const getLabwareCompatibleWithAbsorbanceReader = ( + def: LabwareDefinition2 +): boolean => { + return ( + Object.entries(def.wells).length === 96 && + !def.parameters.isTiprack && + def.dimensions.zDimension <= PLATE_READER_MAX_LABWARE_Z_MM + ) +} + export const getAdapterLabwareIsAMatch = ( labwareId: string, allLabware: LabwareOnDeck[], diff --git a/shared-data/module/definitions/3/absorbanceReaderV1.json b/shared-data/module/definitions/3/absorbanceReaderV1.json index 57b0bfc1b10..7ced1f05ded 100644 --- a/shared-data/module/definitions/3/absorbanceReaderV1.json +++ b/shared-data/module/definitions/3/absorbanceReaderV1.json @@ -11,8 +11,8 @@ "bareOverallHeight": 18.5, "overLabwareHeight": 0.0, "lidHeight": 60.0, - "xDimension": 95.5, - "yDimension": 155.3, + "xDimension": 155.3, + "yDimension": 95.5, "labwareInterfaceXDimension": 127.8, "labwareInterfaceYDimension": 85.5 }, From a51b2025b22c346e4abba3235ffcb4b3587d36d4 Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:16:28 -0500 Subject: [PATCH 38/42] =?UTF-8?q?feat(protocol-designer,=20components):=20?= =?UTF-8?q?deprecate=20DropdownField=20and=20Opti=E2=80=A6=20(#17150)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …ons type --- components/src/controls/LabeledSelect.tsx | 34 ------ components/src/controls/index.ts | 1 - .../src/forms/DropdownField.stories.tsx | 44 -------- components/src/forms/DropdownField.tsx | 106 ------------------ .../forms/__tests__/DropdownField.test.tsx | 5 - components/src/forms/index.ts | 1 - .../src/molecules/DropdownMenu/index.tsx | 2 + .../src/labware-ingred/selectors.ts | 26 ++--- .../molecules/DropdownStepFormField/index.tsx | 4 +- .../PipetteFields/BlowoutLocationField.tsx | 4 +- .../Designer/ProtocolSteps/StepForm/utils.ts | 4 +- protocol-designer/src/ui/labware/selectors.ts | 23 ++-- protocol-designer/src/ui/modules/selectors.ts | 14 ++- protocol-designer/src/ui/modules/utils.ts | 6 +- 14 files changed, 48 insertions(+), 226 deletions(-) delete mode 100644 components/src/controls/LabeledSelect.tsx delete mode 100644 components/src/forms/DropdownField.stories.tsx delete mode 100644 components/src/forms/DropdownField.tsx delete mode 100644 components/src/forms/__tests__/DropdownField.test.tsx diff --git a/components/src/controls/LabeledSelect.tsx b/components/src/controls/LabeledSelect.tsx deleted file mode 100644 index 6a99b5eab2c..00000000000 --- a/components/src/controls/LabeledSelect.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import type * as React from 'react' - -import { DropdownField } from '../forms' -import { LabeledControl } from './LabeledControl' -import styles from './styles.module.css' - -import type { DropdownFieldProps } from '../forms' - -export interface LabeledSelectProps extends DropdownFieldProps { - label: string - children: React.ReactNode - /** optional data test id for the container */ - 'data-test'?: string -} - -export function LabeledSelect(props: LabeledSelectProps): JSX.Element { - const { label, value, options, onChange } = props - - return ( - - } - > - {props.children} - - ) -} diff --git a/components/src/controls/index.ts b/components/src/controls/index.ts index abb5b52f640..f1e416267cc 100644 --- a/components/src/controls/index.ts +++ b/components/src/controls/index.ts @@ -5,6 +5,5 @@ export * from './ToggleButton' export * from './LabeledToggle' export * from './LabeledButton' -export * from './LabeledSelect' export * from './LabeledCheckbox' export * from './LabeledRadioGroup' diff --git a/components/src/forms/DropdownField.stories.tsx b/components/src/forms/DropdownField.stories.tsx deleted file mode 100644 index fbb849caa9e..00000000000 --- a/components/src/forms/DropdownField.stories.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react' - -import { DropdownField as DropdownFieldComponent } from './DropdownField' - -import type { Story, Meta } from '@storybook/react' - -export default { - title: 'Library/Molecules/Forms/Dropdown Field', - argTypes: { onChange: { action: 'clicked' } }, -} as Meta - -const Template: Story< - React.ComponentProps -> = args => { - const [selectedValue, setSelectedValue] = React.useState(null) - return ( - { - setSelectedValue(e.target.value) - args.onChange(e) - }} - value={selectedValue} - /> - ) -} -export const DropdownField = Template.bind({}) -DropdownField.parameters = { - docs: { - description: { - component: - '`DropdownField` is similar to `SelectField`, but more normal. It uses a ` element */ - id?: string - /** name of field in form */ - name?: string - /** Array of {name, value} data */ - options: Options - /** classes to apply */ - className?: string - /** optional caption. hidden when `error` is given */ - caption?: string - /** if included, DropdownField will use error style and display error instead of caption */ - error?: string | null | undefined - /** dropdown is disabled if value is true */ - disabled?: boolean - /** html tabindex property */ - tabIndex?: number - /** automatically focus field on render */ - autoFocus?: boolean - /** if true, render indeterminate unselectable option */ - isIndeterminate?: boolean -} - -const BLANK_OPTION: LegacyDropdownOption = { name: '', value: '' } -const INDETERMINATE_OPTION: LegacyDropdownOption = { - name: '-', - value: '', - disabled: true, -} - -export function DropdownField(props: DropdownFieldProps): JSX.Element { - let options = [] - // add in disabled, unselectable "-" mixed option when isIndeterminate is true - // add in "blank" option if there is no `value`, unless `options` already has a blank option - if (props.isIndeterminate) { - options = [INDETERMINATE_OPTION, ...props.options] - } else if (props.value || props.options.some(opt => opt.value === '')) { - options = props.options - } else { - options = [BLANK_OPTION, ...props.options] - } - - const error = props.error != null - const className = cx(props.className, { - [styles.error]: error, - [styles.dropdown_disabled]: props.disabled, - }) - - return ( -
-
- - -
- -
-
-
- {error ? props.error : props.caption} -
-
- ) -} diff --git a/components/src/forms/__tests__/DropdownField.test.tsx b/components/src/forms/__tests__/DropdownField.test.tsx deleted file mode 100644 index 7e39375e08e..00000000000 --- a/components/src/forms/__tests__/DropdownField.test.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { describe, it } from 'vitest' - -describe('DropdownField', () => { - it.todo('replace deprecated enzyme test') -}) diff --git a/components/src/forms/index.ts b/components/src/forms/index.ts index c8cd6e2b0f0..ba463a0892f 100644 --- a/components/src/forms/index.ts +++ b/components/src/forms/index.ts @@ -1,5 +1,4 @@ export * from './DeprecatedCheckboxField' -export * from './DropdownField' export * from './FormGroup' export * from './LegacyInputField' export * from './RadioGroup' diff --git a/components/src/molecules/DropdownMenu/index.tsx b/components/src/molecules/DropdownMenu/index.tsx index 2e2f2d8b8ca..3fb38f8f531 100644 --- a/components/src/molecules/DropdownMenu/index.tsx +++ b/components/src/molecules/DropdownMenu/index.tsx @@ -30,6 +30,8 @@ export interface DropdownOption { value: string /** optional dropdown option for adding the liquid color icon */ liquidColor?: string + /** optional dropdown option for adding the deck label */ + deckLabel?: string disabled?: boolean tooltipText?: string } diff --git a/protocol-designer/src/labware-ingred/selectors.ts b/protocol-designer/src/labware-ingred/selectors.ts index 25ee8bc0966..80325e33b96 100644 --- a/protocol-designer/src/labware-ingred/selectors.ts +++ b/protocol-designer/src/labware-ingred/selectors.ts @@ -4,7 +4,7 @@ import mapValues from 'lodash/mapValues' import max from 'lodash/max' import reduce from 'lodash/reduce' import type { Selector } from 'reselect' -import type { Options } from '@opentrons/components' +import type { DropdownOption } from '@opentrons/components' import type { LabwareLiquidState } from '@opentrons/step-generation' import type { CutoutId } from '@opentrons/shared-data' import type { @@ -59,18 +59,18 @@ const getLiquidNamesById: Selector< string > ) -const getLiquidSelectionOptions: Selector = createSelector( - getLiquidGroupsById, - liquidGroupsById => { - return Object.keys(liquidGroupsById).map(id => ({ - // NOTE: if these fallbacks are used, it's a bug - name: liquidGroupsById[id] - ? liquidGroupsById[id].name || `(Unnamed Liquid: ${String(id)})` - : 'Missing Liquid', - value: id, - })) - } -) +const getLiquidSelectionOptions: Selector< + RootSlice, + DropdownOption[] +> = createSelector(getLiquidGroupsById, liquidGroupsById => { + return Object.keys(liquidGroupsById).map(id => ({ + // NOTE: if these fallbacks are used, it's a bug + name: liquidGroupsById[id] + ? liquidGroupsById[id].name || `(Unnamed Liquid: ${String(id)})` + : 'Missing Liquid', + value: id, + })) +}) // false or selected slot to add labware to, eg 'A2' const selectedAddLabwareSlot = (state: BaseState): DeckSlot | false => diff --git a/protocol-designer/src/molecules/DropdownStepFormField/index.tsx b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx index 75334fe830a..2714a73156b 100644 --- a/protocol-designer/src/molecules/DropdownStepFormField/index.tsx +++ b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx @@ -10,11 +10,11 @@ import { StyledText, } from '@opentrons/components' import { selectDropdownItem } from '../../ui/steps/actions/actions' -import type { Options } from '@opentrons/components' +import type { DropdownOption } from '@opentrons/components' import type { FieldProps } from '../../pages/Designer/ProtocolSteps/StepForm/types' export interface DropdownStepFormFieldProps extends FieldProps { - options: Options + options: DropdownOption[] title: string width?: string onEnter?: (id: string) => void diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/BlowoutLocationField.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/BlowoutLocationField.tsx index 44c837796bf..28e8228f220 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/BlowoutLocationField.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/BlowoutLocationField.tsx @@ -2,11 +2,11 @@ import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { selectors as uiLabwareSelectors } from '../../../../../ui/labware' import { DropdownStepFormField } from '../../../../../molecules' -import type { Options } from '@opentrons/components' +import type { DropdownOption } from '@opentrons/components' import type { FieldProps } from '../types' type BlowoutLocationDropdownProps = FieldProps & { - options: Options + options: DropdownOption[] } export function BlowoutLocationField( diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/utils.ts b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/utils.ts index db336a0aba1..753746ecd87 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/utils.ts +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/utils.ts @@ -14,7 +14,7 @@ import { import { i18n } from '../../../../assets/localization' import { PROFILE_CYCLE } from '../../../../form-types' import type { PipetteEntity } from '@opentrons/step-generation' -import type { Options } from '@opentrons/components' +import type { DropdownOption } from '@opentrons/components' import type { ProfileFormError } from '../../../../steplist/formLevel/profileErrors' import type { FormWarning } from '../../../../steplist/formLevel/warnings' import type { StepFormErrors } from '../../../../steplist/types' @@ -32,7 +32,7 @@ import type { FieldProps, FieldPropsByName, FocusHandlers } from './types' export function getBlowoutLocationOptionsForForm(args: { stepType: StepType path?: PathOption | null | undefined -}): Options { +}): DropdownOption[] { const { stepType, path } = args // TODO: Ian 2019-02-21 use i18n for names const destOption = { diff --git a/protocol-designer/src/ui/labware/selectors.ts b/protocol-designer/src/ui/labware/selectors.ts index 77369002aeb..2839d001078 100644 --- a/protocol-designer/src/ui/labware/selectors.ts +++ b/protocol-designer/src/ui/labware/selectors.ts @@ -11,7 +11,7 @@ import type { LabwareEntity, AdditionalEquipmentEntity, } from '@opentrons/step-generation' -import type { DropdownOption, Options } from '@opentrons/components' +import type { DropdownOption } from '@opentrons/components' import type { Selector } from '../../types' import type { AllTemporalPropertiesForTimelineFrame, @@ -32,7 +32,9 @@ export const getLabwareNicknamesById: Selector< displayLabware[id]?.nickname || getLabwareDisplayName(labwareEntity.def) ) ) -export const _sortLabwareDropdownOptions = (options: Options): Options => +export const _sortLabwareDropdownOptions = ( + options: DropdownOption[] +): DropdownOption[] => options.sort((a, b) => { // special case for trash (always at the bottom of the list) if (a.name === TRASH) return 1 @@ -81,7 +83,7 @@ const getNickname = ( /** Returns options for labware dropdowns for moveLabware. * Ordered by display name / nickname, but with trash at the bottom. */ -export const getMoveLabwareOptions: Selector = createSelector( +export const getMoveLabwareOptions: Selector = createSelector( stepFormSelectors.getLabwareEntities, getLabwareNicknamesById, stepFormSelectors.getInitialDeckSetup, @@ -111,10 +113,10 @@ export const getMoveLabwareOptions: Selector = createSelector( const moveLabwareOptions = reduce( labwareEntities, ( - acc: Options, + acc: DropdownOption[], labwareEntity: LabwareEntity, labwareId: string - ): Options => { + ): DropdownOption[] => { const isLabwareInWasteChute = filteredSavedStepFormIds.find( id => @@ -153,7 +155,7 @@ export const getMoveLabwareOptions: Selector = createSelector( /** Returns options for labware dropdowns for moveLiquids. * Ordered by display name / nickname, but with trash at the bottom. */ -export const getLabwareOptions: Selector = createSelector( +export const getLabwareOptions: Selector = createSelector( stepFormSelectors.getLabwareEntities, getLabwareNicknamesById, stepFormSelectors.getInitialDeckSetup, @@ -172,10 +174,10 @@ export const getLabwareOptions: Selector = createSelector( const labwareOptions = reduce( labwareEntities, ( - acc: Options, + acc: DropdownOption[], labwareEntity: LabwareEntity, labwareId: string - ): Options => { + ): DropdownOption[] => { const isLabwareInWasteChute = Object.values(savedStepForms).find( form => form.stepType === 'moveLabware' && @@ -236,7 +238,10 @@ export const getDisposalOptions = createSelector( (additionalEquipment, wasteChuteOption) => { const trashBins = reduce( additionalEquipment, - (acc: Options, additionalEquipment: AdditionalEquipmentEntity): Options => + ( + acc: DropdownOption[], + additionalEquipment: AdditionalEquipmentEntity + ): DropdownOption[] => additionalEquipment.name === 'trashBin' ? [ ...acc, diff --git a/protocol-designer/src/ui/modules/selectors.ts b/protocol-designer/src/ui/modules/selectors.ts index 53cf16ca49e..8fdd6e10c0d 100644 --- a/protocol-designer/src/ui/modules/selectors.ts +++ b/protocol-designer/src/ui/modules/selectors.ts @@ -15,7 +15,7 @@ import { getMagnetLabwareEngageHeight as getMagnetLabwareEngageHeightUtil, getModulesOnDeckByType, } from './utils' -import type { Options } from '@opentrons/components' +import type { DropdownOption } from '@opentrons/components' import type { Selector } from '../../types' import type { LabwareNamesByModuleId } from '../../steplist/types' @@ -35,7 +35,9 @@ export const getLabwareNamesByModuleId: Selector = creat ) /** Returns dropdown option for labware placed on magnetic module */ -export const getMagneticLabwareOptions: Selector = createSelector( +export const getMagneticLabwareOptions: Selector< + DropdownOption[] +> = createSelector( getInitialDeckSetup, getLabwareNicknamesById, (initialDeckSetup, nicknamesById) => { @@ -48,7 +50,9 @@ export const getMagneticLabwareOptions: Selector = createSelector( ) /** Returns dropdown option for labware placed on temperature module */ -export const getTemperatureLabwareOptions: Selector = createSelector( +export const getTemperatureLabwareOptions: Selector< + DropdownOption[] +> = createSelector( getInitialDeckSetup, getLabwareNicknamesById, (initialDeckSetup, nicknamesById) => { @@ -62,7 +66,9 @@ export const getTemperatureLabwareOptions: Selector = createSelector( ) /** Returns dropdown option for labware placed on heater shaker module */ -export const getHeaterShakerLabwareOptions: Selector = createSelector( +export const getHeaterShakerLabwareOptions: Selector< + DropdownOption[] +> = createSelector( getInitialDeckSetup, getLabwareNicknamesById, (initialDeckSetup, nicknamesById) => { diff --git a/protocol-designer/src/ui/modules/utils.ts b/protocol-designer/src/ui/modules/utils.ts index ec2a20a7474..e1d26bb840c 100644 --- a/protocol-designer/src/ui/modules/utils.ts +++ b/protocol-designer/src/ui/modules/utils.ts @@ -3,7 +3,7 @@ import { MAGNETIC_MODULE_V1, getLabwareDefaultEngageHeight, } from '@opentrons/shared-data' -import type { Options } from '@opentrons/components' +import type { DropdownOption } from '@opentrons/components' import type { ModuleType } from '@opentrons/shared-data' import type { ModuleOnDeck, @@ -95,11 +95,11 @@ export function getModuleLabwareOptions( initialDeckSetup: InitialDeckSetup, nicknamesById: Record, type: ModuleType -): Options { +): DropdownOption[] { const labwares = initialDeckSetup.labware const modulesOnDeck = getModulesOnDeckByType(initialDeckSetup, type) const module = getModuleShortNames(type) - let options: Options = [] + let options: DropdownOption[] = [] if (modulesOnDeck != null) { options = modulesOnDeck.map(moduleOnDeck => { From 81a90e4cb8e76a311dda9497a07fdcc76797a850 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:14:20 -0500 Subject: [PATCH 39/42] feat(protocol-designer): prevent user from adding plate reader without gripper (#17152) Here, I prevent saving adding a plate reader in DeckSetupTools if a gripper has not already been added. In a followup, we will enforce a timeline error at for plate reader stepforms that modify the lid state of the reader. TODO: update snackbar copy/confirm that behavior with Design Closes AUTH-1095 --- .../localization/en/starting_deck_state.json | 1 + .../CreateNewProtocolWizard/SelectModules.tsx | 2 + .../Designer/DeckSetup/DeckSetupTools.tsx | 14 ++++++- .../__tests__/DeckSetupTools.test.tsx | 41 +++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/protocol-designer/src/assets/localization/en/starting_deck_state.json b/protocol-designer/src/assets/localization/en/starting_deck_state.json index afa602358ca..acf45939403 100644 --- a/protocol-designer/src/assets/localization/en/starting_deck_state.json +++ b/protocol-designer/src/assets/localization/en/starting_deck_state.json @@ -34,6 +34,7 @@ "edit_slot": "Edit slot", "edit": "Edit", "gen1_gen2_different_units": "Switching between GEN1 and GEN2 Magnetic Modules will clear all non-default engage heights from existing magnet steps in your protocol. GEN1 and GEN2 Magnetic Modules do not use the same units.", + "gripper_required_for_plate_reader": "Gripper required to add absorbance reader", "heater_shaker_adjacent_to": "A module is adjacent to this slot. The Heater-Shaker cannot be placed next to a module", "heater_shaker_adjacent": "A Heater-Shaker is adjacent to this slot. Modules cannot be placed next to a Heater-Shaker", "heater_shaker_trash": "The heater-shaker cannot be next to the trash bin", diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx index dfd05979524..568859d205d 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx @@ -14,6 +14,7 @@ import { WRAP, } from '@opentrons/components' import { + ABSORBANCE_READER_TYPE, ABSORBANCE_READER_V1, FLEX_ROBOT_TYPE, getModuleDisplayName, @@ -70,6 +71,7 @@ export function SelectModules(props: WizardTileProps): JSX.Element | null { TEMPERATURE_MODULE_TYPE, HEATERSHAKER_MODULE_TYPE, MAGNETIC_BLOCK_TYPE, + ABSORBANCE_READER_TYPE, ] const handleAddModule = ( diff --git a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx index 4c41a8f8464..c498a71534c 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx @@ -18,6 +18,7 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { + ABSORBANCE_READER_TYPE, ABSORBANCE_READER_V1, FLEX_ROBOT_TYPE, FLEX_STAGING_AREA_SLOT_ADDRESSABLE_AREAS, @@ -36,6 +37,7 @@ import { deleteDeckFixture, } from '../../../step-forms/actions/additionalItems' import { createModule, deleteModule } from '../../../step-forms/actions' +import { getAdditionalEquipment } from '../../../step-forms/selectors' import { getDeckSetupForActiveItem } from '../../../top-selectors/labware-locations' import { createContainer, @@ -110,6 +112,10 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null { const [changeModuleWarningInfo, displayModuleWarning] = useState( false ) + const additionalEquipment = useSelector(getAdditionalEquipment) + const isGripperAttached = Object.values(additionalEquipment).some( + equipment => equipment?.name === 'gripper' + ) const [selectedHardware, setSelectedHardware] = useState< ModuleModel | Fixture | null >(null) @@ -320,10 +326,16 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null { } if (selectedModuleModel != null) { // create module + const moduleType = getModuleType(selectedModuleModel) + // enforce gripper present in order to add plate reader + if (moduleType === ABSORBANCE_READER_TYPE && !isGripperAttached) { + makeSnackbar(t('gripper_required_for_plate_reader') as string) + return + } dispatch( createModule({ slot, - type: getModuleType(selectedModuleModel), + type: moduleType, model: selectedModuleModel, }) ) diff --git a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/DeckSetupTools.test.tsx b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/DeckSetupTools.test.tsx index 5eab480710e..6a0c7d03c87 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/DeckSetupTools.test.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/DeckSetupTools.test.tsx @@ -2,6 +2,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import '@testing-library/jest-dom/vitest' import { fireEvent, screen } from '@testing-library/react' import { + ABSORBANCE_READER_V1, FLEX_ROBOT_TYPE, HEATERSHAKER_MODULE_V1, fixture96Plate, @@ -9,7 +10,9 @@ import { import { i18n } from '../../../../assets/localization' import { renderWithProviders } from '../../../../__testing-utils__' import { deleteContainer } from '../../../../labware-ingred/actions' +import { useKitchen } from '../../../../organisms/Kitchen/hooks' import { deleteModule } from '../../../../step-forms/actions' +import { getAdditionalEquipment } from '../../../../step-forms/selectors' import { getRobotType } from '../../../../file-data/selectors' import { getEnableAbsorbanceReader } from '../../../../feature-flags/selectors' import { deleteDeckFixture } from '../../../../step-forms/actions/additionalItems' @@ -31,12 +34,16 @@ vi.mock('../../../../step-forms/actions') vi.mock('../../../../step-forms/actions/additionalItems') vi.mock('../../../../labware-ingred/selectors') vi.mock('../../../../tutorial/selectors') +vi.mock('../../../../step-forms/selectors') +vi.mock('../../../../organisms/Kitchen/hooks') const render = (props: React.ComponentProps) => { return renderWithProviders(, { i18nInstance: i18n, })[0] } +const mockMakeSnackbar = vi.fn() + describe('DeckSetupTools', () => { let props: React.ComponentProps @@ -66,6 +73,12 @@ describe('DeckSetupTools', () => { pipettes: {}, }) vi.mocked(getDismissedHints).mockReturnValue([]) + vi.mocked(getAdditionalEquipment).mockReturnValue({}) + vi.mocked(useKitchen).mockReturnValue({ + makeSnackbar: mockMakeSnackbar, + bakeToast: vi.fn(), + eatToast: vi.fn(), + }) }) afterEach(() => { vi.resetAllMocks() @@ -164,4 +177,32 @@ describe('DeckSetupTools', () => { fireEvent.click(screen.getByText('Done')) expect(props.onCloseClick).toHaveBeenCalled() }) + it('should save plate reader if gripper configured', () => { + vi.mocked(getAdditionalEquipment).mockReturnValue({ + gripperUri: { name: 'gripper', id: 'gripperId' }, + }) + vi.mocked(selectors.getZoomedInSlotInfo).mockReturnValue({ + selectedLabwareDefUri: null, + selectedNestedLabwareDefUri: null, + selectedFixture: null, + selectedModuleModel: ABSORBANCE_READER_V1, + selectedSlot: { slot: 'D3', cutout: 'cutoutD3' }, + }) + render(props) + fireEvent.click(screen.getByText('Done')) + expect(props.onCloseClick).toHaveBeenCalled() + }) + it('should prevent saving plate reader and make toast if gripper not configured', () => { + vi.mocked(selectors.getZoomedInSlotInfo).mockReturnValue({ + selectedLabwareDefUri: null, + selectedNestedLabwareDefUri: null, + selectedFixture: null, + selectedModuleModel: ABSORBANCE_READER_V1, + selectedSlot: { slot: 'D3', cutout: 'cutoutD3' }, + }) + render(props) + fireEvent.click(screen.getByText('Done')) + expect(props.onCloseClick).not.toHaveBeenCalled() + expect(mockMakeSnackbar).toHaveBeenCalled() + }) }) From ad0b5865ecb0b007e612176c3945474c054c1992 Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Thu, 19 Dec 2024 15:53:01 -0500 Subject: [PATCH 40/42] refactor(app): report `robotType` in select events (#17153) Closes EXEC-629 and RQA-2386 --- .../DeviceResetSlideout.tsx | 5 +++- .../RenameRobotSlideout.tsx | 4 ++++ .../__tests__/RenameRobotSlideout.test.tsx | 10 ++++++-- .../CalibrationDataDownload.tsx | 6 ++++- .../CalibrationDataDownload.test.tsx | 3 ++- app/src/pages/ODD/NameRobot/index.tsx | 2 ++ .../analytics/__tests__/make-event.test.ts | 10 +++++--- app/src/redux/analytics/make-event.ts | 5 ++++ app/src/redux/analytics/selectors.ts | 23 ++++++++++++++++--- app/src/redux/analytics/types.ts | 3 ++- 10 files changed, 59 insertions(+), 12 deletions(-) diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetSlideout.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetSlideout.tsx index 763ca9f0cb2..bf963b22f29 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetSlideout.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetSlideout.tsx @@ -20,6 +20,7 @@ import { LegacyStyledText, TYPOGRAPHY, } from '@opentrons/components' +import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' import { Slideout } from '/app/atoms/Slideout' import { Divider } from '/app/atoms/structure' @@ -107,7 +108,9 @@ export function DeviceResetSlideout({ e.preventDefault() doTrackEvent({ name: ANALYTICS_CALIBRATION_DATA_DOWNLOADED, - properties: {}, + properties: { + robotType: isFlex ? FLEX_ROBOT_TYPE : OT2_ROBOT_TYPE, + }, }) saveAs( new Blob([ diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx index 55d9806a88f..af75fca2189 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx @@ -3,6 +3,7 @@ import { useSelector, useDispatch } from 'react-redux' import { useNavigate } from 'react-router-dom' import { useForm, Controller } from 'react-hook-form' import { useTranslation } from 'react-i18next' + import { COLORS, Banner, @@ -14,6 +15,8 @@ import { SPACING, } from '@opentrons/components' import { useUpdateRobotNameMutation } from '@opentrons/react-api-client' +import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' + import { removeRobot, getConnectableRobots, @@ -152,6 +155,7 @@ export function RenameRobotSlideout({ properties: { previousRobotName, newRobotName: newRobotName, + robotType: isFlex ? FLEX_ROBOT_TYPE : OT2_ROBOT_TYPE, }, }) handleSubmit(onSubmit)() diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/RenameRobotSlideout.test.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/RenameRobotSlideout.test.tsx index 6f7b1b4ab28..13612c63f19 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/RenameRobotSlideout.test.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/RenameRobotSlideout.test.tsx @@ -2,6 +2,9 @@ import { MemoryRouter } from 'react-router-dom' import { fireEvent, screen, waitFor } from '@testing-library/react' import { describe, it, vi, expect, beforeEach } from 'vitest' import '@testing-library/jest-dom/vitest' + +import { OT2_ROBOT_TYPE } from '@opentrons/shared-data' + import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { useTrackEvent, ANALYTICS_RENAME_ROBOT } from '/app/redux/analytics' @@ -14,7 +17,6 @@ import { mockConnectableRobot, mockReachableRobot, } from '/app/redux/discovery/__fixtures__' - import { RenameRobotSlideout } from '../RenameRobotSlideout' import { useIsFlex } from '/app/redux-resources/robots' @@ -111,7 +113,11 @@ describe('RobotSettings RenameRobotSlideout', () => { await waitFor(() => { expect(mockTrackEvent).toHaveBeenCalledWith({ name: ANALYTICS_RENAME_ROBOT, - properties: { newRobotName: 'mockInput', previousRobotName: 'otie' }, + properties: { + newRobotName: 'mockInput', + previousRobotName: 'otie', + robotType: OT2_ROBOT_TYPE, + }, }) }) }) diff --git a/app/src/organisms/Desktop/RobotSettingsCalibration/CalibrationDataDownload.tsx b/app/src/organisms/Desktop/RobotSettingsCalibration/CalibrationDataDownload.tsx index 4731df09ae4..83aeddf3e35 100644 --- a/app/src/organisms/Desktop/RobotSettingsCalibration/CalibrationDataDownload.tsx +++ b/app/src/organisms/Desktop/RobotSettingsCalibration/CalibrationDataDownload.tsx @@ -17,6 +17,8 @@ import { useInstrumentsQuery, useModulesQuery, } from '@opentrons/react-api-client' +import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' + import { TertiaryButton } from '/app/atoms/buttons' import { useDeckCalibrationData, @@ -72,7 +74,9 @@ export function CalibrationDataDownload({ e.preventDefault() doTrackEvent({ name: ANALYTICS_CALIBRATION_DATA_DOWNLOADED, - properties: {}, + properties: { + robotType: isFlex ? FLEX_ROBOT_TYPE : OT2_ROBOT_TYPE, + }, }) saveAs( new Blob([ diff --git a/app/src/organisms/Desktop/RobotSettingsCalibration/__tests__/CalibrationDataDownload.test.tsx b/app/src/organisms/Desktop/RobotSettingsCalibration/__tests__/CalibrationDataDownload.test.tsx index b84b25e2e16..b50a892ca73 100644 --- a/app/src/organisms/Desktop/RobotSettingsCalibration/__tests__/CalibrationDataDownload.test.tsx +++ b/app/src/organisms/Desktop/RobotSettingsCalibration/__tests__/CalibrationDataDownload.test.tsx @@ -16,6 +16,7 @@ import { useModulesQuery, } from '@opentrons/react-api-client' import { instrumentsResponseFixture } from '@opentrons/api-client' +import { OT2_ROBOT_TYPE } from '@opentrons/shared-data' import { i18n } from '/app/i18n' import { @@ -145,7 +146,7 @@ describe('CalibrationDataDownload', () => { fireEvent.click(downloadButton) expect(mockTrackEvent).toHaveBeenCalledWith({ name: ANALYTICS_CALIBRATION_DATA_DOWNLOADED, - properties: {}, + properties: { robotType: OT2_ROBOT_TYPE }, }) }) diff --git a/app/src/pages/ODD/NameRobot/index.tsx b/app/src/pages/ODD/NameRobot/index.tsx index b0162041963..1417adbbf37 100644 --- a/app/src/pages/ODD/NameRobot/index.tsx +++ b/app/src/pages/ODD/NameRobot/index.tsx @@ -23,6 +23,7 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { useUpdateRobotNameMutation } from '@opentrons/react-api-client' +import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data' import { removeRobot, @@ -166,6 +167,7 @@ export function NameRobot(): JSX.Element { properties: { previousRobotName: previousName, newRobotName: newRobotName, + robotType: FLEX_ROBOT_TYPE, }, }) handleSubmit(onSubmit)() diff --git a/app/src/redux/analytics/__tests__/make-event.test.ts b/app/src/redux/analytics/__tests__/make-event.test.ts index 70506dc162a..8cc56e18950 100644 --- a/app/src/redux/analytics/__tests__/make-event.test.ts +++ b/app/src/redux/analytics/__tests__/make-event.test.ts @@ -1,5 +1,7 @@ import { vi, describe, it, expect, beforeEach } from 'vitest' +import { OT2_ROBOT_TYPE } from '@opentrons/shared-data' + import { makeEvent } from '../make-event' import * as selectors from '../selectors' @@ -49,6 +51,7 @@ describe('analytics events map', () => { name: 'pipetteOffsetCalibrationStarted', properties: { ...action.payload, + robotType: OT2_ROBOT_TYPE, }, }) }) @@ -65,6 +68,7 @@ describe('analytics events map', () => { name: 'tipLengthCalibrationStarted', properties: { ...action.payload, + robotType: OT2_ROBOT_TYPE, }, }) }) @@ -77,6 +81,7 @@ describe('analytics events map', () => { robotName: 'my-robot', sessionId: 'seshid', command: { command: 'calibration.exitSession' }, + robotType: OT2_ROBOT_TYPE, }, } as any vi.mocked(selectors.getAnalyticsSessionExitDetails).mockReturnValue({ @@ -86,7 +91,7 @@ describe('analytics events map', () => { return expect(makeEvent(action, state)).resolves.toEqual({ name: 'my-session-typeExit', - properties: { step: 'session-step' }, + properties: { step: 'session-step', robotType: OT2_ROBOT_TYPE }, }) }) @@ -117,12 +122,11 @@ describe('analytics events map', () => { properties: { pipetteModel: 'my-pipette-model', tipRackDisplayName: 'some display name', + robotType: OT2_ROBOT_TYPE, }, }) }) - }) - describe('events with calibration data', () => { it('analytics:RESOURCE_MONITOR_REPORT -> resourceMonitorReport event', () => { const state = {} as any const action = { diff --git a/app/src/redux/analytics/make-event.ts b/app/src/redux/analytics/make-event.ts index bc5c8955104..608915c4112 100644 --- a/app/src/redux/analytics/make-event.ts +++ b/app/src/redux/analytics/make-event.ts @@ -13,6 +13,7 @@ import { getAnalyticsSessionExitDetails, getSessionInstrumentAnalyticsData, } from './selectors' +import { OT2_ROBOT_TYPE } from '@opentrons/shared-data' import type { State, Action } from '../types' import type { AnalyticsEvent } from './types' @@ -180,6 +181,7 @@ export function makeEvent( name: `${sessionDetails.sessionType}Exit`, properties: { step: sessionDetails.step, + robotType: OT2_ROBOT_TYPE, }, } : null @@ -203,6 +205,7 @@ export function makeEvent( 'tiprackDefinition' in commandData ? commandData.tiprackDefinition.metadata.displayName : null, + robotType: OT2_ROBOT_TYPE, }, } : null @@ -234,6 +237,7 @@ export function makeEvent( name: 'pipetteOffsetCalibrationStarted', properties: { ...action.payload, + robotType: OT2_ROBOT_TYPE, }, }) } @@ -243,6 +247,7 @@ export function makeEvent( name: 'tipLengthCalibrationStarted', properties: { ...action.payload, + robotType: OT2_ROBOT_TYPE, }, }) } diff --git a/app/src/redux/analytics/selectors.ts b/app/src/redux/analytics/selectors.ts index 4751a8eb99e..962f2c55832 100644 --- a/app/src/redux/analytics/selectors.ts +++ b/app/src/redux/analytics/selectors.ts @@ -1,24 +1,24 @@ import * as Sessions from '../sessions' -import { getViewableRobots, getRobotApiVersion } from '../discovery' +import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' +import { getViewableRobots, getRobotApiVersion } from '../discovery' import { getRobotUpdateVersion, getRobotUpdateRobot, getRobotUpdateSession, getRobotSystemType, } from '../robot-update' - import { getRobotSessionById } from '../sessions/selectors' import type { State } from '../types' - import type { AnalyticsConfig, BuildrootAnalyticsData, AnalyticsSessionExitDetails, SessionInstrumentAnalyticsData, } from './types' +import type { RobotType } from '@opentrons/shared-data' export function getBuildrootAnalyticsData( state: State, @@ -40,12 +40,29 @@ export function getBuildrootAnalyticsData( const currentVersion = getRobotApiVersion(robot) ?? 'unknown' const currentSystem = getRobotSystemType(robot) ?? 'unknown' + const getRobotType = (): RobotType | undefined => { + switch (currentSystem) { + case 'flex': + return FLEX_ROBOT_TYPE + case 'ot2-buildroot': + case 'ot2-balena': + return OT2_ROBOT_TYPE + case 'unknown': + return undefined + default: { + console.error('Unexpected system type: ', currentSystem) + return undefined + } + } + } + return { currentVersion, currentSystem, updateVersion: updateVersion ?? 'unknown', error: session != null && 'error' in session ? session.error : null, robotSerialNumber, + robotType: getRobotType(), } } diff --git a/app/src/redux/analytics/types.ts b/app/src/redux/analytics/types.ts index d27c2955fe2..95b320e88ab 100644 --- a/app/src/redux/analytics/types.ts +++ b/app/src/redux/analytics/types.ts @@ -1,4 +1,4 @@ -import type { PipetteMount as Mount } from '@opentrons/shared-data' +import type { PipetteMount as Mount, RobotType } from '@opentrons/shared-data' import type { CalibrationCheckComparisonsPerCalibration } from '../sessions/types' import type { DeckCalibrationStatus } from '../calibration/types' import type { Config } from '../config/types' @@ -42,6 +42,7 @@ export interface BuildrootAnalyticsData { updateVersion: string error: string | null robotSerialNumber: string | null + robotType: RobotType | undefined } export interface PipetteOffsetCalibrationAnalyticsData { From efac75b412dfd4337152c754a8205750f499fcc8 Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Thu, 19 Dec 2024 19:24:39 -0500 Subject: [PATCH 41/42] fix(protocol-designer): dropdown option text refinement (#17151) closes RQA-3773 and RQA-3774 --- .../hardware-sim/DeckConfigurator/index.tsx | 2 + .../src/molecules/DropdownMenu/index.tsx | 28 +++++- .../molecules/DropdownStepFormField/index.tsx | 28 +++++- .../__tests__/MaterialsListModal.test.tsx | 2 +- .../top-selectors/labware-locations/index.ts | 14 +-- .../ui/labware/__tests__/selectors.test.ts | 44 +++++---- protocol-designer/src/ui/labware/selectors.ts | 73 +++++++------- protocol-designer/src/ui/labware/utils.ts | 99 ++++++++++++------- protocol-designer/src/ui/modules/utils.ts | 39 +++++--- 9 files changed, 211 insertions(+), 118 deletions(-) diff --git a/components/src/hardware-sim/DeckConfigurator/index.tsx b/components/src/hardware-sim/DeckConfigurator/index.tsx index 4a03ff6c866..65bb6968a45 100644 --- a/components/src/hardware-sim/DeckConfigurator/index.tsx +++ b/components/src/hardware-sim/DeckConfigurator/index.tsx @@ -38,6 +38,8 @@ import { MagneticBlockFixture } from './MagneticBlockFixture' import { ThermocyclerFixture } from './ThermocyclerFixture' import { AbsorbanceReaderFixture } from './AbsorbanceReaderFixture' +export * from './constants' + interface DeckConfiguratorProps { deckConfig: DeckConfiguration handleClickAdd: (cutoutId: CutoutId) => void diff --git a/components/src/molecules/DropdownMenu/index.tsx b/components/src/molecules/DropdownMenu/index.tsx index 3fb38f8f531..3b692c0b3dc 100644 --- a/components/src/molecules/DropdownMenu/index.tsx +++ b/components/src/molecules/DropdownMenu/index.tsx @@ -24,6 +24,7 @@ import { MenuItem } from '../../atoms/MenuList/MenuItem' import { Tooltip } from '../../atoms/Tooltip' import { StyledText } from '../../atoms/StyledText' import { LiquidIcon } from '../LiquidIcon' +import { DeckInfoLabel } from '../DeckInfoLabel' export interface DropdownOption { name: string @@ -32,6 +33,8 @@ export interface DropdownOption { liquidColor?: string /** optional dropdown option for adding the deck label */ deckLabel?: string + /** subtext below the name */ + subtext?: string disabled?: boolean tooltipText?: string } @@ -250,7 +253,11 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { {currentOption.liquidColor != null ? ( ) : null} + {currentOption.deckLabel != null ? ( + + ) : null} ) : null} - {option.name} + {option.deckLabel != null ? ( + + ) : null} + + + {option.name} + + + {option.subtext} + + {option.tooltipText != null ? ( diff --git a/protocol-designer/src/molecules/DropdownStepFormField/index.tsx b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx index 2714a73156b..d40fcc7063f 100644 --- a/protocol-designer/src/molecules/DropdownStepFormField/index.tsx +++ b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx @@ -1,8 +1,10 @@ import { useTranslation } from 'react-i18next' import { useDispatch } from 'react-redux' import { + ALIGN_CENTER, COLORS, DIRECTION_COLUMN, + DeckInfoLabel, DropdownMenu, Flex, ListItem, @@ -108,10 +110,28 @@ export function DropdownStepFormField( {title} - - - {options[0].name} - + + {options[0].deckLabel != null ? ( + + ) : null} + + + {options[0].name} + + + {options[0].subtext} + +
diff --git a/protocol-designer/src/organisms/MaterialsListModal/__tests__/MaterialsListModal.test.tsx b/protocol-designer/src/organisms/MaterialsListModal/__tests__/MaterialsListModal.test.tsx index d18fa1e52de..26e2d0fb098 100644 --- a/protocol-designer/src/organisms/MaterialsListModal/__tests__/MaterialsListModal.test.tsx +++ b/protocol-designer/src/organisms/MaterialsListModal/__tests__/MaterialsListModal.test.tsx @@ -137,7 +137,7 @@ describe('MaterialsListModal', () => { lidTargetTemp: null, lidOpen: false, }, - slot: 'span7_8_10_11', + slot: '7', type: 'thermocyclerModuleType', }, ] as ModuleOnDeck[] diff --git a/protocol-designer/src/top-selectors/labware-locations/index.ts b/protocol-designer/src/top-selectors/labware-locations/index.ts index 34cd5fad561..6a2c5143b00 100644 --- a/protocol-designer/src/top-selectors/labware-locations/index.ts +++ b/protocol-designer/src/top-selectors/labware-locations/index.ts @@ -166,8 +166,8 @@ export const getUnoccupiedLabwareLocationOptions: Selector< { name: modIdWithAdapter != null - ? `${adapterDisplayName} on top of ${moduleUnderAdapter} in slot ${moduleSlotInfo}` - : `${adapterDisplayName} on slot ${adapterSlotInfo}`, + ? `${moduleSlotInfo} on ${moduleUnderAdapter} with ${adapterDisplayName}` + : `${adapterSlotInfo} with ${adapterDisplayName}`, value: labwareId, }, ] @@ -186,13 +186,9 @@ export const getUnoccupiedLabwareLocationOptions: Selector< : [ ...acc, { - name: `${getModuleDisplayName( + name: `${modOnDeck.slot} on ${getModuleDisplayName( moduleEntities[modId].model - )} in slot ${ - modOnDeck.slot === 'span7_8_10_11' - ? '7, 8, 10, 11' - : modOnDeck.slot - }`, + )}`, value: modId, }, ] @@ -234,7 +230,7 @@ export const getUnoccupiedLabwareLocationOptions: Selector< ) }) .map(slotId => ({ name: slotId, value: slotId })) - const offDeck = { name: 'Off-Deck', value: 'offDeck' } + const offDeck = { name: 'Off-deck', value: 'offDeck' } const wasteChuteSlot = { name: 'Waste Chute in D3', value: WASTE_CHUTE_CUTOUT, diff --git a/protocol-designer/src/ui/labware/__tests__/selectors.test.ts b/protocol-designer/src/ui/labware/__tests__/selectors.test.ts index 00359673dbb..e2c74b75508 100644 --- a/protocol-designer/src/ui/labware/__tests__/selectors.test.ts +++ b/protocol-designer/src/ui/labware/__tests__/selectors.test.ts @@ -9,7 +9,6 @@ import { THERMOCYCLER_MODULE_TYPE, THERMOCYCLER_MODULE_V1, } from '@opentrons/shared-data' -import { SPAN7_8_10_11_SLOT } from '../../../constants' import { getDisposalOptions, getLabwareOptions, @@ -102,7 +101,7 @@ describe('labware selectors', () => { expect( // @ts-expect-error(sa, 2021-6-15): resultFunc getDisposalOptions.resultFunc(additionalEquipmentEntities) - ).toEqual([{ name: 'Trash Bin', value: mockTrashId }]) + ).toEqual([{ name: 'Trash bin', value: mockTrashId }]) }) it('filters out additional equipment that is NOT trash when multiple trash bins present', () => { const mockTrashId = 'mockTrashId' @@ -129,8 +128,8 @@ describe('labware selectors', () => { // @ts-expect-error(sa, 2021-6-15): resultFunc getDisposalOptions.resultFunc(additionalEquipmentEntities) ).toEqual([ - { name: 'Trash Bin', value: mockTrashId }, - { name: 'Trash Bin', value: mockTrashId2 }, + { name: 'Trash bin', value: mockTrashId }, + { name: 'Trash bin', value: mockTrashId2 }, ]) }) }) @@ -142,7 +141,12 @@ describe('labware selectors', () => { getLabwareOptions.resultFunc( {}, {}, - { labware: {}, modules: {}, pipettes: {} }, + { + labware: {}, + modules: {}, + pipettes: {}, + additionalEquipmentOnDeck: {}, + }, {}, {}, {} @@ -153,13 +157,13 @@ describe('labware selectors', () => { it('should return labware options when no modules are present, with no tipracks', () => { const labwareEntities = { ...tipracks, - ...trash, ...otherLabware, } const initialDeckSetup = { labware: labwareEntities, modules: {}, pipettes: {}, + additionalEquipmentOnDeck: {}, } expect( // @ts-expect-error(sa, 2021-6-15): resultFunc @@ -171,13 +175,10 @@ describe('labware selectors', () => { {}, {} ) - ).toEqual([ - { name: 'Source Plate', value: 'wellPlateId' }, - { name: 'Trash', value: mockTrash }, - ]) + ).toEqual([{ name: 'Source Plate', value: 'wellPlateId' }]) }) - it('should return labware options with module prefixes when a labware is on module', () => { + it('should return labware options with no module prefixes even when a labware is on module', () => { const labware = { wellPlateId: { ...otherLabware.wellPlateId, @@ -206,6 +207,9 @@ describe('labware selectors', () => { ...trash, ...labware, }, + additionalEquipmentOnDeck: { + trash: { id: 'trash', location: 'cutout12', name: 'trashBin' }, + }, modules: { magModuleId: { id: 'magModuleId', @@ -223,7 +227,7 @@ describe('labware selectors', () => { id: 'thermocyclerId', type: THERMOCYCLER_MODULE_TYPE, model: THERMOCYCLER_MODULE_V1, - slot: SPAN7_8_10_11_SLOT, + slot: '8', }, heaterShakerId: { id: 'heaterShakerId', @@ -253,11 +257,11 @@ describe('labware selectors', () => { {} ) ).toEqual([ - { name: 'HS Plate in Heater-Shaker', value: 'hsPlateId' }, - { name: 'TC Plate in Thermocycler', value: 'tcPlateId' }, - { name: 'Temp Plate in Temperature Module', value: 'tempPlateId' }, + { name: 'HS Plate in 6', value: 'hsPlateId' }, + { name: 'TC Plate in A1+B1', value: 'tcPlateId' }, + { name: 'Temp Plate in 3', value: 'tempPlateId' }, { name: 'Trash', value: mockTrash }, - { name: 'Well Plate in Magnetic Module', value: 'wellPlateId' }, + { name: 'Well Plate in 1', value: 'wellPlateId' }, ]) }) @@ -272,7 +276,6 @@ describe('labware selectors', () => { const initialDeckSetup = { pipettes: {}, labware: { - ...trash, ...labware, }, modules: { @@ -283,6 +286,9 @@ describe('labware selectors', () => { slot: '1', }, }, + additionalEquipmentOnDeck: { + trash: { id: 'trash', name: 'trashBin', location: 'cutout12' }, + }, } const nicknames: Record = { @@ -312,14 +318,14 @@ describe('labware selectors', () => { ) ).toEqual([ { name: 'Trash', value: mockTrash }, - { name: 'Well Plate in Magnetic Module', value: 'wellPlateId' }, + { name: 'Well Plate in 1', value: 'wellPlateId' }, ]) }) }) describe('_sortLabwareDropdownOptions', () => { const trashOption = { - name: 'Trash Bin', + name: 'Trash bin', value: mockTrash, } const zzzPlateOption = { name: 'Zzz Plate', value: 'zzz' } diff --git a/protocol-designer/src/ui/labware/selectors.ts b/protocol-designer/src/ui/labware/selectors.ts index 2839d001078..34d5818611f 100644 --- a/protocol-designer/src/ui/labware/selectors.ts +++ b/protocol-designer/src/ui/labware/selectors.ts @@ -1,25 +1,32 @@ import { createSelector } from 'reselect' import mapValues from 'lodash/mapValues' import reduce from 'lodash/reduce' -import { getIsTiprack, getLabwareDisplayName } from '@opentrons/shared-data' +import { + TRASH_BIN_DISPLAY_NAME, + WASTE_CHUTE_DISPLAY_NAME, +} from '@opentrons/components' +import { + FLEX_ROBOT_TYPE, + OT2_ROBOT_TYPE, + getIsTiprack, + getLabwareDisplayName, +} from '@opentrons/shared-data' import * as stepFormSelectors from '../../step-forms/selectors' import { selectors as labwareIngredSelectors } from '../../labware-ingred/selectors' -import { getModuleShortNames, getModuleUnderLabware } from '../modules/utils' -import { getLabwareOffDeck, getLabwareInColumn4 } from './utils' +import { getLabwareLatestSlot } from './utils' import type { LabwareEntity, AdditionalEquipmentEntity, } from '@opentrons/step-generation' import type { DropdownOption } from '@opentrons/components' +import type { RobotType } from '@opentrons/shared-data' import type { Selector } from '../../types' import type { AllTemporalPropertiesForTimelineFrame, SavedStepFormState, } from '../../step-forms' -const TRASH = 'Trash Bin' - export const getLabwareNicknamesById: Selector< Record > = createSelector( @@ -37,8 +44,8 @@ export const _sortLabwareDropdownOptions = ( ): DropdownOption[] => options.sort((a, b) => { // special case for trash (always at the bottom of the list) - if (a.name === TRASH) return 1 - if (b.name === TRASH) return -1 + if (a.name === TRASH_BIN_DISPLAY_NAME) return 1 + if (b.name === TRASH_BIN_DISPLAY_NAME) return -1 // sort by name everything else by name return a.name.localeCompare(b.name) }) @@ -47,35 +54,21 @@ const getNickname = ( nicknamesById: Record, initialDeckSetup: AllTemporalPropertiesForTimelineFrame, labwareId: string, - savedStepForms: SavedStepFormState + savedStepForms: SavedStepFormState, + robotType: RobotType ): string => { - const isOffDeck = getLabwareOffDeck( + const latestSlot = getLabwareLatestSlot( initialDeckSetup, savedStepForms ?? {}, - labwareId - ) - - const moduleOnDeck = getModuleUnderLabware( - initialDeckSetup, - savedStepForms ?? {}, - labwareId - ) - const module = - moduleOnDeck != null ? getModuleShortNames(moduleOnDeck.type) : null - - const isLabwareInColumn4 = getLabwareInColumn4( - initialDeckSetup, - savedStepForms ?? {}, - labwareId + labwareId, + robotType ) let nickName: string = nicknamesById[labwareId] - if (module != null) { - nickName = `${nicknamesById[labwareId]} in ${module}` - } else if (isOffDeck) { + if (latestSlot != null && latestSlot !== 'offDeck') { + nickName = `${nicknamesById[labwareId]} in ${latestSlot}` + } else if (latestSlot != null && latestSlot === 'offDeck') { nickName = `${nicknamesById[labwareId]} off-deck` - } else if (isLabwareInColumn4) { - nickName = `${nicknamesById[labwareId]} in staging area slot` } return nickName } @@ -110,6 +103,12 @@ export const getMoveLabwareOptions: Selector = createSelector( const wasteChuteLocation = Object.values(additionalEquipmentEntities).find( aE => aE.name === 'wasteChute' )?.location + const trashBinLocation = Object.values(additionalEquipmentEntities).find( + aE => aE.name === 'trashBin' + )?.location + const robotType = + trashBinLocation === 'cutout12' ? OT2_ROBOT_TYPE : FLEX_ROBOT_TYPE + const moveLabwareOptions = reduce( labwareEntities, ( @@ -131,7 +130,8 @@ export const getMoveLabwareOptions: Selector = createSelector( nicknamesById, initialDeckSetup, labwareId, - savedStepForms + savedStepForms, + robotType ) // filter out moving trash, adapters, and labware in @@ -171,6 +171,12 @@ export const getLabwareOptions: Selector = createSelector( const wasteChuteLocation = Object.values(additionalEquipmentEntities).find( aE => aE.name === 'wasteChute' )?.location + const trashBinLocation = Object.values(additionalEquipmentEntities).find( + aE => aE.name === 'trashBin' + )?.location + const robotType = + trashBinLocation === 'cutout12' ? OT2_ROBOT_TYPE : FLEX_ROBOT_TYPE + const labwareOptions = reduce( labwareEntities, ( @@ -191,7 +197,8 @@ export const getLabwareOptions: Selector = createSelector( nicknamesById, initialDeckSetup, labwareId, - savedStepForms + savedStepForms, + robotType ) return getIsTiprack(labwareEntity.def) || @@ -222,7 +229,7 @@ export const getWasteChuteOption: Selector = createSelect const wasteChuteOption: DropdownOption | null = wasteChuteEntity != null ? { - name: 'Waste Chute', + name: WASTE_CHUTE_DISPLAY_NAME, value: wasteChuteEntity.id, } : null @@ -246,7 +253,7 @@ export const getDisposalOptions = createSelector( ? [ ...acc, { - name: TRASH, + name: TRASH_BIN_DISPLAY_NAME, value: additionalEquipment.id ?? '', }, ] diff --git a/protocol-designer/src/ui/labware/utils.ts b/protocol-designer/src/ui/labware/utils.ts index 2377f7976db..d55c35b578f 100644 --- a/protocol-designer/src/ui/labware/utils.ts +++ b/protocol-designer/src/ui/labware/utils.ts @@ -1,39 +1,54 @@ -import { COLUMN_4_SLOTS } from '@opentrons/step-generation' +import { getHasWasteChute } from '@opentrons/step-generation' +import { WASTE_CHUTE_DISPLAY_NAME } from '@opentrons/components' +import { + FLEX_ROBOT_TYPE, + TC_MODULE_LOCATION_OT2, + TC_MODULE_LOCATION_OT3, + THERMOCYCLER_MODULE_TYPE, +} from '@opentrons/shared-data' +import type { RobotType } from '@opentrons/shared-data' import type { InitialDeckSetup, SavedStepFormState } from '../../step-forms' -export function getLabwareOffDeck( - initialDeckSetup: InitialDeckSetup, - savedStepFormState: SavedStepFormState, - labwareId: string -): boolean { - // latest moveLabware step related to labwareId - const moveLabwareStep = Object.values(savedStepFormState) - .filter( - state => - state.stepType === 'moveLabware' && - labwareId != null && - state.labware === labwareId - ) - .reverse()[0] - - if (moveLabwareStep?.newLocation === 'offDeck') { - return true - } else if ( - moveLabwareStep == null && - initialDeckSetup.labware[labwareId]?.slot === 'offDeck' - ) { - return true - } else return false +function resolveSlotLocation( + modules: InitialDeckSetup['modules'], + labware: InitialDeckSetup['labware'], + location: string, + robotType: RobotType +): string { + const TCSlot = + robotType === FLEX_ROBOT_TYPE + ? TC_MODULE_LOCATION_OT3 + : TC_MODULE_LOCATION_OT2 + if (location === 'offDeck') { + return 'offDeck' + } else if (modules[location] != null) { + return modules[location].type === THERMOCYCLER_MODULE_TYPE + ? TCSlot + : modules[location].slot + } else if (labware[location] != null) { + const adapter = labware[location] + if (modules[adapter.slot] != null) { + return modules[adapter.slot].type === THERMOCYCLER_MODULE_TYPE + ? TCSlot + : modules[adapter.slot].slot + } else { + return adapter.slot + } + } else { + return location + } } -export function getLabwareInColumn4( +export function getLabwareLatestSlot( initialDeckSetup: InitialDeckSetup, savedStepForms: SavedStepFormState, - labwareId: string -): boolean { - const isStartingInColumn4 = COLUMN_4_SLOTS.includes( - initialDeckSetup.labware[labwareId]?.slot - ) + labwareId: string, + robotType: RobotType +): string | null { + const { modules, labware, additionalEquipmentOnDeck } = initialDeckSetup + const initialSlot = labware[labwareId]?.slot + const hasWasteChute = getHasWasteChute(additionalEquipmentOnDeck) + // latest moveLabware step related to labwareId const moveLabwareStep = Object.values(savedStepForms) .filter( @@ -45,13 +60,25 @@ export function getLabwareInColumn4( .reverse()[0] if ( - moveLabwareStep?.newLocation != null && - COLUMN_4_SLOTS.includes(moveLabwareStep.newLocation as string) + hasWasteChute && + (initialSlot === 'D3' || moveLabwareStep?.newLocation === 'D3') ) { - return true - } else if (moveLabwareStep == null && isStartingInColumn4) { - return true + return WASTE_CHUTE_DISPLAY_NAME + } + + if (moveLabwareStep?.newLocation != null) { + return resolveSlotLocation( + modules, + labware, + moveLabwareStep.newLocation as string, + robotType + ) + } else if (moveLabwareStep == null) { + return resolveSlotLocation(modules, labware, initialSlot, robotType) } else { - return false + console.warn( + `Expected to find labware's location but could not with initial slot ${initialSlot}` + ) + return null } } diff --git a/protocol-designer/src/ui/modules/utils.ts b/protocol-designer/src/ui/modules/utils.ts index e1d26bb840c..d347c1b5388 100644 --- a/protocol-designer/src/ui/modules/utils.ts +++ b/protocol-designer/src/ui/modules/utils.ts @@ -1,7 +1,13 @@ import values from 'lodash/values' import { - MAGNETIC_MODULE_V1, + ABSORBANCE_READER_TYPE, getLabwareDefaultEngageHeight, + HEATERSHAKER_MODULE_TYPE, + MAGNETIC_BLOCK_TYPE, + MAGNETIC_MODULE_TYPE, + MAGNETIC_MODULE_V1, + TEMPERATURE_MODULE_TYPE, + THERMOCYCLER_MODULE_TYPE, } from '@opentrons/shared-data' import type { DropdownOption } from '@opentrons/components' import type { ModuleType } from '@opentrons/shared-data' @@ -76,17 +82,17 @@ export function getModuleUnderLabware( export const getModuleShortNames = (type: ModuleType): string => { switch (type) { - case 'heaterShakerModuleType': - return 'Heater-Shaker' - case 'magneticBlockType': + case HEATERSHAKER_MODULE_TYPE: + return 'Heater-Shaker Module' + case MAGNETIC_BLOCK_TYPE: return 'Magnetic Block' - case 'magneticModuleType': + case MAGNETIC_MODULE_TYPE: return 'Magnetic Module' - case 'temperatureModuleType': + case TEMPERATURE_MODULE_TYPE: return 'Temperature Module' - case 'thermocyclerModuleType': + case THERMOCYCLER_MODULE_TYPE: return 'Thermocycler' - case 'absorbanceReaderType': + case ABSORBANCE_READER_TYPE: return 'Absorbance Reader' } } @@ -110,22 +116,25 @@ export function getModuleLabwareOptions( )?.id if (labwareOnAdapterId != null) { return { - name: `${nicknamesById[labwareOnAdapterId]} in ${ - nicknamesById[labware.id] - } in ${module} in slot ${moduleOnDeck.slot}`, + name: `${nicknamesById[labware.id]} with ${ + nicknamesById[labwareOnAdapterId] + }`, + deckLabel: moduleOnDeck.slot, + subtext: module, value: moduleOnDeck.id, } } else { return { - name: `${nicknamesById[labware.id]} in ${module} in slot ${ - moduleOnDeck.slot - }`, + name: nicknamesById[labware.id], + deckLabel: moduleOnDeck.slot, + subtext: module, value: moduleOnDeck.id, } } } else { return { - name: `No labware in ${module} in slot ${moduleOnDeck.slot}`, + name: module, + deckLabel: moduleOnDeck.slot, value: moduleOnDeck.id, } } From 47dbbe95d02d7cbcc64ea5d398dca3fd80ec68e4 Mon Sep 17 00:00:00 2001 From: koji Date: Fri, 20 Dec 2024 09:20:47 -0500 Subject: [PATCH 42/42] chore(protocol-designer): remove classnames from pd (#17148) * chore(protocol-designer): remove classnames from pd --- protocol-designer/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/protocol-designer/package.json b/protocol-designer/package.json index 95f5acf4813..8be7d0a965b 100755 --- a/protocol-designer/package.json +++ b/protocol-designer/package.json @@ -33,7 +33,6 @@ "@typescript-eslint/eslint-plugin": "^6.10.0", "@typescript-eslint/parser": "^6.10.0", "ajv": "6.12.3", - "classnames": "2.2.5", "cookie": "0.3.1", "core-js": "3.2.1", "date-fns": "2.10.0",