diff --git a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a9557d762c][Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp].json b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a9557d762c][Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp].json index b316741d29b..60a0f1c77a3 100644 --- a/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a9557d762c][Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp].json +++ b/analyses-snapshot-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a9557d762c][Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp].json @@ -24,7 +24,7 @@ "errors": [ { "createdAt": "TIMESTAMP", - "detail": "APIVersionError [line 15]: Fixed Trash is not supported on Flex protocols in API Version 2.16 and above.", + "detail": "UnsupportedAPIError [line 15]: Error 4002 API_REMOVED (UnsupportedAPIError): Fixed Trash is not available after API version 2.16. You are currently using API version 2.16. Fixed trash is no longer supported on Flex protocols.", "errorCode": "4000", "errorInfo": {}, "errorType": "ExceptionInProtocolError", @@ -33,14 +33,14 @@ "wrappedErrors": [ { "createdAt": "TIMESTAMP", - "detail": "opentrons.protocols.api_support.util.APIVersionError: Fixed Trash is not supported on Flex protocols in API Version 2.16 and above.", - "errorCode": "4000", + "detail": "Fixed Trash is not available after API version 2.16. You are currently using API version 2.16. Fixed trash is no longer supported on Flex protocols.", + "errorCode": "4002", "errorInfo": { - "args": "('Fixed Trash is not supported on Flex protocols in API Version 2.16 and above.',)", - "class": "APIVersionError", - "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 \"Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line N, in fixed_trash\n raise APIVersionError(\n" + "current_version": "2.16", + "identifier": "Fixed Trash", + "since_version": "2.16" }, - "errorType": "PythonException", + "errorType": "UnsupportedAPIError", "id": "UUID", "isDefined": false, "wrappedErrors": [] diff --git a/api/src/opentrons/protocol_api/core/engine/instrument.py b/api/src/opentrons/protocol_api/core/engine/instrument.py index 6c93c154fa0..fcf853067fc 100644 --- a/api/src/opentrons/protocol_api/core/engine/instrument.py +++ b/api/src/opentrons/protocol_api/core/engine/instrument.py @@ -811,20 +811,11 @@ def configure_nozzle_layout( primaryNozzle=cast(PRIMARY_NOZZLE_LITERAL, primary_nozzle) ) ) - elif style == NozzleLayout.PARTIAL_COLUMN: - assert primary_nozzle is not None - assert front_right_nozzle is not None or back_left_nozzle is not None - configuration_model = QuadrantNozzleLayoutConfiguration( - primaryNozzle=cast(PRIMARY_NOZZLE_LITERAL, primary_nozzle), - frontRightNozzle=front_right_nozzle, - backLeftNozzle=back_left_nozzle, - ) elif style == NozzleLayout.ROW: configuration_model = RowNozzleLayoutConfiguration( primaryNozzle=cast(PRIMARY_NOZZLE_LITERAL, primary_nozzle) ) - elif style == NozzleLayout.QUADRANT: - assert front_right_nozzle is not None or back_left_nozzle is not None + elif style == NozzleLayout.QUADRANT or style == NozzleLayout.PARTIAL_COLUMN: configuration_model = QuadrantNozzleLayoutConfiguration( primaryNozzle=cast(PRIMARY_NOZZLE_LITERAL, primary_nozzle), frontRightNozzle=front_right_nozzle, diff --git a/api/src/opentrons/protocol_api/instrument_context.py b/api/src/opentrons/protocol_api/instrument_context.py index 3bc3eba0d87..b61fa70cdc9 100644 --- a/api/src/opentrons/protocol_api/instrument_context.py +++ b/api/src/opentrons/protocol_api/instrument_context.py @@ -2030,6 +2030,15 @@ def configure_nozzle_layout( # noqa: C901 f"Nozzle layout configuration of style {style.value} is currently unsupported." ) + original_enabled_layouts = [NozzleLayout.COLUMN, NozzleLayout.ALL] + if ( + self._api_version + < _PARTIAL_NOZZLE_CONFIGURATION_SINGLE_ROW_PARTIAL_COLUMN_ADDED_IN + ) and (style not in original_enabled_layouts): + raise ValueError( + f"Nozzle layout configuration of style {style.value} is unsupported in API Versions lower than {_PARTIAL_NOZZLE_CONFIGURATION_SINGLE_ROW_PARTIAL_COLUMN_ADDED_IN}." + ) + if style != NozzleLayout.ALL: if start is None: raise ValueError( @@ -2040,43 +2049,35 @@ def configure_nozzle_layout( # noqa: C901 f"Starting nozzle specified is not one of {types.ALLOWED_PRIMARY_NOZZLES}" ) if style == NozzleLayout.QUADRANT: - if front_right is None: + if front_right is None and back_left is None: raise ValueError( - "Cannot configure a QUADRANT layout without a front right nozzle." + "Cannot configure a QUADRANT layout without a front right or back left nozzle." ) - original_enabled_layouts = [NozzleLayout.COLUMN, NozzleLayout.ALL] - if ( - self._api_version - < _PARTIAL_NOZZLE_CONFIGURATION_SINGLE_ROW_PARTIAL_COLUMN_ADDED_IN - ): - if style not in original_enabled_layouts: + + front_right_resolved = front_right + back_left_resolved = back_left + if style == NozzleLayout.PARTIAL_COLUMN: + if end is None: + raise ValueError( + "Parameter 'end' is required for Partial Column Nozzle Configuration Layout." + ) + if front_right is not None or back_left is not None: raise ValueError( - f"Nozzle layout configuration of style {style.value} is unsupported in API Versions lower than {_PARTIAL_NOZZLE_CONFIGURATION_SINGLE_ROW_PARTIAL_COLUMN_ADDED_IN}." + "Parameters 'front_right' and 'back_left' cannot be used with Partial Column Nozzle Configuration Layout." ) - if style == NozzleLayout.PARTIAL_COLUMN: + # Determine if 'end' will be configured as front_right or back_left if start == "H1" or start == "H12": - self._core.configure_nozzle_layout( - style, - primary_nozzle=start, - front_right_nozzle=front_right, - back_left_nozzle=end, - ) + back_left_resolved = end elif start == "A1" or start == "A12": - self._core.configure_nozzle_layout( - style, - primary_nozzle=start, - front_right_nozzle=end, - back_left_nozzle=back_left, - ) - else: - self._core.configure_nozzle_layout( - style, - primary_nozzle=start, - front_right_nozzle=front_right, - back_left_nozzle=back_left, - ) - # TODO (spp, 2023-12-05): verify that tipracks are on adapters for only full 96 channel config + front_right_resolved = end + + self._core.configure_nozzle_layout( + style, + primary_nozzle=start, + front_right_nozzle=front_right_resolved, + back_left_nozzle=back_left_resolved, + ) self._tip_racks = tip_racks or [] @requires_version(2, 20)