From 82e9b7612e30123fb1d029c62bcc3fdf9f64525a Mon Sep 17 00:00:00 2001 From: tadelesh Date: Thu, 5 Dec 2024 16:19:11 +0800 Subject: [PATCH 1/5] refine exception handling logic --- .../http-client-python/emitter/src/http.ts | 2 +- .../generator/pygen/codegen/__init__.py | 12 +++ .../pygen/codegen/models/operation.py | 19 +---- .../pygen/codegen/models/response.py | 4 +- .../codegen/serializers/builder_serializer.py | 83 +++++++------------ .../codegen/templates/model_base.py.jinja2 | 17 ++++ packages/http-client-python/package-lock.json | 4 +- 7 files changed, 66 insertions(+), 75 deletions(-) diff --git a/packages/http-client-python/emitter/src/http.ts b/packages/http-client-python/emitter/src/http.ts index ad62dd4082d..cd2ae439047 100644 --- a/packages/http-client-python/emitter/src/http.ts +++ b/packages/http-client-python/emitter/src/http.ts @@ -379,7 +379,7 @@ function emitHttpResponse( headers: response.headers.map((x) => emitHttpResponseHeader(context, x)), statusCodes: typeof statusCodes === "object" - ? [(statusCodes as HttpStatusCodeRange).start] + ? [[(statusCodes as HttpStatusCodeRange).start, (statusCodes as HttpStatusCodeRange).end]] : statusCodes === "*" ? ["default"] : [statusCodes], diff --git a/packages/http-client-python/generator/pygen/codegen/__init__.py b/packages/http-client-python/generator/pygen/codegen/__init__.py index 11d829263ce..1ab9bd6237e 100644 --- a/packages/http-client-python/generator/pygen/codegen/__init__.py +++ b/packages/http-client-python/generator/pygen/codegen/__init__.py @@ -241,6 +241,16 @@ def _validate_code_model_options(self) -> None: if not self.options_retriever.is_azure_flavor and self.options_retriever.tracing: raise ValueError("Can only have tracing turned on for Azure SDKs.") + @staticmethod + def sort_exceptions(yaml_data: Dict[str, Any]) -> None: + for client in yaml_data["clients"]: + for group in client["operationGroups"]: + for operation in group["operations"]: + if not operation.get("exceptions"): + continue + # sort exceptions by status code, first single status code, then range, then default + operation["exceptions"] = sorted(operation["exceptions"], key=lambda x: 3 if x["statusCodes"][0] == "default" else (1 if isinstance(x["statusCodes"][0], int) else 2)) + @staticmethod def remove_cloud_errors(yaml_data: Dict[str, Any]) -> None: for client in yaml_data["clients"]: @@ -315,6 +325,8 @@ def process(self) -> bool: self._validate_code_model_options() options = self._build_code_model_options() yaml_data = self.get_yaml() + + self.sort_exceptions(yaml_data) if self.options_retriever.azure_arm: self.remove_cloud_errors(yaml_data) diff --git a/packages/http-client-python/generator/pygen/codegen/models/operation.py b/packages/http-client-python/generator/pygen/codegen/models/operation.py index 06631ca9078..fa10d5bc1fb 100644 --- a/packages/http-client-python/generator/pygen/codegen/models/operation.py +++ b/packages/http-client-python/generator/pygen/codegen/models/operation.py @@ -9,6 +9,7 @@ List, Any, Optional, + Tuple, Union, TYPE_CHECKING, Generic, @@ -206,10 +207,10 @@ def default_error_deserialization(self) -> Optional[str]: @property def non_default_errors(self) -> List[Response]: - return [e for e in self.exceptions if "default" not in e.status_codes] + return [e for e in self.exceptions if "default" not in e.status_codes and e.type] @property - def non_default_error_status_codes(self) -> List[Union[str, int]]: + def non_default_error_status_codes(self) -> List[Union[str, int, Tuple[int, int]]]: """Actually returns all of the status codes from exceptions (besides default)""" return list(chain.from_iterable([error.status_codes for error in self.non_default_errors])) @@ -344,19 +345,7 @@ def imports( # pylint: disable=too-many-branches, disable=too-many-statements file_import.add_submodule_import("exceptions", error, ImportType.SDKCORE) if self.code_model.options["azure_arm"]: file_import.add_submodule_import("azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.SDKCORE) - if self.non_default_errors: - file_import.add_submodule_import( - "typing", - "Type", - ImportType.STDLIB, - ) file_import.add_mutable_mapping_import() - if self.non_default_error_status_codes: - file_import.add_submodule_import( - "typing", - "cast", - ImportType.STDLIB, - ) if self.has_kwargs_to_pop_with_default( self.parameters.kwargs_to_pop, ParameterLocation.HEADER # type: ignore @@ -436,7 +425,7 @@ def imports( # pylint: disable=too-many-branches, disable=too-many-statements elif any(r.type for r in self.responses): file_import.add_submodule_import(f"{relative_path}_model_base", "_deserialize", ImportType.LOCAL) if self.default_error_deserialization or self.non_default_errors: - file_import.add_submodule_import(f"{relative_path}_model_base", "_deserialize", ImportType.LOCAL) + file_import.add_submodule_import(f"{relative_path}_model_base", "_failsafe_deserialize", ImportType.LOCAL) return file_import def get_response_from_status(self, status_code: Optional[Union[str, int]]) -> ResponseType: diff --git a/packages/http-client-python/generator/pygen/codegen/models/response.py b/packages/http-client-python/generator/pygen/codegen/models/response.py index 19a7d62e944..b409f26ae05 100644 --- a/packages/http-client-python/generator/pygen/codegen/models/response.py +++ b/packages/http-client-python/generator/pygen/codegen/models/response.py @@ -3,7 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for # license information. # -------------------------------------------------------------------------- -from typing import Dict, Optional, List, Any, TYPE_CHECKING, Union +from typing import Dict, Optional, List, Any, TYPE_CHECKING, Union, Tuple from .base import BaseModel from .base import BaseType @@ -54,7 +54,7 @@ def __init__( type: Optional[BaseType] = None, ) -> None: super().__init__(yaml_data=yaml_data, code_model=code_model) - self.status_codes: List[Union[int, str]] = yaml_data["statusCodes"] + self.status_codes: List[Union[int, str, Tuple[int, int]]] = yaml_data["statusCodes"] self.headers = headers or [] self.type = type self.nullable = yaml_data.get("nullable") diff --git a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py index de7d6c20867..98d904cb548 100644 --- a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py +++ b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py @@ -61,14 +61,6 @@ def _all_same(data: List[List[str]]) -> bool: return len(data) > 1 and all(sorted(data[0]) == sorted(data[i]) for i in range(1, len(data))) -def _need_type_ignore(builder: OperationType) -> bool: - for e in builder.non_default_errors: - for status_code in e.status_codes: - if status_code in (401, 404, 409, 304): - return True - return False - - def _xml_config(send_xml: bool, content_types: List[str]) -> str: if not (send_xml and "xml" in str(content_types)): return "" @@ -999,17 +991,41 @@ def handle_error_response(self, builder: OperationType) -> List[str]: elif isinstance(builder.stream_value, str): # _stream is not sure, so we need to judge it retval.append(" if _stream:") retval.extend([f" {l}" for l in response_read]) - type_ignore = " # type: ignore" if _need_type_ignore(builder) else "" retval.append( - f" map_error(status_code=response.status_code, response=response, error_map=error_map){type_ignore}" + f" map_error(status_code=response.status_code, response=response, error_map=error_map)" ) error_model = "" + if builder.non_default_errors and self.code_model.options["models_mode"]: + error_model = ", model=error" + condition = "if" + retval.append(" error = None") + for e in builder.non_default_errors: + if isinstance(e.status_codes[0], int): + if len(e.status_codes) == 1: + retval.append(f" {condition} response.status_code == {e.status_codes[0]}:") + else: + retval.append(f" {condition} response.status_code in {str(e.status_codes)}:") + else: + # ranged status code only exist in typespec and will not have multiple status codes + retval.append(f" {condition} {e.status_codes[0][0]} <= response.status_code <= {e.status_codes[0][1]}:") + if self.code_model.options["models_mode"] == "dpg": + retval.append(f" error = _failsafe_deserialize({e.type.type_annotation(is_operation_file=True, skip_quote=True)}, response.json())") + else: + retval.append( + f" error = self._deserialize.failsafe_deserialize({e.type.type_annotation(is_operation_file=True, skip_quote=True)}, " + "pipeline_response)" + ) + condition = "elif" + if builder.default_error_deserialization and self.code_model.options["models_mode"]: + indent = " " if builder.non_default_errors else " " + if builder.non_default_errors: + retval.append(" else:") if self.code_model.options["models_mode"] == "dpg": - retval.append(f" error = _deserialize({builder.default_error_deserialization}, response.json())") + retval.append(f"{indent}error = _deserialize({builder.default_error_deserialization}, response.json())") else: retval.append( - f" error = self._deserialize.failsafe_deserialize({builder.default_error_deserialization}, " + f"{indent}error = self._deserialize.failsafe_deserialize({builder.default_error_deserialization}, " "pipeline_response)" ) error_model = ", model=error" @@ -1096,49 +1112,6 @@ def error_map(self, builder: OperationType) -> List[str]: retval.append(" 409: ResourceExistsError,") if not 304 in builder.non_default_error_status_codes: retval.append(" 304: ResourceNotModifiedError,") - for e in builder.non_default_errors: - error_model_str = "" - if isinstance(e.type, ModelType): - if self.code_model.options["models_mode"] == "msrest": - error_model_str = ( - f", model=self._deserialize(" f"_models.{e.type.serialization_type}, response)" - ) - elif self.code_model.options["models_mode"] == "dpg": - error_model_str = f", model=_deserialize(_models.{e.type.name}, response.json())" - error_format_str = ", error_format=ARMErrorFormat" if self.code_model.options["azure_arm"] else "" - for status_code in e.status_codes: - if status_code == 401: - retval.append( - " 401: cast(Type[HttpResponseError], " - "lambda response: ClientAuthenticationError(response=response" - f"{error_model_str}{error_format_str}))," - ) - elif status_code == 404: - retval.append( - " 404: cast(Type[HttpResponseError], " - "lambda response: ResourceNotFoundError(response=response" - f"{error_model_str}{error_format_str}))," - ) - elif status_code == 409: - retval.append( - " 409: cast(Type[HttpResponseError], " - "lambda response: ResourceExistsError(response=response" - f"{error_model_str}{error_format_str}))," - ) - elif status_code == 304: - retval.append( - " 304: cast(Type[HttpResponseError], " - "lambda response: ResourceNotModifiedError(response=response" - f"{error_model_str}{error_format_str}))," - ) - elif not error_model_str and not error_format_str: - retval.append(f" {status_code}: HttpResponseError,") - else: - retval.append( - f" {status_code}: cast(Type[HttpResponseError], " - "lambda response: HttpResponseError(response=response" - f"{error_model_str}{error_format_str}))," - ) else: retval.append( " 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, " diff --git a/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 b/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 index 2bea913ef3c..57f2cba9eeb 100644 --- a/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 +++ b/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 @@ -892,6 +892,23 @@ def _deserialize( return _deserialize_with_callable(deserializer, value) +def _failsafe_deserialize( + deserializer: typing.Any, + value: typing.Any, + module: typing.Optional[str] = None, + rf: typing.Optional["_RestField"] = None, + format: typing.Optional[str] = None, +) -> typing.Any: + try: + return _deserialize(deserializer, value, module, rf, format) + except: + _LOGGER.warning( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", + exc_info=True + ) + return None + + class _RestField: def __init__( self, diff --git a/packages/http-client-python/package-lock.json b/packages/http-client-python/package-lock.json index 500223ac086..99219312040 100644 --- a/packages/http-client-python/package-lock.json +++ b/packages/http-client-python/package-lock.json @@ -1,12 +1,12 @@ { "name": "@typespec/http-client-python", - "version": "0.3.9", + "version": "0.3.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@typespec/http-client-python", - "version": "0.3.9", + "version": "0.3.12", "hasInstallScript": true, "license": "MIT", "dependencies": { From 137bb89efbf28c90151c04849ce19ffa3b28a308 Mon Sep 17 00:00:00 2001 From: tadelesh Date: Thu, 5 Dec 2024 17:57:52 +0800 Subject: [PATCH 2/5] fix lint --- .../generator/pygen/codegen/templates/model_base.py.jinja2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 b/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 index 57f2cba9eeb..fd2cbdedc1e 100644 --- a/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 +++ b/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 @@ -901,7 +901,7 @@ def _failsafe_deserialize( ) -> typing.Any: try: return _deserialize(deserializer, value, module, rf, format) - except: + except DeserializationError: _LOGGER.warning( "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True From f2768c258c0af88bd212c03071672b5c4a52265c Mon Sep 17 00:00:00 2001 From: tadelesh Date: Fri, 6 Dec 2024 11:41:51 +0800 Subject: [PATCH 3/5] refine logic and fix union model deserialization issue --- .../pygen/codegen/models/model_type.py | 2 +- .../pygen/codegen/models/operation.py | 10 +-- .../pygen/codegen/models/response.py | 4 +- .../codegen/serializers/builder_serializer.py | 85 ++++++++++++++----- 4 files changed, 71 insertions(+), 30 deletions(-) diff --git a/packages/http-client-python/generator/pygen/codegen/models/model_type.py b/packages/http-client-python/generator/pygen/codegen/models/model_type.py index 80e21252b42..09422a44e35 100644 --- a/packages/http-client-python/generator/pygen/codegen/models/model_type.py +++ b/packages/http-client-python/generator/pygen/codegen/models/model_type.py @@ -348,7 +348,7 @@ def serialization_type(self) -> str: @property def instance_check_template(self) -> str: - return "isinstance({}, _model_base.Model)" + return "isinstance({}, " + f"_models.{self.name})" def imports(self, **kwargs: Any) -> FileImport: file_import = super().imports(**kwargs) diff --git a/packages/http-client-python/generator/pygen/codegen/models/operation.py b/packages/http-client-python/generator/pygen/codegen/models/operation.py index fa10d5bc1fb..0ce0c62aeef 100644 --- a/packages/http-client-python/generator/pygen/codegen/models/operation.py +++ b/packages/http-client-python/generator/pygen/codegen/models/operation.py @@ -202,17 +202,11 @@ def default_error_deserialization(self) -> Optional[str]: exception_schema = default_exceptions[0].type if isinstance(exception_schema, ModelType): return exception_schema.type_annotation(skip_quote=True) - # in this case, it's just an AnyType - return "'object'" + return None @property def non_default_errors(self) -> List[Response]: - return [e for e in self.exceptions if "default" not in e.status_codes and e.type] - - @property - def non_default_error_status_codes(self) -> List[Union[str, int, Tuple[int, int]]]: - """Actually returns all of the status codes from exceptions (besides default)""" - return list(chain.from_iterable([error.status_codes for error in self.non_default_errors])) + return [e for e in self.exceptions if "default" not in e.status_codes and e.type and isinstance(e.type, ModelType)] def _imports_shared(self, async_mode: bool, **kwargs: Any) -> FileImport: # pylint: disable=unused-argument file_import = FileImport(self.code_model) diff --git a/packages/http-client-python/generator/pygen/codegen/models/response.py b/packages/http-client-python/generator/pygen/codegen/models/response.py index b409f26ae05..c36a98a371f 100644 --- a/packages/http-client-python/generator/pygen/codegen/models/response.py +++ b/packages/http-client-python/generator/pygen/codegen/models/response.py @@ -3,7 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for # license information. # -------------------------------------------------------------------------- -from typing import Dict, Optional, List, Any, TYPE_CHECKING, Union, Tuple +from typing import Dict, Optional, List, Any, TYPE_CHECKING, Union from .base import BaseModel from .base import BaseType @@ -54,7 +54,7 @@ def __init__( type: Optional[BaseType] = None, ) -> None: super().__init__(yaml_data=yaml_data, code_model=code_model) - self.status_codes: List[Union[int, str, Tuple[int, int]]] = yaml_data["statusCodes"] + self.status_codes: List[Union[int, str, List[int]]] = yaml_data["statusCodes"] self.headers = headers or [] self.type = type self.nullable = yaml_data.get("nullable") diff --git a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py index 98d904cb548..f6962a59412 100644 --- a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py +++ b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py @@ -1000,35 +1000,71 @@ def handle_error_response(self, builder: OperationType) -> List[str]: condition = "if" retval.append(" error = None") for e in builder.non_default_errors: + # single status code if isinstance(e.status_codes[0], int): - if len(e.status_codes) == 1: - retval.append(f" {condition} response.status_code == {e.status_codes[0]}:") - else: - retval.append(f" {condition} response.status_code in {str(e.status_codes)}:") + for status_code in e.status_codes: + retval.append(f" {condition} response.status_code == {status_code}:") + if self.code_model.options["models_mode"] == "dpg": + retval.append(f" error = _failsafe_deserialize({e.type.type_annotation(is_operation_file=True, skip_quote=True)}, response.json())") + else: + retval.append( + f" error = self._deserialize.failsafe_deserialize({e.type.type_annotation(is_operation_file=True, skip_quote=True)}, " + "pipeline_response)" + ) + # add build-in error type + # TODO: we should decide whether need to this wrapper for customized error type + if status_code == 401: + retval.append( + " raise ClientAuthenticationError(response=response{}{})".format( + error_model, + (", error_format=ARMErrorFormat" if self.code_model.options["azure_arm"] else ""), + ) + ) + elif status_code == 404: + retval.append( + " raise ResourceNotFoundError(response=response{}{})".format( + error_model, + (", error_format=ARMErrorFormat" if self.code_model.options["azure_arm"] else ""), + ) + ) + elif status_code == 409: + retval.append( + " raise ResourceExistsError(response=response{}{})".format( + error_model, + (", error_format=ARMErrorFormat" if self.code_model.options["azure_arm"] else ""), + ) + ) + elif status_code == 304: + retval.append( + " raise ResourceNotModifiedError(response=response{}{})".format( + error_model, + (", error_format=ARMErrorFormat" if self.code_model.options["azure_arm"] else ""), + ) + ) + # ranged status code only exist in typespec and will not have multiple status codes else: - # ranged status code only exist in typespec and will not have multiple status codes retval.append(f" {condition} {e.status_codes[0][0]} <= response.status_code <= {e.status_codes[0][1]}:") - if self.code_model.options["models_mode"] == "dpg": - retval.append(f" error = _failsafe_deserialize({e.type.type_annotation(is_operation_file=True, skip_quote=True)}, response.json())") - else: - retval.append( - f" error = self._deserialize.failsafe_deserialize({e.type.type_annotation(is_operation_file=True, skip_quote=True)}, " - "pipeline_response)" - ) + if self.code_model.options["models_mode"] == "dpg": + retval.append(f" error = _failsafe_deserialize({e.type.type_annotation(is_operation_file=True, skip_quote=True)}, response.json())") + else: + retval.append( + f" error = self._deserialize.failsafe_deserialize({e.type.type_annotation(is_operation_file=True, skip_quote=True)}, " + "pipeline_response)" + ) condition = "elif" - + # default error handling if builder.default_error_deserialization and self.code_model.options["models_mode"]: + error_model = ", model=error" indent = " " if builder.non_default_errors else " " if builder.non_default_errors: retval.append(" else:") if self.code_model.options["models_mode"] == "dpg": - retval.append(f"{indent}error = _deserialize({builder.default_error_deserialization}, response.json())") + retval.append(f"{indent}error = _failsafe_deserialize({builder.default_error_deserialization}, response.json())") else: retval.append( f"{indent}error = self._deserialize.failsafe_deserialize({builder.default_error_deserialization}, " "pipeline_response)" ) - error_model = ", model=error" retval.append( " raise HttpResponseError(response=response{}{})".format( error_model, @@ -1101,16 +1137,27 @@ def handle_response(self, builder: OperationType) -> List[str]: retval.append("return 200 <= response.status_code <= 299") return retval + def _need_specific_error_map(self, code: int, builder: OperationType) -> bool: + for non_default_error in builder.non_default_errors: + # single status code + if code in non_default_error.status_codes: + return False + # ranged status code + if isinstance(non_default_error.status_codes[0], list) and non_default_error.status_codes[0][0] <= code <= non_default_error.status_codes[0][1]: + return False + return True + def error_map(self, builder: OperationType) -> List[str]: retval = ["error_map: MutableMapping = {"] if builder.non_default_errors: - if not 401 in builder.non_default_error_status_codes: + # TODO: we should decide whether to add the build-in error map when there is a customized default error type + if self._need_specific_error_map(401, builder): retval.append(" 401: ClientAuthenticationError,") - if not 404 in builder.non_default_error_status_codes: + elif self._need_specific_error_map(404, builder): retval.append(" 404: ResourceNotFoundError,") - if not 409 in builder.non_default_error_status_codes: + elif self._need_specific_error_map(409, builder): retval.append(" 409: ResourceExistsError,") - if not 304 in builder.non_default_error_status_codes: + elif self._need_specific_error_map(304, builder): retval.append(" 304: ResourceNotModifiedError,") else: retval.append( From 2da7d78526572d6d4f5e512c5f9d304d8cc78ca2 Mon Sep 17 00:00:00 2001 From: tadelesh Date: Fri, 6 Dec 2024 14:21:44 +0800 Subject: [PATCH 4/5] fix condition --- .../pygen/codegen/serializers/builder_serializer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py index f6962a59412..a318c094cfb 100644 --- a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py +++ b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py @@ -1153,11 +1153,11 @@ def error_map(self, builder: OperationType) -> List[str]: # TODO: we should decide whether to add the build-in error map when there is a customized default error type if self._need_specific_error_map(401, builder): retval.append(" 401: ClientAuthenticationError,") - elif self._need_specific_error_map(404, builder): + if self._need_specific_error_map(404, builder): retval.append(" 404: ResourceNotFoundError,") - elif self._need_specific_error_map(409, builder): + if self._need_specific_error_map(409, builder): retval.append(" 409: ResourceExistsError,") - elif self._need_specific_error_map(304, builder): + if self._need_specific_error_map(304, builder): retval.append(" 304: ResourceNotModifiedError,") else: retval.append( From ed21a88aa6dfd435d0c09b2e6158fee6e4488766 Mon Sep 17 00:00:00 2001 From: tadelesh Date: Fri, 6 Dec 2024 15:26:47 +0800 Subject: [PATCH 5/5] fix version tolerant code issue --- .../codegen/serializers/builder_serializer.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py index a318c094cfb..34924397e1d 100644 --- a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py +++ b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py @@ -1138,18 +1138,18 @@ def handle_response(self, builder: OperationType) -> List[str]: return retval def _need_specific_error_map(self, code: int, builder: OperationType) -> bool: - for non_default_error in builder.non_default_errors: - # single status code - if code in non_default_error.status_codes: - return False - # ranged status code - if isinstance(non_default_error.status_codes[0], list) and non_default_error.status_codes[0][0] <= code <= non_default_error.status_codes[0][1]: - return False - return True + for non_default_error in builder.non_default_errors: + # single status code + if code in non_default_error.status_codes: + return False + # ranged status code + if isinstance(non_default_error.status_codes[0], list) and non_default_error.status_codes[0][0] <= code <= non_default_error.status_codes[0][1]: + return False + return True def error_map(self, builder: OperationType) -> List[str]: retval = ["error_map: MutableMapping = {"] - if builder.non_default_errors: + if builder.non_default_errors and self.code_model.options["models_mode"]: # TODO: we should decide whether to add the build-in error map when there is a customized default error type if self._need_specific_error_map(401, builder): retval.append(" 401: ClientAuthenticationError,")